hc
2024-05-10 61598093bbdd283a7edc367d900f223070ead8d2
kernel/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
....@@ -1,14 +1,16 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
23 * dw-hdmi-i2s-audio.c
34 *
45 * Copyright (c) 2017 Renesas Solutions Corp.
56 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License version 2 as
9
- * published by the Free Software Foundation.
107 */
8
+
9
+#include <linux/dma-mapping.h>
10
+#include <linux/module.h>
11
+
1112 #include <drm/bridge/dw_hdmi.h>
13
+#include <drm/drm_crtc.h>
1214
1315 #include <sound/hdmi-codec.h>
1416
....@@ -48,17 +50,35 @@
4850 struct dw_hdmi *hdmi = audio->hdmi;
4951 u8 conf0 = 0;
5052 u8 conf1 = 0;
53
+ u8 conf2 = 0;
5154 u8 inputclkfs = 0;
52
- u8 val;
5355
5456 /* it cares I2S only */
55
- if ((fmt->fmt != HDMI_I2S) ||
56
- (fmt->bit_clk_master | fmt->frame_clk_master)) {
57
- dev_err(dev, "unsupported format/settings\n");
57
+ if (fmt->bit_clk_master | fmt->frame_clk_master) {
58
+ dev_err(dev, "unsupported clock settings\n");
5859 return -EINVAL;
5960 }
6061
61
- inputclkfs = HDMI_AUD_INPUTCLKFS_128FS;
62
+ /* Reset the FIFOs before applying new params */
63
+ hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
64
+ HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
65
+ hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ);
66
+
67
+ inputclkfs = HDMI_AUD_INPUTCLKFS_64FS;
68
+ conf0 = (HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_EN0);
69
+
70
+ /* Enable the required i2s lanes */
71
+ switch (hparms->channels) {
72
+ case 7 ... 8:
73
+ conf0 |= HDMI_AUD_CONF0_I2S_EN3;
74
+ fallthrough;
75
+ case 5 ... 6:
76
+ conf0 |= HDMI_AUD_CONF0_I2S_EN2;
77
+ fallthrough;
78
+ case 3 ... 4:
79
+ conf0 |= HDMI_AUD_CONF0_I2S_EN1;
80
+ /* Fall-thru */
81
+ }
6282
6383 switch (hparms->sample_width) {
6484 case 16:
....@@ -68,136 +88,72 @@
6888 case 32:
6989 conf1 = HDMI_AUD_CONF1_WIDTH_24;
7090 break;
91
+ }
92
+
93
+ switch (fmt->fmt) {
94
+ case HDMI_I2S:
95
+ conf1 |= HDMI_AUD_CONF1_MODE_I2S;
96
+ break;
97
+ case HDMI_RIGHT_J:
98
+ conf1 |= HDMI_AUD_CONF1_MODE_RIGHT_J;
99
+ break;
100
+ case HDMI_LEFT_J:
101
+ conf1 |= HDMI_AUD_CONF1_MODE_LEFT_J;
102
+ break;
103
+ case HDMI_DSP_A:
104
+ conf1 |= HDMI_AUD_CONF1_MODE_BURST_1;
105
+ break;
106
+ case HDMI_DSP_B:
107
+ conf1 |= HDMI_AUD_CONF1_MODE_BURST_2;
108
+ break;
71109 default:
72
- dev_err(dev, "unsupported sample width [%d]\n", hparms->sample_width);
110
+ dev_err(dev, "unsupported format\n");
73111 return -EINVAL;
74112 }
75113
76
- switch (hparms->channels) {
77
- case 2:
78
- conf0 = HDMI_AUD_CONF0_I2S_2CHANNEL_ENABLE;
79
- break;
80
- case 4:
81
- conf0 = HDMI_AUD_CONF0_I2S_4CHANNEL_ENABLE;
82
- break;
83
- case 6:
84
- conf0 = HDMI_AUD_CONF0_I2S_6CHANNEL_ENABLE;
85
- break;
86
- case 8:
87
- conf0 = HDMI_AUD_CONF0_I2S_8CHANNEL_ENABLE;
114
+ switch (fmt->bit_fmt) {
115
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
116
+ conf1 = HDMI_AUD_CONF1_WIDTH_21;
117
+ conf2 = (hparms->channels == 8) ? HDMI_AUD_CONF2_HBR : HDMI_AUD_CONF2_NLPCM;
88118 break;
89119 default:
90
- dev_err(dev, "unsupported channels [%d]\n", hparms->channels);
91
- return -EINVAL;
92
- }
93
-
94
- /*
95
- * dw-hdmi introduced insert_pcuv bit in version 2.10a.
96
- * When set (1'b1), this bit enables the insertion of the PCUV
97
- * (Parity, Channel Status, User bit and Validity) bits on the
98
- * incoming audio stream (support limited to Linear PCM audio)
99
- */
100
- val = 0;
101
- if (hdmi_read(audio, HDMI_DESIGN_ID) >= 0x21)
102
- val = HDMI_AUD_CONF2_INSERT_PCUV;
103
-
104
- /*Mask fifo empty and full int and reset fifo*/
105
- hdmi_update_bits(audio,
106
- HDMI_AUD_INT_FIFO_EMPTY_MSK |
107
- HDMI_AUD_INT_FIFO_FULL_MSK,
108
- HDMI_AUD_INT_FIFO_EMPTY_MSK |
109
- HDMI_AUD_INT_FIFO_FULL_MSK, HDMI_AUD_INT);
110
- hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
111
- HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
112
- hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK,
113
- HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ);
114
-
115
- switch (hparms->mode) {
116
- case NLPCM:
117
- hdmi_write(audio, HDMI_AUD_CONF2_NLPCM, HDMI_AUD_CONF2);
118
- conf1 = HDMI_AUD_CONF1_WIDTH_21;
119
- break;
120
- case HBR:
121
- hdmi_write(audio, HDMI_AUD_CONF2_HBR, HDMI_AUD_CONF2);
122
- conf1 = HDMI_AUD_CONF1_WIDTH_21;
123
- break;
124
- default:
125
- hdmi_write(audio, val, HDMI_AUD_CONF2);
120
+ /*
121
+ * dw-hdmi introduced insert_pcuv bit in version 2.10a.
122
+ * When set (1'b1), this bit enables the insertion of the PCUV
123
+ * (Parity, Channel Status, User bit and Validity) bits on the
124
+ * incoming audio stream (support limited to Linear PCM audio)
125
+ */
126
+ if (hdmi_read(audio, HDMI_DESIGN_ID) >= 0x21)
127
+ conf2 = HDMI_AUD_CONF2_INSERT_PCUV;
126128 break;
127129 }
128130
129131 dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
132
+ dw_hdmi_set_channel_status(hdmi, hparms->iec.status);
133
+ dw_hdmi_set_channel_count(hdmi, hparms->channels);
134
+ dw_hdmi_set_channel_allocation(hdmi, hparms->cea.channel_allocation);
130135
131136 hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
132137 hdmi_write(audio, conf0, HDMI_AUD_CONF0);
133138 hdmi_write(audio, conf1, HDMI_AUD_CONF1);
139
+ hdmi_write(audio, conf2, HDMI_AUD_CONF2);
134140
135
- val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0;
136
- if (hparms->channels > 2)
137
- val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1;
138
- hdmi_update_bits(audio, val, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK,
139
- HDMI_FC_AUDSCONF);
141
+ return 0;
142
+}
140143
141
- switch (hparms->sample_rate) {
142
- case 32000:
143
- val = HDMI_FC_AUDSCHNLS_32K;
144
- break;
145
- case 44100:
146
- val = HDMI_FC_AUDSCHNLS_441K;
147
- break;
148
- case 48000:
149
- val = HDMI_FC_AUDSCHNLS_48K;
150
- break;
151
- case 88200:
152
- val = HDMI_FC_AUDSCHNLS_882K;
153
- break;
154
- case 96000:
155
- val = HDMI_FC_AUDSCHNLS_96K;
156
- break;
157
- case 176400:
158
- val = HDMI_FC_AUDSCHNLS_1764K;
159
- break;
160
- case 192000:
161
- val = HDMI_FC_AUDSCHNLS_192K;
162
- break;
163
- default:
164
- val = HDMI_FC_AUDSCHNLS_441K;
165
- break;
166
- }
144
+static int dw_hdmi_i2s_prepare(struct device *dev, void *data,
145
+ struct hdmi_codec_daifmt *fmt,
146
+ struct hdmi_codec_params *hparms)
147
+{
148
+ return dw_hdmi_i2s_hw_params(dev, data, fmt, hparms);
149
+}
167150
168
- /* set channel status register */
169
- hdmi_update_bits(audio, val,
170
- HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK,
171
- HDMI_FC_AUDSCHNLS7);
172
- hdmi_write(audio,
173
- (((u8)~val) << HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET),
174
- HDMI_FC_AUDSCHNLS8);
175
-
176
- /* Refer to CEA861-E Audio infoFrame
177
- * Set both Audio Channel Count and Audio Coding
178
- * Type Refer to Stream Head for HDMI
179
- */
180
- hdmi_update_bits(audio,
181
- (hparms->channels - 1) << HDMI_FC_AUDICONF0_CC_OFFSET,
182
- HDMI_FC_AUDICONF0_CC_MASK, HDMI_FC_AUDICONF0);
183
-
184
- /* Set both Audio Sample Size and Sample Frequency
185
- * Refer to Stream Head for HDMI
186
- */
187
- hdmi_write(audio, 0x00, HDMI_FC_AUDICONF1);
188
-
189
- /* Set Channel Allocation */
190
- hdmi_write(audio, 0x00, HDMI_FC_AUDICONF2);
191
-
192
- /* Set LFEPBLDOWN-MIX INH and LSV */
193
- hdmi_write(audio, 0x00, HDMI_FC_AUDICONF3);
151
+static int dw_hdmi_i2s_audio_startup(struct device *dev, void *data)
152
+{
153
+ struct dw_hdmi_i2s_audio_data *audio = data;
154
+ struct dw_hdmi *hdmi = audio->hdmi;
194155
195156 dw_hdmi_audio_enable(hdmi);
196
-
197
- hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
198
- HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
199
- hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK,
200
- HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ);
201157
202158 return 0;
203159 }
....@@ -208,13 +164,22 @@
208164 struct dw_hdmi *hdmi = audio->hdmi;
209165
210166 dw_hdmi_audio_disable(hdmi);
167
+}
211168
212
- hdmi_update_bits(audio,
213
- HDMI_AUD_CONF0_SW_RESET,
214
- HDMI_AUD_CONF0_SW_RESET |
215
- (HDMI_AUD_CONF0_I2S_ALL_ENABLE ^
216
- HDMI_AUD_CONF0_I2S_SELECT_MASK),
217
- HDMI_AUD_CONF0);
169
+static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, uint8_t *buf,
170
+ size_t len)
171
+{
172
+ struct dw_hdmi_i2s_audio_data *audio = data;
173
+ u8 *eld;
174
+
175
+ eld = audio->get_eld(audio->hdmi);
176
+ if (eld)
177
+ memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
178
+ else
179
+ /* Pass en empty ELD if connector not available */
180
+ memset(buf, 0, len);
181
+
182
+ return 0;
218183 }
219184
220185 static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
....@@ -249,7 +214,10 @@
249214
250215 static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
251216 .hw_params = dw_hdmi_i2s_hw_params,
217
+ .prepare = dw_hdmi_i2s_prepare,
218
+ .audio_startup = dw_hdmi_i2s_audio_startup,
252219 .audio_shutdown = dw_hdmi_i2s_audio_shutdown,
220
+ .get_eld = dw_hdmi_i2s_get_eld,
253221 .get_dai_id = dw_hdmi_i2s_get_dai_id,
254222 .hook_plugged_cb = dw_hdmi_i2s_hook_plugged_cb,
255223 };