hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
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
....@@ -32,14 +34,6 @@
3234 return audio->read(hdmi, offset);
3335 }
3436
35
-static inline void hdmi_update_bits(struct dw_hdmi_i2s_audio_data *audio,
36
- u8 data, u8 mask, unsigned int reg)
37
-{
38
- struct dw_hdmi *hdmi = audio->hdmi;
39
-
40
- audio->mod(hdmi, data, mask, reg);
41
-}
42
-
4337 static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
4438 struct hdmi_codec_daifmt *fmt,
4539 struct hdmi_codec_params *hparms)
....@@ -48,17 +42,34 @@
4842 struct dw_hdmi *hdmi = audio->hdmi;
4943 u8 conf0 = 0;
5044 u8 conf1 = 0;
45
+ u8 conf2 = 0;
5146 u8 inputclkfs = 0;
52
- u8 val;
5347
5448 /* 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");
49
+ if (fmt->bit_clk_master | fmt->frame_clk_master) {
50
+ dev_err(dev, "unsupported clock settings\n");
5851 return -EINVAL;
5952 }
6053
61
- inputclkfs = HDMI_AUD_INPUTCLKFS_128FS;
54
+ /* Reset the FIFOs before applying new params */
55
+ hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
56
+ hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ);
57
+
58
+ inputclkfs = HDMI_AUD_INPUTCLKFS_64FS;
59
+ conf0 = (HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_EN0);
60
+
61
+ /* Enable the required i2s lanes */
62
+ switch (hparms->channels) {
63
+ case 7 ... 8:
64
+ conf0 |= HDMI_AUD_CONF0_I2S_EN3;
65
+ fallthrough;
66
+ case 5 ... 6:
67
+ conf0 |= HDMI_AUD_CONF0_I2S_EN2;
68
+ fallthrough;
69
+ case 3 ... 4:
70
+ conf0 |= HDMI_AUD_CONF0_I2S_EN1;
71
+ /* Fall-thru */
72
+ }
6273
6374 switch (hparms->sample_width) {
6475 case 16:
....@@ -68,136 +79,65 @@
6879 case 32:
6980 conf1 = HDMI_AUD_CONF1_WIDTH_24;
7081 break;
82
+ }
83
+
84
+ switch (fmt->fmt) {
85
+ case HDMI_I2S:
86
+ conf1 |= HDMI_AUD_CONF1_MODE_I2S;
87
+ break;
88
+ case HDMI_RIGHT_J:
89
+ conf1 |= HDMI_AUD_CONF1_MODE_RIGHT_J;
90
+ break;
91
+ case HDMI_LEFT_J:
92
+ conf1 |= HDMI_AUD_CONF1_MODE_LEFT_J;
93
+ break;
94
+ case HDMI_DSP_A:
95
+ conf1 |= HDMI_AUD_CONF1_MODE_BURST_1;
96
+ break;
97
+ case HDMI_DSP_B:
98
+ conf1 |= HDMI_AUD_CONF1_MODE_BURST_2;
99
+ break;
71100 default:
72
- dev_err(dev, "unsupported sample width [%d]\n", hparms->sample_width);
101
+ dev_err(dev, "unsupported format\n");
73102 return -EINVAL;
74103 }
75104
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;
105
+ switch (fmt->bit_fmt) {
106
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
107
+ conf1 = HDMI_AUD_CONF1_WIDTH_21;
108
+ conf2 = (hparms->channels == 8) ? HDMI_AUD_CONF2_HBR : HDMI_AUD_CONF2_NLPCM;
88109 break;
89110 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);
111
+ /*
112
+ * dw-hdmi introduced insert_pcuv bit in version 2.10a.
113
+ * When set (1'b1), this bit enables the insertion of the PCUV
114
+ * (Parity, Channel Status, User bit and Validity) bits on the
115
+ * incoming audio stream (support limited to Linear PCM audio)
116
+ */
117
+ if (hdmi_read(audio, HDMI_DESIGN_ID) >= 0x21)
118
+ conf2 = HDMI_AUD_CONF2_INSERT_PCUV;
126119 break;
127120 }
128121
129122 dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
123
+ dw_hdmi_set_channel_status(hdmi, hparms->iec.status);
124
+ dw_hdmi_set_channel_count(hdmi, hparms->channels);
125
+ dw_hdmi_set_channel_allocation(hdmi, hparms->cea.channel_allocation);
130126
131127 hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
132128 hdmi_write(audio, conf0, HDMI_AUD_CONF0);
133129 hdmi_write(audio, conf1, HDMI_AUD_CONF1);
130
+ hdmi_write(audio, conf2, HDMI_AUD_CONF2);
134131
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);
132
+ return 0;
133
+}
140134
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
- }
167
-
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);
135
+static int dw_hdmi_i2s_audio_startup(struct device *dev, void *data)
136
+{
137
+ struct dw_hdmi_i2s_audio_data *audio = data;
138
+ struct dw_hdmi *hdmi = audio->hdmi;
194139
195140 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);
201141
202142 return 0;
203143 }
....@@ -208,13 +148,22 @@
208148 struct dw_hdmi *hdmi = audio->hdmi;
209149
210150 dw_hdmi_audio_disable(hdmi);
151
+}
211152
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);
153
+static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, uint8_t *buf,
154
+ size_t len)
155
+{
156
+ struct dw_hdmi_i2s_audio_data *audio = data;
157
+ u8 *eld;
158
+
159
+ eld = audio->get_eld(audio->hdmi);
160
+ if (eld)
161
+ memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
162
+ else
163
+ /* Pass en empty ELD if connector not available */
164
+ memset(buf, 0, len);
165
+
166
+ return 0;
218167 }
219168
220169 static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
....@@ -249,7 +198,9 @@
249198
250199 static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
251200 .hw_params = dw_hdmi_i2s_hw_params,
201
+ .audio_startup = dw_hdmi_i2s_audio_startup,
252202 .audio_shutdown = dw_hdmi_i2s_audio_shutdown,
203
+ .get_eld = dw_hdmi_i2s_get_eld,
253204 .get_dai_id = dw_hdmi_i2s_get_dai_id,
254205 .hook_plugged_cb = dw_hdmi_i2s_hook_plugged_cb,
255206 };