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