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,19 +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;
53
-
54
- dw_hdmi_audio_disable(hdmi);
5555
5656 /* it cares I2S only */
57
- if ((fmt->fmt != HDMI_I2S) ||
58
- (fmt->bit_clk_master | fmt->frame_clk_master)) {
59
- 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");
6059 return -EINVAL;
6160 }
6261
63
- 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
+ }
6482
6583 switch (hparms->sample_width) {
6684 case 16:
....@@ -70,136 +88,96 @@
7088 case 32:
7189 conf1 = HDMI_AUD_CONF1_WIDTH_24;
7290 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;
73109 default:
74
- dev_err(dev, "unsupported sample width [%d]\n", hparms->sample_width);
110
+ dev_err(dev, "unsupported format\n");
75111 return -EINVAL;
76112 }
77113
78
- switch (hparms->channels) {
79
- case 2:
80
- conf0 = HDMI_AUD_CONF0_I2S_2CHANNEL_ENABLE;
81
- break;
82
- case 4:
83
- conf0 = HDMI_AUD_CONF0_I2S_4CHANNEL_ENABLE;
84
- break;
85
- case 6:
86
- conf0 = HDMI_AUD_CONF0_I2S_6CHANNEL_ENABLE;
87
- break;
88
- case 8:
89
- 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;
90118 break;
91119 default:
92
- dev_err(dev, "unsupported channels [%d]\n", hparms->channels);
93
- return -EINVAL;
94
- }
95
-
96
- /*
97
- * dw-hdmi introduced insert_pcuv bit in version 2.10a.
98
- * When set (1'b1), this bit enables the insertion of the PCUV
99
- * (Parity, Channel Status, User bit and Validity) bits on the
100
- * incoming audio stream (support limited to Linear PCM audio)
101
- */
102
- val = 0;
103
- if (hdmi_read(audio, HDMI_DESIGN_ID) >= 0x21)
104
- val = HDMI_AUD_CONF2_INSERT_PCUV;
105
-
106
- /*Mask fifo empty and full int and reset fifo*/
107
- hdmi_update_bits(audio,
108
- HDMI_AUD_INT_FIFO_EMPTY_MSK |
109
- HDMI_AUD_INT_FIFO_FULL_MSK,
110
- HDMI_AUD_INT_FIFO_EMPTY_MSK |
111
- HDMI_AUD_INT_FIFO_FULL_MSK, HDMI_AUD_INT);
112
- hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
113
- HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
114
- hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK,
115
- HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ);
116
-
117
- switch (hparms->mode) {
118
- case NLPCM:
119
- hdmi_write(audio, HDMI_AUD_CONF2_NLPCM, HDMI_AUD_CONF2);
120
- conf1 = HDMI_AUD_CONF1_WIDTH_21;
121
- break;
122
- case HBR:
123
- hdmi_write(audio, HDMI_AUD_CONF2_HBR, HDMI_AUD_CONF2);
124
- conf1 = HDMI_AUD_CONF1_WIDTH_21;
125
- break;
126
- default:
127
- 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;
128128 break;
129129 }
130130
131131 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);
132135
133136 hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
134137 hdmi_write(audio, conf0, HDMI_AUD_CONF0);
135138 hdmi_write(audio, conf1, HDMI_AUD_CONF1);
139
+ hdmi_write(audio, conf2, HDMI_AUD_CONF2);
136140
137
- val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0;
138
- if (hparms->channels > 2)
139
- val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1;
140
- hdmi_update_bits(audio, val, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK,
141
- HDMI_FC_AUDSCONF);
141
+ return 0;
142
+}
142143
143
- switch (hparms->sample_rate) {
144
- case 32000:
145
- val = HDMI_FC_AUDSCHNLS_32K;
146
- break;
147
- case 44100:
148
- val = HDMI_FC_AUDSCHNLS_441K;
149
- break;
150
- case 48000:
151
- val = HDMI_FC_AUDSCHNLS_48K;
152
- break;
153
- case 88200:
154
- val = HDMI_FC_AUDSCHNLS_882K;
155
- break;
156
- case 96000:
157
- val = HDMI_FC_AUDSCHNLS_96K;
158
- break;
159
- case 176400:
160
- val = HDMI_FC_AUDSCHNLS_1764K;
161
- break;
162
- case 192000:
163
- val = HDMI_FC_AUDSCHNLS_192K;
164
- break;
165
- default:
166
- val = HDMI_FC_AUDSCHNLS_441K;
167
- break;
168
- }
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
+}
169150
170
- /* set channel status register */
171
- hdmi_update_bits(audio, val,
172
- HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK,
173
- HDMI_FC_AUDSCHNLS7);
174
- hdmi_write(audio,
175
- (((u8)~val) << HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET),
176
- HDMI_FC_AUDSCHNLS8);
177
-
178
- /* Refer to CEA861-E Audio infoFrame
179
- * Set both Audio Channel Count and Audio Coding
180
- * Type Refer to Stream Head for HDMI
181
- */
182
- hdmi_update_bits(audio,
183
- (hparms->channels - 1) << HDMI_FC_AUDICONF0_CC_OFFSET,
184
- HDMI_FC_AUDICONF0_CC_MASK, HDMI_FC_AUDICONF0);
185
-
186
- /* Set both Audio Sample Size and Sample Frequency
187
- * Refer to Stream Head for HDMI
188
- */
189
- hdmi_write(audio, 0x00, HDMI_FC_AUDICONF1);
190
-
191
- /* Set Channel Allocation */
192
- hdmi_write(audio, 0x00, HDMI_FC_AUDICONF2);
193
-
194
- /* Set LFEPBLDOWN-MIX INH and LSV */
195
- 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;
196155
197156 dw_hdmi_audio_enable(hdmi);
198157
199
- hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
200
- HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
201
- hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK,
202
- HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ);
158
+ return 0;
159
+}
160
+
161
+static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
162
+{
163
+ struct dw_hdmi_i2s_audio_data *audio = data;
164
+ struct dw_hdmi *hdmi = audio->hdmi;
165
+
166
+ dw_hdmi_audio_disable(hdmi);
167
+}
168
+
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);
203181
204182 return 0;
205183 }
....@@ -236,6 +214,10 @@
236214
237215 static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
238216 .hw_params = dw_hdmi_i2s_hw_params,
217
+ .prepare = dw_hdmi_i2s_prepare,
218
+ .audio_startup = dw_hdmi_i2s_audio_startup,
219
+ .audio_shutdown = dw_hdmi_i2s_audio_shutdown,
220
+ .get_eld = dw_hdmi_i2s_get_eld,
239221 .get_dai_id = dw_hdmi_i2s_get_dai_id,
240222 .hook_plugged_cb = dw_hdmi_i2s_hook_plugged_cb,
241223 };