Skip to content

Commit 924f480

Browse files
Sugar Zhangrkhuangtao
authored andcommitted
drm: bridge/dw-hdmi: add support for hdmi bitstream audio
Change-Id: Ib1f6c5dba6451f3fbb029b5472dbfbf5694cff68 Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
1 parent 3fc90c1 commit 924f480

4 files changed

Lines changed: 140 additions & 8 deletions

File tree

drivers/gpu/drm/bridge/dw-hdmi-audio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct dw_hdmi_i2s_audio_data {
1616

1717
void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
1818
u8 (*read)(struct dw_hdmi *hdmi, int offset);
19+
void (*mod)(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned int reg);
1920
};
2021

2122
#endif

drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset)
3030
return audio->read(hdmi, offset);
3131
}
3232

33+
static inline void hdmi_update_bits(struct dw_hdmi_i2s_audio_data *audio,
34+
u8 data, u8 mask, unsigned int reg)
35+
{
36+
struct dw_hdmi *hdmi = audio->hdmi;
37+
38+
audio->mod(hdmi, data, mask, reg);
39+
}
40+
3341
static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
3442
struct hdmi_codec_daifmt *fmt,
3543
struct hdmi_codec_params *hparms)
@@ -39,6 +47,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
3947
u8 conf0 = 0;
4048
u8 conf1 = 0;
4149
u8 inputclkfs = 0;
50+
u8 val;
4251

4352
/* it cares I2S only */
4453
if ((fmt->fmt != HDMI_I2S) ||
@@ -47,7 +56,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
4756
return -EINVAL;
4857
}
4958

50-
inputclkfs = HDMI_AUD_INPUTCLKFS_64FS;
59+
inputclkfs = HDMI_AUD_INPUTCLKFS_128FS;
5160

5261
switch (hparms->sample_width) {
5362
case 16:
@@ -80,19 +89,112 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
8089
return -EINVAL;
8190
}
8291

83-
dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
84-
85-
hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
86-
hdmi_write(audio, conf0, HDMI_AUD_CONF0);
87-
hdmi_write(audio, conf1, HDMI_AUD_CONF1);
8892
/*
8993
* dw-hdmi introduced insert_pcuv bit in version 2.10a.
9094
* When set (1'b1), this bit enables the insertion of the PCUV
9195
* (Parity, Channel Status, User bit and Validity) bits on the
9296
* incoming audio stream (support limited to Linear PCM audio)
9397
*/
94-
if (hdmi_read(audio, HDMI_DESIGN_ID) > 0x21)
95-
hdmi_write(audio, HDMI_AUD_CONF2_INSERT_PCUV, HDMI_AUD_CONF2);
98+
val = 0;
99+
if (hdmi_read(audio, HDMI_DESIGN_ID) >= 0x21)
100+
val = HDMI_AUD_CONF2_INSERT_PCUV;
101+
102+
/*Mask fifo empty and full int and reset fifo*/
103+
hdmi_update_bits(audio,
104+
HDMI_AUD_INT_FIFO_EMPTY_MSK |
105+
HDMI_AUD_INT_FIFO_FULL_MSK,
106+
HDMI_AUD_INT_FIFO_EMPTY_MSK |
107+
HDMI_AUD_INT_FIFO_FULL_MSK, HDMI_AUD_INT);
108+
hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
109+
HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
110+
hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK,
111+
HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ);
112+
113+
switch (hparms->mode) {
114+
case NLPCM:
115+
hdmi_write(audio, HDMI_AUD_CONF2_NLPCM, HDMI_AUD_CONF2);
116+
conf1 = HDMI_AUD_CONF1_WIDTH_21;
117+
break;
118+
case HBR:
119+
hdmi_write(audio, HDMI_AUD_CONF2_HBR, HDMI_AUD_CONF2);
120+
conf1 = HDMI_AUD_CONF1_WIDTH_21;
121+
break;
122+
default:
123+
hdmi_write(audio, val, HDMI_AUD_CONF2);
124+
break;
125+
}
126+
127+
dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
128+
129+
hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
130+
hdmi_write(audio, conf0, HDMI_AUD_CONF0);
131+
hdmi_write(audio, conf1, HDMI_AUD_CONF1);
132+
133+
val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0;
134+
if (hparms->channels > 2)
135+
val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1;
136+
hdmi_update_bits(audio, val, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK,
137+
HDMI_FC_AUDSCONF);
138+
139+
switch (hparms->sample_rate) {
140+
case 32000:
141+
val = HDMI_FC_AUDSCHNLS_32K;
142+
break;
143+
case 44100:
144+
val = HDMI_FC_AUDSCHNLS_441K;
145+
break;
146+
case 48000:
147+
val = HDMI_FC_AUDSCHNLS_48K;
148+
break;
149+
case 88200:
150+
val = HDMI_FC_AUDSCHNLS_882K;
151+
break;
152+
case 96000:
153+
val = HDMI_FC_AUDSCHNLS_96K;
154+
break;
155+
case 176400:
156+
val = HDMI_FC_AUDSCHNLS_1764K;
157+
break;
158+
case 192000:
159+
val = HDMI_FC_AUDSCHNLS_192K;
160+
break;
161+
default:
162+
val = HDMI_FC_AUDSCHNLS_441K;
163+
break;
164+
}
165+
166+
/* set channel status register */
167+
hdmi_update_bits(audio, val,
168+
HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK,
169+
HDMI_FC_AUDSCHNLS7);
170+
hdmi_write(audio,
171+
((~val) << HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET),
172+
HDMI_FC_AUDSCHNLS8);
173+
174+
/* Refer to CEA861-E Audio infoFrame
175+
* Set both Audio Channel Count and Audio Coding
176+
* Type Refer to Stream Head for HDMI
177+
*/
178+
hdmi_update_bits(audio,
179+
(hparms->channels - 1) << HDMI_FC_AUDICONF0_CC_OFFSET,
180+
HDMI_FC_AUDICONF0_CC_MASK, HDMI_FC_AUDICONF0);
181+
182+
/* Set both Audio Sample Size and Sample Frequency
183+
* Refer to Stream Head for HDMI
184+
*/
185+
hdmi_write(audio, 0x00, HDMI_FC_AUDICONF1);
186+
187+
/* Set Channel Allocation */
188+
hdmi_write(audio, 0x00, HDMI_FC_AUDICONF2);
189+
190+
/* Set LFEPBLDOWN-MIX INH and LSV */
191+
hdmi_write(audio, 0x00, HDMI_FC_AUDICONF3);
192+
193+
hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
194+
HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
195+
hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK,
196+
HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ);
197+
96198
dw_hdmi_audio_enable(hdmi);
97199

