dw_hdmi.c revision 1.7 1 /* $NetBSD: dw_hdmi.c,v 1.7 2019/12/22 23:23:32 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2019 Jared D. McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: dw_hdmi.c,v 1.7 2019/12/22 23:23:32 thorpej Exp $");
31
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/device.h>
35 #include <sys/intr.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/conf.h>
39
40 #include <dev/ic/dw_hdmi.h>
41
42 #include <dev/i2c/i2cvar.h>
43 #include <dev/i2c/ddcvar.h>
44 #include <dev/i2c/ddcreg.h>
45 #include <dev/videomode/videomode.h>
46 #include <dev/videomode/edidvar.h>
47
48 #include <dev/audio/audio_dai.h>
49
50 #include <drm/drmP.h>
51 #include <drm/drm_crtc.h>
52 #include <drm/drm_crtc_helper.h>
53 #include <drm/drm_edid.h>
54
55 #define HDMI_DESIGN_ID 0x0000
56 #define HDMI_REVISION_ID 0x0001
57 #define HDMI_CONFIG0_ID 0x0004
58 #define HDMI_CONFIG0_ID_AUDI2S __BIT(4)
59 #define HDMI_CONFIG2_ID 0x0006
60
61 #define HDMI_IH_I2CM_STAT0 0x0105
62 #define HDMI_IH_I2CM_STAT0_DONE __BIT(1)
63 #define HDMI_IH_I2CM_STAT0_ERROR __BIT(0)
64 #define HDMI_IH_MUTE 0x01ff
65 #define HDMI_IH_MUTE_WAKEUP_INTERRUPT __BIT(1)
66 #define HDMI_IH_MUTE_ALL_INTERRUPT __BIT(0)
67
68 #define HDMI_TX_INVID0 0x0200
69 #define HDMI_TX_INVID0_VIDEO_MAPPING __BITS(4,0)
70 #define HDMI_TX_INVID0_VIDEO_MAPPING_DEFAULT 1
71 #define HDMI_TX_INSTUFFING 0x0201
72 #define HDMI_TX_INSTUFFING_BCBDATA_STUFFING __BIT(2)
73 #define HDMI_TX_INSTUFFING_RCRDATA_STUFFING __BIT(1)
74 #define HDMI_TX_INSTUFFING_GYDATA_STUFFING __BIT(0)
75 #define HDMI_TX_GYDATA0 0x0202
76 #define HDMI_TX_GYDATA1 0x0203
77 #define HDMI_TX_RCRDATA0 0x0204
78 #define HDMI_TX_RCRDATA1 0x0205
79 #define HDMI_TX_BCBDATA0 0x0206
80 #define HDMI_TX_BCBDATA1 0x0207
81
82 #define HDMI_VP_STATUS 0x0800
83 #define HDMI_VP_PR_CD 0x0801
84 #define HDMI_VP_PR_CD_COLOR_DEPTH __BITS(7,4)
85 #define HDMI_VP_PR_CD_COLOR_DEPTH_24 0
86 #define HDMI_VP_PR_CD_DESIRED_PR_FACTOR __BITS(3,0)
87 #define HDMI_VP_PR_CD_DESIRED_PR_FACTOR_NONE 0
88 #define HDMI_VP_STUFF 0x0802
89 #define HDMI_VP_STUFF_IDEFAULT_PHASE __BIT(5)
90 #define HDMI_VP_STUFF_YCC422_STUFFING __BIT(2)
91 #define HDMI_VP_STUFF_PP_STUFFING __BIT(1)
92 #define HDMI_VP_STUFF_PR_STUFFING __BIT(0)
93 #define HDMI_VP_REMAP 0x0803
94 #define HDMI_VP_REMAP_YCC422_SIZE __BITS(1,0)
95 #define HDMI_VP_REMAP_YCC422_SIZE_16 0
96 #define HDMI_VP_CONF 0x0804
97 #define HDMI_VP_CONF_BYPASS_EN __BIT(6)
98 #define HDMI_VP_CONF_BYPASS_SELECT __BIT(2)
99 #define HDMI_VP_CONF_OUTPUT_SELECT __BITS(1,0)
100 #define HDMI_VP_CONF_OUTPUT_SELECT_BYPASS 2
101 #define HDMI_VP_STAT 0x0805
102 #define HDMI_VP_INT 0x0806
103 #define HDMI_VP_MASK 0x0807
104 #define HDMI_VP_POL 0x0808
105
106 #define HDMI_FC_INVIDCONF 0x1000
107 #define HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY __BIT(6)
108 #define HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY __BIT(5)
109 #define HDMI_FC_INVIDCONF_DE_IN_POLARITY __BIT(4)
110 #define HDMI_FC_INVIDCONF_DVI_MODE __BIT(3)
111 #define HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC __BIT(1)
112 #define HDMI_FC_INVIDCONF_IN_I_P __BIT(0)
113 #define HDMI_FC_INHACTIV0 0x1001
114 #define HDMI_FC_INHACTIV1 0x1002
115 #define HDMI_FC_INHBLANK0 0x1003
116 #define HDMI_FC_INHBLANK1 0x1004
117 #define HDMI_FC_INVACTIV0 0x1005
118 #define HDMI_FC_INVACTIV1 0x1006
119 #define HDMI_FC_INVBLANK 0x1007
120 #define HDMI_FC_HSYNCINDELAY0 0x1008
121 #define HDMI_FC_HSYNCINDELAY1 0x1009
122 #define HDMI_FC_HSYNCINWIDTH0 0x100a
123 #define HDMI_FC_HSYNCINWIDTH1 0x100b
124 #define HDMI_FC_VSYNCINDELAY 0x100c
125 #define HDMI_FC_VSYNCINWIDTH 0x100d
126 #define HDMI_FC_CTRLDUR 0x1011
127 #define HDMI_FC_CTRLDUR_DEFAULT 12
128 #define HDMI_FC_EXCTRLDUR 0x1012
129 #define HDMI_FC_EXCTRLDUR_DEFAULT 32
130 #define HDMI_FC_EXCTRLSPAC 0x1013
131 #define HDMI_FC_EXCTRLSPAC_DEFAULT 1
132 #define HDMI_FC_CH0PREAM 0x1014
133 #define HDMI_FC_CH0PREAM_DEFAULT 0x0b
134 #define HDMI_FC_CH1PREAM 0x1015
135 #define HDMI_FC_CH1PREAM_DEFAULT 0x16
136 #define HDMI_FC_CH2PREAM 0x1016
137 #define HDMI_FC_CH2PREAM_DEFAULT 0x21
138 #define HDMI_FC_AUDCONF0 0x1025
139 #define HDMI_FC_AUDCONF1 0x1026
140 #define HDMI_FC_AUDCONF2 0x1027
141 #define HDMI_FC_AUDCONF3 0x1028
142
143 #define HDMI_PHY_CONF0 0x3000
144 #define HDMI_PHY_CONF0_PDZ __BIT(7)
145 #define HDMI_PHY_CONF0_ENTMDS __BIT(6)
146 #define HDMI_PHY_CONF0_SVSRET __BIT(5)
147 #define HDMI_PHY_CONF0_PDDQ __BIT(4)
148 #define HDMI_PHY_CONF0_TXPWRON __BIT(3)
149 #define HDMI_PHY_CONF0_ENHPDRXSENSE __BIT(2)
150 #define HDMI_PHY_CONF0_SELDATAENPOL __BIT(1)
151 #define HDMI_PHY_CONF0_SELDIPIF __BIT(0)
152 #define HDMI_PHY_STAT0 0x3004
153 #define HDMI_PHY_STAT0_RX_SENSE_3 __BIT(7)
154 #define HDMI_PHY_STAT0_RX_SENSE_2 __BIT(6)
155 #define HDMI_PHY_STAT0_RX_SENSE_1 __BIT(5)
156 #define HDMI_PHY_STAT0_RX_SENSE_0 __BIT(4)
157 #define HDMI_PHY_STAT0_HPD __BIT(1)
158 #define HDMI_PHY_STAT0_TX_PHY_LOCK __BIT(0)
159
160 #define HDMI_AUD_CONF0 0x3100
161 #define HDMI_AUD_CONF0_SW_AUDIO_FIFO_RST __BIT(7)
162 #define HDMI_AUD_CONF0_I2S_SELECT __BIT(5)
163 #define HDMI_AUD_CONF0_I2S_IN_EN __BITS(3,0)
164 #define HDMI_AUD_CONF1 0x3101
165 #define HDMI_AUD_CONF1_I2S_WIDTH __BITS(4,0)
166 #define HDMI_AUD_INT 0x3102
167 #define HDMI_AUD_CONF2 0x3103
168 #define HDMI_AUD_CONF2_INSERT_PCUV __BIT(2)
169 #define HDMI_AUD_CONF2_NLPCM __BIT(1)
170 #define HDMI_AUD_CONF2_HBR __BIT(0)
171 #define HDMI_AUD_INT1 0x3104
172
173 #define HDMI_AUD_N1 0x3200
174 #define HDMI_AUD_N2 0x3201
175 #define HDMI_AUD_N3 0x3202
176 #define HDMI_AUD_CTS1 0x3203
177 #define HDMI_AUD_CTS2 0x3204
178 #define HDMI_AUD_CTS3 0x3205
179 #define HDMI_AUD_INPUTCLKFS 0x3206
180 #define HDMI_AUD_INPUTCLKFS_IFSFACTOR __BITS(2,0)
181
182 #define HDMI_MC_CLKDIS 0x4001
183 #define HDMI_MC_CLKDIS_HDCPCLK_DISABLE __BIT(6)
184 #define HDMI_MC_CLKDIS_CECCLK_DISABLE __BIT(5)
185 #define HDMI_MC_CLKDIS_CSCCLK_DISABLE __BIT(4)
186 #define HDMI_MC_CLKDIS_AUDCLK_DISABLE __BIT(3)
187 #define HDMI_MC_CLKDIS_PREPCLK_DISABLE __BIT(2)
188 #define HDMI_MC_CLKDIS_TMDSCLK_DISABLE __BIT(1)
189 #define HDMI_MC_CLKDIS_PIXELCLK_DISABLE __BIT(0)
190 #define HDMI_MC_SWRSTZREQ 0x4002
191 #define HDMI_MC_SWRSTZREQ_CECSWRST_REQ __BIT(6)
192 #define HDMI_MC_SWRSTZREQ_PREPSWRST_REQ __BIT(2)
193 #define HDMI_MC_SWRSTZREQ_TMDSSWRST_REQ __BIT(1)
194 #define HDMI_MC_SWRSTZREQ_PIXELSWRST_REQ __BIT(0)
195 #define HDMI_MC_FLOWCTRL 0x4004
196 #define HDMI_MC_PHYRSTZ 0x4005
197 #define HDMI_MC_PHYRSTZ_ASSERT __BIT(0)
198 #define HDMI_MC_PHYRSTZ_DEASSERT 0
199 #define HDMI_MC_LOCKONCLOCK 0x4006
200 #define HDMI_MC_HEACPHY_RST 0x4007
201
202 #define HDMI_I2CM_SLAVE 0x7e00
203 #define HDMI_I2CM_ADDRESS 0x7e01
204 #define HDMI_I2CM_DATAO 0x7e02
205 #define HDMI_I2CM_DATAI 0x7e03
206 #define HDMI_I2CM_OPERATION 0x7e04
207 #define HDMI_I2CM_OPERATION_WR __BIT(4)
208 #define HDMI_I2CM_OPERATION_RD_EXT __BIT(1)
209 #define HDMI_I2CM_OPERATION_RD __BIT(0)
210 #define HDMI_I2CM_INT 0x7e05
211 #define HDMI_I2CM_INT_DONE_POL __BIT(3)
212 #define HDMI_I2CM_INT_DONE_MASK __BIT(2)
213 #define HDMI_I2CM_INT_DONE_INTERRUPT __BIT(1)
214 #define HDMI_I2CM_INT_DONE_STATUS __BIT(0)
215 #define HDMI_I2CM_INT_DEFAULT \
216 (HDMI_I2CM_INT_DONE_POL| \
217 HDMI_I2CM_INT_DONE_INTERRUPT| \
218 HDMI_I2CM_INT_DONE_STATUS)
219 #define HDMI_I2CM_CTLINT 0x7e06
220 #define HDMI_I2CM_CTLINT_NACK_POL __BIT(7)
221 #define HDMI_I2CM_CTLINT_NACK_MASK __BIT(6)
222 #define HDMI_I2CM_CTLINT_NACK_INTERRUPT __BIT(5)
223 #define HDMI_I2CM_CTLINT_NACK_STATUS __BIT(4)
224 #define HDMI_I2CM_CTLINT_ARB_POL __BIT(3)
225 #define HDMI_I2CM_CTLINT_ARB_MASK __BIT(2)
226 #define HDMI_I2CM_CTLINT_ARB_INTERRUPT __BIT(1)
227 #define HDMI_I2CM_CTLINT_ARB_STATUS __BIT(0)
228 #define HDMI_I2CM_CTLINT_DEFAULT \
229 (HDMI_I2CM_CTLINT_NACK_POL| \
230 HDMI_I2CM_CTLINT_NACK_INTERRUPT| \
231 HDMI_I2CM_CTLINT_NACK_STATUS| \
232 HDMI_I2CM_CTLINT_ARB_POL| \
233 HDMI_I2CM_CTLINT_ARB_INTERRUPT| \
234 HDMI_I2CM_CTLINT_ARB_STATUS)
235 #define HDMI_I2CM_DIV 0x7e07
236 #define HDMI_I2CM_DIV_FAST_STD_MODE __BIT(3)
237 #define HDMI_I2CM_SEGADDR 0x7e08
238 #define HDMI_I2CM_SEGADDR_SEGADDR __BITS(6,0)
239 #define HDMI_I2CM_SOFTRSTZ 0x7e09
240 #define HDMI_I2CM_SOFTRSTZ_I2C_SOFTRST __BIT(0)
241 #define HDMI_I2CM_SEGPTR 0x7e0a
242 #define HDMI_I2CM_SS_SCL_HCNT_0_ADDR 0x730c
243 #define HDMI_I2CM_SS_SCL_LCNT_0_ADDR 0x730e
244
245 enum dwhdmi_dai_mixer_ctrl {
246 DWHDMI_DAI_OUTPUT_CLASS,
247 DWHDMI_DAI_INPUT_CLASS,
248
249 DWHDMI_DAI_OUTPUT_MASTER_VOLUME,
250 DWHDMI_DAI_INPUT_DAC_VOLUME,
251
252 DWHDMI_DAI_MIXER_CTRL_LAST
253 };
254
255 static int
256 dwhdmi_ddc_exec(void *priv, i2c_op_t op, i2c_addr_t addr,
257 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
258 {
259 struct dwhdmi_softc * const sc = priv;
260 uint8_t block, operation, val;
261 uint8_t *pbuf = buf;
262 int off, n, retry;
263
264 if (addr != DDC_ADDR || op != I2C_OP_READ_WITH_STOP || cmdlen == 0 || buf == NULL) {
265 printf("dwhdmi_ddc_exec: bad args addr=%#x op=%#x cmdlen=%d buf=%p\n",
266 addr, op, (int)cmdlen, buf);
267 return ENXIO;
268 }
269 if (len > 256) {
270 printf("dwhdmi_ddc_exec: bad len %d\n", (int)len);
271 return ERANGE;
272 }
273
274 dwhdmi_write(sc, HDMI_I2CM_SOFTRSTZ, 0);
275 dwhdmi_write(sc, HDMI_IH_I2CM_STAT0, dwhdmi_read(sc, HDMI_IH_I2CM_STAT0));
276 if (sc->sc_scl_hcnt)
277 dwhdmi_write(sc, HDMI_I2CM_SS_SCL_HCNT_0_ADDR, sc->sc_scl_hcnt);
278 if (sc->sc_scl_lcnt)
279 dwhdmi_write(sc, HDMI_I2CM_SS_SCL_LCNT_0_ADDR, sc->sc_scl_lcnt);
280 dwhdmi_write(sc, HDMI_I2CM_DIV, 0);
281 dwhdmi_write(sc, HDMI_I2CM_SLAVE, DDC_ADDR);
282 dwhdmi_write(sc, HDMI_I2CM_SEGADDR, DDC_SEGMENT_ADDR);
283
284 block = *(const uint8_t *)cmdbuf;
285 operation = block ? HDMI_I2CM_OPERATION_RD_EXT : HDMI_I2CM_OPERATION_RD;
286 off = (block & 1) ? 128 : 0;
287
288 dwhdmi_write(sc, HDMI_I2CM_SEGPTR, block >> 1);
289
290 for (n = 0; n < len; n++) {
291 dwhdmi_write(sc, HDMI_I2CM_ADDRESS, n + off);
292 dwhdmi_write(sc, HDMI_I2CM_OPERATION, operation);
293 for (retry = 10000; retry > 0; retry--) {
294 val = dwhdmi_read(sc, HDMI_IH_I2CM_STAT0);
295 if (val & HDMI_IH_I2CM_STAT0_ERROR) {
296 return EIO;
297 }
298 if (val & HDMI_IH_I2CM_STAT0_DONE) {
299 dwhdmi_write(sc, HDMI_IH_I2CM_STAT0, val);
300 break;
301 }
302 delay(1);
303 }
304 if (retry == 0) {
305 printf("dwhdmi_ddc_exec: timeout waiting for xfer, stat0=%#x\n", dwhdmi_read(sc, HDMI_IH_I2CM_STAT0));
306 return ETIMEDOUT;
307 }
308
309 pbuf[n] = dwhdmi_read(sc, HDMI_I2CM_DATAI);
310 }
311
312 return 0;
313 }
314
315 uint8_t
316 dwhdmi_read(struct dwhdmi_softc *sc, bus_size_t reg)
317 {
318 uint8_t val;
319
320 switch (sc->sc_reg_width) {
321 case 1:
322 val = bus_space_read_1(sc->sc_bst, sc->sc_bsh, reg);
323 break;
324 case 4:
325 val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg * 4) & 0xff;
326 break;
327 default:
328 val = 0;
329 break;
330 }
331
332 return val;
333 }
334
335 void
336 dwhdmi_write(struct dwhdmi_softc *sc, bus_size_t reg, uint8_t val)
337 {
338 switch (sc->sc_reg_width) {
339 case 1:
340 bus_space_write_1(sc->sc_bst, sc->sc_bsh, reg, val);
341 break;
342 case 4:
343 bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg * 4, val);
344 break;
345 }
346 }
347
348 static void
349 dwhdmi_vp_init(struct dwhdmi_softc *sc)
350 {
351 uint8_t val;
352
353 /* Select 24-bits per pixel video, 8-bit packing mode and disable pixel repetition */
354 val = __SHIFTIN(HDMI_VP_PR_CD_COLOR_DEPTH_24, HDMI_VP_PR_CD_COLOR_DEPTH) |
355 __SHIFTIN(HDMI_VP_PR_CD_DESIRED_PR_FACTOR_NONE, HDMI_VP_PR_CD_DESIRED_PR_FACTOR);
356 dwhdmi_write(sc, HDMI_VP_PR_CD, val);
357
358 /* Configure stuffing */
359 val = HDMI_VP_STUFF_IDEFAULT_PHASE |
360 HDMI_VP_STUFF_YCC422_STUFFING |
361 HDMI_VP_STUFF_PP_STUFFING |
362 HDMI_VP_STUFF_PR_STUFFING;
363 dwhdmi_write(sc, HDMI_VP_STUFF, val);
364
365 /* Set YCC422 remap to 16-bit input video */
366 val = __SHIFTIN(HDMI_VP_REMAP_YCC422_SIZE_16, HDMI_VP_REMAP_YCC422_SIZE);
367 dwhdmi_write(sc, HDMI_VP_REMAP, val);
368
369 /* Configure video packetizer */
370 val = HDMI_VP_CONF_BYPASS_EN |
371 HDMI_VP_CONF_BYPASS_SELECT |
372 __SHIFTIN(HDMI_VP_CONF_OUTPUT_SELECT_BYPASS, HDMI_VP_CONF_OUTPUT_SELECT);
373 dwhdmi_write(sc, HDMI_VP_CONF, val);
374 }
375
376 static void
377 dwhdmi_tx_init(struct dwhdmi_softc *sc)
378 {
379 uint8_t val;
380
381 /* Disable internal data enable generator and set default video mapping */
382 val = __SHIFTIN(HDMI_TX_INVID0_VIDEO_MAPPING_DEFAULT, HDMI_TX_INVID0_VIDEO_MAPPING);
383 dwhdmi_write(sc, HDMI_TX_INVID0, val);
384
385 /* Enable video sampler stuffing */
386 val = HDMI_TX_INSTUFFING_BCBDATA_STUFFING |
387 HDMI_TX_INSTUFFING_RCRDATA_STUFFING |
388 HDMI_TX_INSTUFFING_GYDATA_STUFFING;
389 dwhdmi_write(sc, HDMI_TX_INSTUFFING, val);
390 }
391
392 static bool
393 dwhdmi_cea_mode_uses_fractional_vblank(uint8_t vic)
394 {
395 const uint8_t match[] = { 5, 6, 7, 10, 11, 20, 21, 22 };
396 u_int n;
397
398 for (n = 0; n < __arraycount(match); n++)
399 if (match[n] == vic)
400 return true;
401
402 return false;
403 }
404
405 static void
406 dwhdmi_fc_init(struct dwhdmi_softc *sc, struct drm_display_mode *mode)
407 {
408 struct dwhdmi_connector *dwhdmi_connector = &sc->sc_connector;
409 uint8_t val;
410
411 const uint8_t vic = drm_match_cea_mode(mode);
412 const uint16_t inhactiv = mode->crtc_hdisplay;
413 const uint16_t inhblank = mode->crtc_htotal - mode->crtc_hdisplay;
414 const uint16_t invactiv = mode->crtc_vdisplay;
415 const uint8_t invblank = mode->crtc_vtotal - mode->crtc_vdisplay;
416 const uint16_t hsyncindelay = mode->crtc_hsync_start - mode->crtc_hdisplay;
417 const uint16_t hsyncinwidth = mode->crtc_hsync_end - mode->crtc_hsync_start;
418 const uint8_t vsyncindelay = mode->crtc_vsync_start - mode->crtc_vdisplay;
419 const uint8_t vsyncinwidth = mode->crtc_vsync_end - mode->crtc_vsync_start;
420
421 /* Input video configuration for frame composer */
422 val = HDMI_FC_INVIDCONF_DE_IN_POLARITY;
423 if ((mode->flags & DRM_MODE_FLAG_PVSYNC) != 0)
424 val |= HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY;
425 if ((mode->flags & DRM_MODE_FLAG_PHSYNC) != 0)
426 val |= HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY;
427 if ((mode->flags & DRM_MODE_FLAG_INTERLACE) != 0)
428 val |= HDMI_FC_INVIDCONF_IN_I_P;
429 if (dwhdmi_connector->hdmi_monitor)
430 val |= HDMI_FC_INVIDCONF_DVI_MODE;
431 if (dwhdmi_cea_mode_uses_fractional_vblank(vic))
432 val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC;
433 dwhdmi_write(sc, HDMI_FC_INVIDCONF, val);
434
435 /* Input video mode timings */
436 dwhdmi_write(sc, HDMI_FC_INHACTIV0, inhactiv & 0xff);
437 dwhdmi_write(sc, HDMI_FC_INHACTIV1, inhactiv >> 8);
438 dwhdmi_write(sc, HDMI_FC_INHBLANK0, inhblank & 0xff);
439 dwhdmi_write(sc, HDMI_FC_INHBLANK1, inhblank >> 8);
440 dwhdmi_write(sc, HDMI_FC_INVACTIV0, invactiv & 0xff);
441 dwhdmi_write(sc, HDMI_FC_INVACTIV1, invactiv >> 8);
442 dwhdmi_write(sc, HDMI_FC_INVBLANK, invblank);
443 dwhdmi_write(sc, HDMI_FC_HSYNCINDELAY0, hsyncindelay & 0xff);
444 dwhdmi_write(sc, HDMI_FC_HSYNCINDELAY1, hsyncindelay >> 8);
445 dwhdmi_write(sc, HDMI_FC_HSYNCINWIDTH0, hsyncinwidth & 0xff);
446 dwhdmi_write(sc, HDMI_FC_HSYNCINWIDTH1, hsyncinwidth >> 8);
447 dwhdmi_write(sc, HDMI_FC_VSYNCINDELAY, vsyncindelay);
448 dwhdmi_write(sc, HDMI_FC_VSYNCINWIDTH, vsyncinwidth);
449
450 /* Setup control period minimum durations */
451 dwhdmi_write(sc, HDMI_FC_CTRLDUR, HDMI_FC_CTRLDUR_DEFAULT);
452 dwhdmi_write(sc, HDMI_FC_EXCTRLDUR, HDMI_FC_EXCTRLDUR_DEFAULT);
453 dwhdmi_write(sc, HDMI_FC_EXCTRLSPAC, HDMI_FC_EXCTRLSPAC_DEFAULT);
454
455 /* Setup channel preamble filters */
456 dwhdmi_write(sc, HDMI_FC_CH0PREAM, HDMI_FC_CH0PREAM_DEFAULT);
457 dwhdmi_write(sc, HDMI_FC_CH1PREAM, HDMI_FC_CH1PREAM_DEFAULT);
458 dwhdmi_write(sc, HDMI_FC_CH2PREAM, HDMI_FC_CH2PREAM_DEFAULT);
459 }
460
461 static void
462 dwhdmi_mc_init(struct dwhdmi_softc *sc)
463 {
464 uint8_t val;
465 u_int n, iter;
466
467 /* Bypass colour space converter */
468 dwhdmi_write(sc, HDMI_MC_FLOWCTRL, 0);
469
470 /* Enable TMDS, pixel, and (if required) audio sampler clocks */
471 val = HDMI_MC_CLKDIS_HDCPCLK_DISABLE |
472 HDMI_MC_CLKDIS_CECCLK_DISABLE |
473 HDMI_MC_CLKDIS_CSCCLK_DISABLE |
474 HDMI_MC_CLKDIS_PREPCLK_DISABLE;
475 dwhdmi_write(sc, HDMI_MC_CLKDIS, val);
476
477 /* Soft reset TMDS */
478 val = 0xff & ~HDMI_MC_SWRSTZREQ_TMDSSWRST_REQ;
479 dwhdmi_write(sc, HDMI_MC_SWRSTZREQ, val);
480
481 iter = sc->sc_version == 0x130a ? 4 : 1;
482
483 val = dwhdmi_read(sc, HDMI_FC_INVIDCONF);
484 for (n = 0; n < iter; n++)
485 dwhdmi_write(sc, HDMI_FC_INVIDCONF, val);
486 }
487
488 static void
489 dwhdmi_mc_disable(struct dwhdmi_softc *sc)
490 {
491 /* Disable clocks */
492 dwhdmi_write(sc, HDMI_MC_CLKDIS, 0xff);
493 }
494
495 static void
496 dwhdmi_audio_init(struct dwhdmi_softc *sc)
497 {
498 uint8_t val;
499 u_int n;
500
501 /* The following values are for 48 kHz */
502 switch (sc->sc_curmode.clock) {
503 case 25170:
504 n = 6864;
505 break;
506 case 74170:
507 n = 11648;
508 break;
509 case 148350:
510 n = 5824;
511 break;
512 default:
513 n = 6144;
514 break;
515 }
516
517 /* Use automatic CTS generation */
518 dwhdmi_write(sc, HDMI_AUD_CTS1, 0);
519 dwhdmi_write(sc, HDMI_AUD_CTS2, 0);
520 dwhdmi_write(sc, HDMI_AUD_CTS3, 0);
521
522 /* Set N factor for audio clock regeneration */
523 dwhdmi_write(sc, HDMI_AUD_N1, n & 0xff);
524 dwhdmi_write(sc, HDMI_AUD_N2, (n >> 8) & 0xff);
525 dwhdmi_write(sc, HDMI_AUD_N3, (n >> 16) & 0xff);
526
527 val = dwhdmi_read(sc, HDMI_AUD_CONF0);
528 val |= HDMI_AUD_CONF0_I2S_SELECT; /* XXX i2s mode */
529 val &= ~HDMI_AUD_CONF0_I2S_IN_EN;
530 val |= __SHIFTIN(1, HDMI_AUD_CONF0_I2S_IN_EN); /* XXX 2ch */
531 dwhdmi_write(sc, HDMI_AUD_CONF0, val);
532
533 val = __SHIFTIN(16, HDMI_AUD_CONF1_I2S_WIDTH);
534 dwhdmi_write(sc, HDMI_AUD_CONF1, val);
535
536 dwhdmi_write(sc, HDMI_AUD_INPUTCLKFS, 4); /* XXX 64 FS */
537
538 dwhdmi_write(sc, HDMI_FC_AUDCONF0, 1 << 4); /* XXX 2ch */
539 dwhdmi_write(sc, HDMI_FC_AUDCONF1, 0);
540 dwhdmi_write(sc, HDMI_FC_AUDCONF2, 0);
541 dwhdmi_write(sc, HDMI_FC_AUDCONF3, 0);
542
543 val = dwhdmi_read(sc, HDMI_MC_CLKDIS);
544 val &= ~HDMI_MC_CLKDIS_PREPCLK_DISABLE;
545 dwhdmi_write(sc, HDMI_MC_CLKDIS, val);
546 }
547
548 static enum drm_connector_status
549 dwhdmi_connector_detect(struct drm_connector *connector, bool force)
550 {
551 struct dwhdmi_connector *dwhdmi_connector = to_dwhdmi_connector(connector);
552 struct dwhdmi_softc * const sc = dwhdmi_connector->sc;
553
554 if (sc->sc_detect != NULL)
555 return sc->sc_detect(sc, force);
556
557 return connector_status_connected;
558 }
559
560 static void
561 dwhdmi_connector_destroy(struct drm_connector *connector)
562 {
563 drm_connector_unregister(connector);
564 drm_connector_cleanup(connector);
565 }
566
567 static const struct drm_connector_funcs dwhdmi_connector_funcs = {
568 .dpms = drm_helper_connector_dpms,
569 .detect = dwhdmi_connector_detect,
570 .fill_modes = drm_helper_probe_single_connector_modes,
571 .destroy = dwhdmi_connector_destroy,
572 };
573
574 static int
575 dwhdmi_connector_get_modes(struct drm_connector *connector)
576 {
577 struct dwhdmi_connector *dwhdmi_connector = to_dwhdmi_connector(connector);
578 struct dwhdmi_softc * const sc = dwhdmi_connector->sc;
579 char edid[EDID_LENGTH * 4];
580 struct edid *pedid = NULL;
581 int error, block;
582
583 memset(edid, 0, sizeof(edid));
584 for (block = 0; block < 4; block++) {
585 error = ddc_read_edid_block(sc->sc_ic,
586 &edid[block * EDID_LENGTH], EDID_LENGTH, block);
587 if (error != 0)
588 break;
589 if (block == 0) {
590 pedid = (struct edid *)edid;
591 if (edid[0x7e] == 0)
592 break;
593 }
594 }
595
596 if (pedid) {
597 dwhdmi_connector->hdmi_monitor = drm_detect_hdmi_monitor(pedid);
598 dwhdmi_connector->monitor_audio = drm_detect_monitor_audio(pedid);
599 } else {
600 dwhdmi_connector->hdmi_monitor = false;
601 dwhdmi_connector->monitor_audio = false;
602 }
603
604 drm_mode_connector_update_edid_property(connector, pedid);
605 if (pedid == NULL)
606 return 0;
607
608 error = drm_add_edid_modes(connector, pedid);
609 drm_edid_to_eld(connector, pedid);
610
611 return error;
612 }
613
614 static struct drm_encoder *
615 dwhdmi_connector_best_encoder(struct drm_connector *connector)
616 {
617 int enc_id = connector->encoder_ids[0];
618 struct drm_mode_object *obj;
619 struct drm_encoder *encoder = NULL;
620
621 if (enc_id) {
622 obj = drm_mode_object_find(connector->dev, enc_id,
623 DRM_MODE_OBJECT_ENCODER);
624 if (obj == NULL)
625 return NULL;
626 encoder = obj_to_encoder(obj);
627 }
628
629 return encoder;
630 }
631
632 static const struct drm_connector_helper_funcs dwhdmi_connector_helper_funcs = {
633 .get_modes = dwhdmi_connector_get_modes,
634 .best_encoder = dwhdmi_connector_best_encoder,
635 };
636
637 static int
638 dwhdmi_bridge_attach(struct drm_bridge *bridge)
639 {
640 struct dwhdmi_softc * const sc = bridge->driver_private;
641 struct dwhdmi_connector *dwhdmi_connector = &sc->sc_connector;
642 struct drm_connector *connector = &dwhdmi_connector->base;
643 int error;
644
645 dwhdmi_connector->sc = sc;
646
647 connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
648 connector->interlace_allowed = 0;
649 connector->doublescan_allowed = 0;
650
651 drm_connector_init(bridge->dev, connector, &dwhdmi_connector_funcs,
652 DRM_MODE_CONNECTOR_HDMIA);
653 drm_connector_helper_add(connector, &dwhdmi_connector_helper_funcs);
654
655 error = drm_mode_connector_attach_encoder(connector, bridge->encoder);
656 if (error != 0)
657 return error;
658
659 return drm_connector_register(connector);
660 }
661
662 static void
663 dwhdmi_bridge_enable(struct drm_bridge *bridge)
664 {
665 struct dwhdmi_softc * const sc = bridge->driver_private;
666
667 dwhdmi_vp_init(sc);
668 dwhdmi_fc_init(sc, &sc->sc_curmode);
669
670 if (sc->sc_enable)
671 sc->sc_enable(sc);
672
673 dwhdmi_tx_init(sc);
674 dwhdmi_mc_init(sc);
675
676 if (sc->sc_connector.monitor_audio)
677 dwhdmi_audio_init(sc);
678 }
679
680 static void
681 dwhdmi_bridge_pre_enable(struct drm_bridge *bridge)
682 {
683 }
684
685 static void
686 dwhdmi_bridge_disable(struct drm_bridge *bridge)
687 {
688 struct dwhdmi_softc * const sc = bridge->driver_private;
689
690 if (sc->sc_disable)
691 sc->sc_disable(sc);
692
693 dwhdmi_mc_disable(sc);
694 }
695
696 static void
697 dwhdmi_bridge_post_disable(struct drm_bridge *bridge)
698 {
699 }
700
701 static void
702 dwhdmi_bridge_mode_set(struct drm_bridge *bridge,
703 struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
704 {
705 struct dwhdmi_softc * const sc = bridge->driver_private;
706
707 if (sc->sc_mode_set)
708 sc->sc_mode_set(sc, mode, adjusted_mode);
709
710 sc->sc_curmode = *adjusted_mode;
711 }
712
713 static bool
714 dwhdmi_bridge_mode_fixup(struct drm_bridge *bridge,
715 const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
716 {
717 return true;
718 }
719
720 static const struct drm_bridge_funcs dwhdmi_bridge_funcs = {
721 .attach = dwhdmi_bridge_attach,
722 .enable = dwhdmi_bridge_enable,
723 .pre_enable = dwhdmi_bridge_pre_enable,
724 .disable = dwhdmi_bridge_disable,
725 .post_disable = dwhdmi_bridge_post_disable,
726 .mode_set = dwhdmi_bridge_mode_set,
727 .mode_fixup = dwhdmi_bridge_mode_fixup,
728 };
729
730 static int
731 dwhdmi_dai_set_format(audio_dai_tag_t dai, u_int format)
732 {
733 return 0;
734 }
735
736 static int
737 dwhdmi_dai_add_device(audio_dai_tag_t dai, audio_dai_tag_t aux)
738 {
739 /* Not supported */
740 return 0;
741 }
742
743 static void
744 dwhdmi_audio_swvol_codec(audio_filter_arg_t *arg)
745 {
746 struct dwhdmi_softc * const sc = arg->context;
747 const aint_t *src;
748 aint_t *dst;
749 u_int sample_count;
750 u_int i;
751
752 src = arg->src;
753 dst = arg->dst;
754 sample_count = arg->count * arg->srcfmt->channels;
755 for (i = 0; i < sample_count; i++) {
756 aint2_t v = (aint2_t)(*src++);
757 v = v * sc->sc_swvol / 255;
758 *dst++ = (aint_t)v;
759 }
760 }
761
762 static int
763 dwhdmi_audio_set_format(void *priv, int setmode,
764 const audio_params_t *play, const audio_params_t *rec,
765 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
766 {
767 struct dwhdmi_softc * const sc = priv;
768
769 pfil->codec = dwhdmi_audio_swvol_codec;
770 pfil->context = sc;
771
772 return 0;
773 }
774
775 static int
776 dwhdmi_audio_set_port(void *priv, mixer_ctrl_t *mc)
777 {
778 struct dwhdmi_softc * const sc = priv;
779
780 switch (mc->dev) {
781 case DWHDMI_DAI_OUTPUT_MASTER_VOLUME:
782 case DWHDMI_DAI_INPUT_DAC_VOLUME:
783 sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
784 return 0;
785 default:
786 return ENXIO;
787 }
788 }
789
790 static int
791 dwhdmi_audio_get_port(void *priv, mixer_ctrl_t *mc)
792 {
793 struct dwhdmi_softc * const sc = priv;
794
795 switch (mc->dev) {
796 case DWHDMI_DAI_OUTPUT_MASTER_VOLUME:
797 case DWHDMI_DAI_INPUT_DAC_VOLUME:
798 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_swvol;
799 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_swvol;
800 return 0;
801 default:
802 return ENXIO;
803 }
804 }
805
806 static int
807 dwhdmi_audio_query_devinfo(void *priv, mixer_devinfo_t *di)
808 {
809 switch (di->index) {
810 case DWHDMI_DAI_OUTPUT_CLASS:
811 di->mixer_class = di->index;
812 strcpy(di->label.name, AudioCoutputs);
813 di->type = AUDIO_MIXER_CLASS;
814 di->next = di->prev = AUDIO_MIXER_LAST;
815 return 0;
816
817 case DWHDMI_DAI_INPUT_CLASS:
818 di->mixer_class = di->index;
819 strcpy(di->label.name, AudioCinputs);
820 di->type = AUDIO_MIXER_CLASS;
821 di->next = di->prev = AUDIO_MIXER_LAST;
822 return 0;
823
824 case DWHDMI_DAI_OUTPUT_MASTER_VOLUME:
825 di->mixer_class = DWHDMI_DAI_OUTPUT_CLASS;
826 strcpy(di->label.name, AudioNmaster);
827 di->un.v.delta = 1;
828 di->un.v.num_channels = 2;
829 strcpy(di->un.v.units.name, AudioNvolume);
830 di->type = AUDIO_MIXER_VALUE;
831 di->next = di->prev = AUDIO_MIXER_LAST;
832 return 0;
833
834 case DWHDMI_DAI_INPUT_DAC_VOLUME:
835 di->mixer_class = DWHDMI_DAI_INPUT_CLASS;
836 strcpy(di->label.name, AudioNdac);
837 di->un.v.delta = 1;
838 di->un.v.num_channels = 2;
839 strcpy(di->un.v.units.name, AudioNvolume);
840 di->type = AUDIO_MIXER_VALUE;
841 di->next = di->prev = AUDIO_MIXER_LAST;
842 return 0;
843
844 default:
845 return ENXIO;
846 }
847 }
848
849 static const struct audio_hw_if dwhdmi_dai_hw_if = {
850 .set_format = dwhdmi_audio_set_format,
851 .set_port = dwhdmi_audio_set_port,
852 .get_port = dwhdmi_audio_get_port,
853 .query_devinfo = dwhdmi_audio_query_devinfo,
854 };
855
856 int
857 dwhdmi_attach(struct dwhdmi_softc *sc)
858 {
859 uint8_t val;
860
861 if (sc->sc_reg_width != 1 && sc->sc_reg_width != 4) {
862 aprint_error_dev(sc->sc_dev, "unsupported register width %d\n", sc->sc_reg_width);
863 return EINVAL;
864 }
865
866 sc->sc_version = dwhdmi_read(sc, HDMI_DESIGN_ID);
867 sc->sc_version <<= 8;
868 sc->sc_version |= dwhdmi_read(sc, HDMI_REVISION_ID);
869
870 sc->sc_phytype = dwhdmi_read(sc, HDMI_CONFIG2_ID);
871
872 aprint_normal_dev(sc->sc_dev, "version %x.%03x, phytype 0x%02x\n",
873 sc->sc_version >> 12, sc->sc_version & 0xfff,
874 sc->sc_phytype);
875
876 sc->sc_swvol = 255;
877
878 /*
879 * If a DDC i2c bus tag is provided by the caller, use it. Otherwise,
880 * use the I2C master built-in to DWC HDMI.
881 */
882 if (sc->sc_ic == NULL) {
883 struct i2c_controller *ic = &sc->sc_ic_builtin;
884 iic_tag_init(ic);
885 ic->ic_cookie = sc;
886 ic->ic_exec = dwhdmi_ddc_exec;
887 sc->sc_ic = ic;
888 }
889
890 /*
891 * Enable HPD on internal PHY
892 */
893 if ((sc->sc_flags & DWHDMI_USE_INTERNAL_PHY) != 0) {
894 val = dwhdmi_read(sc, HDMI_PHY_CONF0);
895 val |= HDMI_PHY_CONF0_ENHPDRXSENSE;
896 dwhdmi_write(sc, HDMI_PHY_CONF0, val);
897 }
898
899 /*
900 * Initialize audio DAI
901 */
902 sc->sc_dai.dai_set_format = dwhdmi_dai_set_format;
903 sc->sc_dai.dai_add_device = dwhdmi_dai_add_device;
904 sc->sc_dai.dai_hw_if = &dwhdmi_dai_hw_if;
905 sc->sc_dai.dai_dev = sc->sc_dev;
906 sc->sc_dai.dai_priv = sc;
907
908 return 0;
909 }
910
911 int
912 dwhdmi_bind(struct dwhdmi_softc *sc, struct drm_encoder *encoder)
913 {
914 int error;
915
916 sc->sc_bridge.driver_private = sc;
917 sc->sc_bridge.funcs = &dwhdmi_bridge_funcs;
918 sc->sc_bridge.encoder = encoder;
919
920 error = drm_bridge_attach(encoder->dev, &sc->sc_bridge);
921 if (error != 0)
922 return EIO;
923
924 encoder->bridge = &sc->sc_bridge;
925
926 return 0;
927 }
928