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