98200
return 0;

drivers/gpu/drm/bridge/dw-hdmi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2614,6 +2614,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
26142614
audio.hdmi = hdmi;
26152615
audio.write = hdmi_writeb;
26162616
audio.read = hdmi_readb;
2617+
audio.mod = hdmi_modb;
26172618

26182619
pdevinfo.name = "dw-hdmi-i2s-audio";
26192620
pdevinfo.data = &audio;

drivers/gpu/drm/bridge/dw-hdmi.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@
162162
#define HDMI_FC_SPDDEVICEINF 0x1062
163163
#define HDMI_FC_AUDSCONF 0x1063
164164
#define HDMI_FC_AUDSSTAT 0x1064
165+
#define HDMI_FC_AUDSCHNLS0 0x1067
166+
#define HDMI_FC_AUDSCHNLS1 0x1068
167+
#define HDMI_FC_AUDSCHNLS2 0x1069
168+
#define HDMI_FC_AUDSCHNLS3 0x106a
169+
#define HDMI_FC_AUDSCHNLS4 0x106b
170+
#define HDMI_FC_AUDSCHNLS5 0x106c
171+
#define HDMI_FC_AUDSCHNLS6 0x106d
172+
#define HDMI_FC_AUDSCHNLS7 0x106e
173+
#define HDMI_FC_AUDSCHNLS8 0x106f
165174
#define HDMI_FC_DATACH0FILL 0x1070
166175
#define HDMI_FC_DATACH1FILL 0x1071
167176
#define HDMI_FC_DATACH2FILL 0x1072
@@ -744,13 +753,24 @@ enum {
744753
/* HDMI_FC_AUDSCHNLS7 field values */
745754
HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
746755
HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
756+
HDMI_FC_AUDSCHNLS7_SAMPFREQ_OFFSET = 0,
757+
HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK = 0x0f,
747758

748759
/* HDMI_FC_AUDSCHNLS8 field values */
749760
HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
750761
HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
751762
HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
752763
HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
753764

765+
/* HDMI_FC_AUDSCHNLS Sample Rate */
766+
HDMI_FC_AUDSCHNLS_32K = 0x3,
767+
HDMI_FC_AUDSCHNLS_441K = 0x0,
768+
HDMI_FC_AUDSCHNLS_48K = 0x2,
769+
HDMI_FC_AUDSCHNLS_882K = 0x8,
770+
HDMI_FC_AUDSCHNLS_96K = 0xa,
771+
HDMI_FC_AUDSCHNLS_1764K = 0xc,
772+
HDMI_FC_AUDSCHNLS_192K = 0xe,
773+
754774
/* FC_AUDSCONF field values */
755775
HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
756776
HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
@@ -909,11 +929,16 @@ enum {
909929
HDMI_AUD_CONF0_I2S_8CHANNEL_ENABLE = 0x2F,
910930
HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F,
911931

932+
/* AUD_INT field values */
933+
HDMI_AUD_INT_FIFO_EMPTY_MSK = BIT(3),
934+
HDMI_AUD_INT_FIFO_FULL_MSK = BIT(2),
935+
912936
/* AUD_CONF1 field values */
913937
HDMI_AUD_CONF1_MODE_I2S = 0x00,
914938
HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02,
915939
HDMI_AUD_CONF1_MODE_LEFT_J = 0x04,
916940
HDMI_AUD_CONF1_WIDTH_16 = 0x10,
941+
HDMI_AUD_CONF1_WIDTH_21 = 0x15,
917942
HDMI_AUD_CONF1_WIDTH_24 = 0x18,
918943

919944
/* AUD_CONF2 filed values */
@@ -1092,6 +1117,9 @@ enum {
10921117
HDMI_I2CM_DIV_FAST_STD_MODE = 0x8,
10931118
HDMI_I2CM_DIV_FAST_MODE = 0x8,
10941119
HDMI_I2CM_DIV_STD_MODE = 0,
1120+
1121+
/* HDMI_MC_SWRSTZ filed values */
1122+
HDMI_MC_SWRSTZ_I2S_RESET_MSK = BIT(3),
10951123
};
10961124

10971125
#endif /* __DW_HDMI_H__ */

0 commit comments

Comments
 (0)