Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133128861
D8826.id23036.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
51 KB
Referenced Files
None
Subscribers
None
D8826.id23036.diff
View Options
Index: sys/arm/allwinner/files.allwinner
===================================================================
--- sys/arm/allwinner/files.allwinner
+++ sys/arm/allwinner/files.allwinner
@@ -35,7 +35,7 @@
arm/allwinner/a10_fb.c optional vt
arm/allwinner/a10_hdmi.c optional hdmi
arm/allwinner/a10_hdmiaudio.c optional hdmi sound
-arm/arm/hdmi_if.m optional hdmi
+dev/hdmi/hdmi_if.m optional hdmi
arm/allwinner/aw_reset.c standard
arm/allwinner/aw_ccu.c standard
Index: sys/arm/freescale/imx/files.imx6
===================================================================
--- sys/arm/freescale/imx/files.imx6
+++ sys/arm/freescale/imx/files.imx6
@@ -24,7 +24,8 @@
arm/freescale/imx/imx6_audmux.c optional sound
arm/freescale/imx/imx6_ssi.c optional sound
-arm/arm/hdmi_if.m optional hdmi
+dev/hdmi/hdmi_if.m optional hdmi
+dev/hdmi/dwc_hdmi.c optional hdmi
arm/freescale/imx/imx6_hdmi.c optional hdmi
arm/freescale/imx/imx6_ipu.c optional vt
Index: sys/arm/freescale/imx/imx6_hdmi.c
===================================================================
--- sys/arm/freescale/imx/imx6_hdmi.c
+++ sys/arm/freescale/imx/imx6_hdmi.c
@@ -44,30 +44,18 @@
#include <machine/bus.h>
#include <dev/videomode/videomode.h>
-#include <dev/videomode/edidvar.h>
-
-#include <dev/iicbus/iicbus.h>
-#include <dev/iicbus/iiconf.h>
#include <arm/freescale/imx/imx_ccmvar.h>
#include <arm/freescale/imx/imx_iomuxvar.h>
#include <arm/freescale/imx/imx_iomuxreg.h>
-#include <arm/freescale/imx/imx6_hdmireg.h>
-#include "hdmi_if.h"
+#include <dev/hdmi/dwc_hdmi.h>
-#define I2C_DDC_ADDR (0x50 << 1)
-#define EDID_LENGTH 0x80
+#include "hdmi_if.h"
struct imx_hdmi_softc {
- device_t sc_dev;
- struct resource *sc_mem_res;
- int sc_mem_rid;
- struct intr_config_hook sc_mode_hook;
- struct videomode sc_mode;
- uint8_t *sc_edid;
- uint8_t sc_edid_len;
- phandle_t sc_i2c_xref;
+ struct dwc_hdmi_softc base;
+ phandle_t i2c_xref;
};
static struct ofw_compat_data compat_data[] = {
@@ -76,565 +64,17 @@
{NULL, 0}
};
-static inline uint8_t
-RD1(struct imx_hdmi_softc *sc, bus_size_t off)
-{
-
- return (bus_read_1(sc->sc_mem_res, off));
-}
-
-static inline void
-WR1(struct imx_hdmi_softc *sc, bus_size_t off, uint8_t val)
-{
-
- bus_write_1(sc->sc_mem_res, off, val);
-}
-
-static void
-imx_hdmi_phy_wait_i2c_done(struct imx_hdmi_softc *sc, int msec)
-{
- uint8_t val;
-
- val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) &
- (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
- while (val == 0) {
- pause("HDMI_PHY", hz/100);
- msec -= 10;
- if (msec <= 0)
- return;
- val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) &
- (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
- }
-}
-
-static void
-imx_hdmi_phy_i2c_write(struct imx_hdmi_softc *sc, unsigned short data,
- unsigned char addr)
-{
-
- /* clear DONE and ERROR flags */
- WR1(sc, HDMI_IH_I2CMPHY_STAT0,
- HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
- WR1(sc, HDMI_PHY_I2CM_ADDRESS_ADDR, addr);
- WR1(sc, HDMI_PHY_I2CM_DATAO_1_ADDR, ((data >> 8) & 0xff));
- WR1(sc, HDMI_PHY_I2CM_DATAO_0_ADDR, ((data >> 0) & 0xff));
- WR1(sc, HDMI_PHY_I2CM_OPERATION_ADDR, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE);
- imx_hdmi_phy_wait_i2c_done(sc, 1000);
-}
-
-static void
-imx_hdmi_disable_overflow_interrupts(struct imx_hdmi_softc *sc)
-{
- WR1(sc, HDMI_IH_MUTE_FC_STAT2, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK);
- WR1(sc, HDMI_FC_MASK2,
- HDMI_FC_MASK2_LOW_PRI | HDMI_FC_MASK2_HIGH_PRI);
-}
-
-static void
-imx_hdmi_av_composer(struct imx_hdmi_softc *sc)
-{
- uint8_t inv_val;
- int is_dvi;
- int hblank, vblank, hsync_len, hbp, vbp;
-
- /* Set up HDMI_FC_INVIDCONF */
- inv_val = ((sc->sc_mode.flags & VID_NVSYNC) ?
- HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW :
- HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH);
-
- inv_val |= ((sc->sc_mode.flags & VID_NHSYNC) ?
- HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW :
- HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH);
-
- inv_val |= HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH;
-
- inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ?
- HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
- HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
-
- inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ?
- HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
- HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
-
- /* TODO: implement HDMI part */
- is_dvi = 1;
- inv_val |= (is_dvi ?
- HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
- HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
-
- WR1(sc, HDMI_FC_INVIDCONF, inv_val);
-
- /* Set up horizontal active pixel region width */
- WR1(sc, HDMI_FC_INHACTV1, sc->sc_mode.hdisplay >> 8);
- WR1(sc, HDMI_FC_INHACTV0, sc->sc_mode.hdisplay);
-
- /* Set up vertical blanking pixel region width */
- WR1(sc, HDMI_FC_INVACTV1, sc->sc_mode.vdisplay >> 8);
- WR1(sc, HDMI_FC_INVACTV0, sc->sc_mode.vdisplay);
-
- /* Set up horizontal blanking pixel region width */
- hblank = sc->sc_mode.htotal - sc->sc_mode.hdisplay;
- WR1(sc, HDMI_FC_INHBLANK1, hblank >> 8);
- WR1(sc, HDMI_FC_INHBLANK0, hblank);
-
- /* Set up vertical blanking pixel region width */
- vblank = sc->sc_mode.vtotal - sc->sc_mode.vdisplay;
- WR1(sc, HDMI_FC_INVBLANK, vblank);
-
- /* Set up HSYNC active edge delay width (in pixel clks) */
- hbp = sc->sc_mode.htotal - sc->sc_mode.hsync_end;
- WR1(sc, HDMI_FC_HSYNCINDELAY1, hbp >> 8);
- WR1(sc, HDMI_FC_HSYNCINDELAY0, hbp);
-
- /* Set up VSYNC active edge delay (in pixel clks) */
- vbp = sc->sc_mode.vtotal - sc->sc_mode.vsync_end;
- WR1(sc, HDMI_FC_VSYNCINDELAY, vbp);
-
- hsync_len = (sc->sc_mode.hsync_end - sc->sc_mode.hsync_start);
- /* Set up HSYNC active pulse width (in pixel clks) */
- WR1(sc, HDMI_FC_HSYNCINWIDTH1, hsync_len >> 8);
- WR1(sc, HDMI_FC_HSYNCINWIDTH0, hsync_len);
-
- /* Set up VSYNC active edge delay (in pixel clks) */
- WR1(sc, HDMI_FC_VSYNCINWIDTH, (sc->sc_mode.vsync_end - sc->sc_mode.vsync_start));
-}
-
-static void
-imx_hdmi_phy_enable_power(struct imx_hdmi_softc *sc, uint8_t enable)
-{
- uint8_t reg;
-
- reg = RD1(sc, HDMI_PHY_CONF0);
- reg &= ~HDMI_PHY_CONF0_PDZ_MASK;
- reg |= (enable << HDMI_PHY_CONF0_PDZ_OFFSET);
- WR1(sc, HDMI_PHY_CONF0, reg);
-}
-
-static void
-imx_hdmi_phy_enable_tmds(struct imx_hdmi_softc *sc, uint8_t enable)
-{
- uint8_t reg;
-
- reg = RD1(sc, HDMI_PHY_CONF0);
- reg &= ~HDMI_PHY_CONF0_ENTMDS_MASK;
- reg |= (enable << HDMI_PHY_CONF0_ENTMDS_OFFSET);
- WR1(sc, HDMI_PHY_CONF0, reg);
-}
-
-static void
-imx_hdmi_phy_gen2_pddq(struct imx_hdmi_softc *sc, uint8_t enable)
-{
- uint8_t reg;
-
- reg = RD1(sc, HDMI_PHY_CONF0);
- reg &= ~HDMI_PHY_CONF0_GEN2_PDDQ_MASK;
- reg |= (enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET);
- WR1(sc, HDMI_PHY_CONF0, reg);
-}
-
-static void
-imx_hdmi_phy_gen2_txpwron(struct imx_hdmi_softc *sc, uint8_t enable)
-{
- uint8_t reg;
-
- reg = RD1(sc, HDMI_PHY_CONF0);
- reg &= ~HDMI_PHY_CONF0_GEN2_TXPWRON_MASK;
- reg |= (enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET);
- WR1(sc, HDMI_PHY_CONF0, reg);
-}
-
-static void
-imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi_softc *sc, uint8_t enable)
-{
- uint8_t reg;
-
- reg = RD1(sc, HDMI_PHY_CONF0);
- reg &= ~HDMI_PHY_CONF0_SELDATAENPOL_MASK;
- reg |= (enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET);
- WR1(sc, HDMI_PHY_CONF0, reg);
-}
-
-static void
-imx_hdmi_phy_sel_interface_control(struct imx_hdmi_softc *sc, uint8_t enable)
-{
- uint8_t reg;
-
- reg = RD1(sc, HDMI_PHY_CONF0);
- reg &= ~HDMI_PHY_CONF0_SELDIPIF_MASK;
- reg |= (enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET);
- WR1(sc, HDMI_PHY_CONF0, reg);
-}
-
-static inline void
-imx_hdmi_phy_test_clear(struct imx_hdmi_softc *sc, unsigned char bit)
-{
- uint8_t val;
-
- val = RD1(sc, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
- HDMI_PHY_TST0_TSTCLR_MASK;
- WR1(sc, HDMI_PHY_TST0, val);
-}
-
-static void
-imx_hdmi_clear_overflow(struct imx_hdmi_softc *sc)
-{
- int count;
- uint8_t val;
-
- /* TMDS software reset */
- WR1(sc, HDMI_MC_SWRSTZ, (uint8_t)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ);
-
- val = RD1(sc, HDMI_FC_INVIDCONF);
-
- for (count = 0 ; count < 5 ; count++)
- WR1(sc, HDMI_FC_INVIDCONF, val);
-}
-
-static int
-imx_hdmi_phy_configure(struct imx_hdmi_softc *sc)
+static device_t
+imx_hdmi_get_i2c_dev(device_t dev)
{
- uint8_t val;
- uint8_t msec;
-
- WR1(sc, HDMI_MC_FLOWCTRL, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS);
-
- /* gen2 tx power off */
- imx_hdmi_phy_gen2_txpwron(sc, 0);
-
- /* gen2 pddq */
- imx_hdmi_phy_gen2_pddq(sc, 1);
-
- /* PHY reset */
- WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_DEASSERT);
- WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_ASSERT);
-
- WR1(sc, HDMI_MC_HEACPHY_RST, HDMI_MC_HEACPHY_RST_ASSERT);
-
- imx_hdmi_phy_test_clear(sc, 1);
- WR1(sc, HDMI_PHY_I2CM_SLAVE_ADDR, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2);
- imx_hdmi_phy_test_clear(sc, 0);
-
- /*
- * Following initialization are for 8bit per color case
- */
-
- /*
- * PLL/MPLL config, see section 24.7.22 in TRM
- * config, see section 24.7.22
- */
- if (sc->sc_mode.dot_clock*1000 <= 45250000) {
- imx_hdmi_phy_i2c_write(sc, CPCE_CTRL_45_25, HDMI_PHY_I2C_CPCE_CTRL);
- imx_hdmi_phy_i2c_write(sc, GMPCTRL_45_25, HDMI_PHY_I2C_GMPCTRL);
- } else if (sc->sc_mode.dot_clock*1000 <= 92500000) {
- imx_hdmi_phy_i2c_write(sc, CPCE_CTRL_92_50, HDMI_PHY_I2C_CPCE_CTRL);
- imx_hdmi_phy_i2c_write(sc, GMPCTRL_92_50, HDMI_PHY_I2C_GMPCTRL);
- } else if (sc->sc_mode.dot_clock*1000 <= 185000000) {
- imx_hdmi_phy_i2c_write(sc, CPCE_CTRL_185, HDMI_PHY_I2C_CPCE_CTRL);
- imx_hdmi_phy_i2c_write(sc, GMPCTRL_185, HDMI_PHY_I2C_GMPCTRL);
- } else {
- imx_hdmi_phy_i2c_write(sc, CPCE_CTRL_370, HDMI_PHY_I2C_CPCE_CTRL);
- imx_hdmi_phy_i2c_write(sc, GMPCTRL_370, HDMI_PHY_I2C_GMPCTRL);
- }
-
- /*
- * Values described in TRM section 34.9.2 PLL/MPLL Generic
- * Configuration Settings. Table 34-23.
- */
- if (sc->sc_mode.dot_clock*1000 <= 54000000) {
- imx_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
- } else if (sc->sc_mode.dot_clock*1000 <= 58400000) {
- imx_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
- } else if (sc->sc_mode.dot_clock*1000 <= 72000000) {
- imx_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
- } else if (sc->sc_mode.dot_clock*1000 <= 74250000) {
- imx_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
- } else if (sc->sc_mode.dot_clock*1000 <= 118800000) {
- imx_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
- } else if (sc->sc_mode.dot_clock*1000 <= 216000000) {
- imx_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
- } else {
- panic("Unsupported mode\n");
- }
-
- imx_hdmi_phy_i2c_write(sc, 0x0000, HDMI_PHY_I2C_PLLPHBYCTRL);
- imx_hdmi_phy_i2c_write(sc, MSM_CTRL_FB_CLK, HDMI_PHY_I2C_MSM_CTRL);
- /* RESISTANCE TERM 133 Ohm */
- imx_hdmi_phy_i2c_write(sc, TXTERM_133, HDMI_PHY_I2C_TXTERM);
-
- /* REMOVE CLK TERM */
- imx_hdmi_phy_i2c_write(sc, CKCALCTRL_OVERRIDE, HDMI_PHY_I2C_CKCALCTRL);
-
- if (sc->sc_mode.dot_clock*1000 > 148500000) {
- imx_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON |
- CKSYMTXCTRL_TX_TRBON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL);
- imx_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(9) | VLEVCTRL_CK_LVL(9),
- HDMI_PHY_I2C_VLEVCTRL);
- } else {
- imx_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON |
- CKSYMTXCTRL_TX_TRAON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL);
- imx_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(13) | VLEVCTRL_CK_LVL(13),
- HDMI_PHY_I2C_VLEVCTRL);
- }
-
- imx_hdmi_phy_enable_power(sc, 1);
-
- /* toggle TMDS enable */
- imx_hdmi_phy_enable_tmds(sc, 0);
- imx_hdmi_phy_enable_tmds(sc, 1);
-
- /* gen2 tx power on */
- imx_hdmi_phy_gen2_txpwron(sc, 1);
- imx_hdmi_phy_gen2_pddq(sc, 0);
-
- /*Wait for PHY PLL lock */
- msec = 4;
- val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
- while (val == 0) {
- DELAY(1000);
- if (msec-- == 0) {
- device_printf(sc->sc_dev, "PHY PLL not locked\n");
- return (-1);
- }
- val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
- }
-
- return true;
-}
-
-static void
-imx_hdmi_phy_init(struct imx_hdmi_softc *sc)
-{
- int i;
-
- /* HDMI Phy spec says to do the phy initialization sequence twice */
- for (i = 0 ; i < 2 ; i++) {
- imx_hdmi_phy_sel_data_en_pol(sc, 1);
- imx_hdmi_phy_sel_interface_control(sc, 0);
- imx_hdmi_phy_enable_tmds(sc, 0);
- imx_hdmi_phy_enable_power(sc, 0);
-
- /* Enable CSC */
- imx_hdmi_phy_configure(sc);
- }
-}
-
-static void
-imx_hdmi_enable_video_path(struct imx_hdmi_softc *sc)
-{
- uint8_t clkdis;
-
- /*
- * Control period timing
- * Values are minimal according to HDMI spec 1.4a
- */
- WR1(sc, HDMI_FC_CTRLDUR, 12);
- WR1(sc, HDMI_FC_EXCTRLDUR, 32);
- WR1(sc, HDMI_FC_EXCTRLSPAC, 1);
-
- /*
- * Bits to fill data lines not used to transmit preamble
- * for channels 0, 1, and 2 respectively
- */
- WR1(sc, HDMI_FC_CH0PREAM, 0x0B);
- WR1(sc, HDMI_FC_CH1PREAM, 0x16);
- WR1(sc, HDMI_FC_CH2PREAM, 0x21);
-
- /* Save CEC clock */
- clkdis = RD1(sc, HDMI_MC_CLKDIS) & HDMI_MC_CLKDIS_CECCLK_DISABLE;
- clkdis |= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
-
- /* Enable pixel clock and tmds data path */
- clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- WR1(sc, HDMI_MC_CLKDIS, clkdis);
-
- clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- WR1(sc, HDMI_MC_CLKDIS, clkdis);
-}
-
-static void
-imx_hdmi_video_packetize(struct imx_hdmi_softc *sc)
-{
- unsigned int color_depth = 0;
- unsigned int remap_size = HDMI_VP_REMAP_YCC422_16BIT;
- unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
- uint8_t val;
-
- output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- color_depth = 0;
-
- /* set the packetizer registers */
- val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
- HDMI_VP_PR_CD_COLOR_DEPTH_MASK);
- WR1(sc, HDMI_VP_PR_CD, val);
-
- val = RD1(sc, HDMI_VP_STUFF);
- val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
- val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
- WR1(sc, HDMI_VP_STUFF, val);
-
- val = RD1(sc, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK);
- val |= HDMI_VP_CONF_PR_EN_DISABLE |
- HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
- WR1(sc, HDMI_VP_CONF, val);
-
- val = RD1(sc, HDMI_VP_STUFF);
- val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
- val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
- WR1(sc, HDMI_VP_STUFF, val);
-
- WR1(sc, HDMI_VP_REMAP, remap_size);
-
- if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
- val = RD1(sc, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_ENABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- WR1(sc, HDMI_VP_CONF, val);
- } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
- val = RD1(sc, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_ENABLE;
- WR1(sc, HDMI_VP_CONF, val);
- } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
- val = RD1(sc, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- WR1(sc, HDMI_VP_CONF, val);
- } else {
- return;
- }
-
- val = RD1(sc, HDMI_VP_STUFF);
- val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
- HDMI_VP_STUFF_YCC422_STUFFING_MASK);
- val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
- HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
- WR1(sc, HDMI_VP_STUFF, val);
-
- val = RD1(sc, HDMI_VP_CONF);
- val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
- val |= output_select;
- WR1(sc, HDMI_VP_CONF, val);
-}
-
-static void
-imx_hdmi_video_sample(struct imx_hdmi_softc *sc)
-{
- int color_format;
- uint8_t val;
-
- color_format = 0x01;
- val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
- ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
- HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
- WR1(sc, HDMI_TX_INVID0, val);
-
- /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
- val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
- HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
- HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
- WR1(sc, HDMI_TX_INSTUFFING, val);
- WR1(sc, HDMI_TX_GYDATA0, 0x0);
- WR1(sc, HDMI_TX_GYDATA1, 0x0);
- WR1(sc, HDMI_TX_RCRDATA0, 0x0);
- WR1(sc, HDMI_TX_RCRDATA1, 0x0);
- WR1(sc, HDMI_TX_BCBDATA0, 0x0);
- WR1(sc, HDMI_TX_BCBDATA1, 0x0);
-}
-
-static int
-imx_hdmi_set_mode(struct imx_hdmi_softc *sc)
-{
-
- imx_hdmi_disable_overflow_interrupts(sc);
- imx_hdmi_av_composer(sc);
- imx_hdmi_phy_init(sc);
- imx_hdmi_enable_video_path(sc);
- /* TODO: AVI infoframes */
- imx_hdmi_video_packetize(sc);
- /* TODO: imx_hdmi_video_csc(sc); */
- imx_hdmi_video_sample(sc);
- imx_hdmi_clear_overflow(sc);
-
- return (0);
-}
-
-static int
-hdmi_edid_read(struct imx_hdmi_softc *sc, uint8_t **edid, uint32_t *edid_len)
-{
- device_t i2c_dev;
- int result;
- uint8_t addr = 0;
- struct iic_msg msg[] = {
- { 0, IIC_M_WR, 1, &addr },
- { 0, IIC_M_RD, EDID_LENGTH, NULL}
- };
-
- *edid = NULL;
- *edid_len = 0;
-
- if (sc->sc_i2c_xref == 0)
- return (ENXIO);
-
- i2c_dev = OF_device_from_xref(sc->sc_i2c_xref);
- if (!i2c_dev) {
- device_printf(sc->sc_dev,
- "no actual device for \"ddc-i2c-bus\" property (handle=%x)\n", sc->sc_i2c_xref);
- return (ENXIO);
- }
-
- device_printf(sc->sc_dev, "reading EDID from %s, addr %02x\n",
- device_get_nameunit(i2c_dev), I2C_DDC_ADDR/2);
-
- msg[0].slave = I2C_DDC_ADDR;
- msg[1].slave = I2C_DDC_ADDR;
- msg[1].buf = sc->sc_edid;
-
- result = iicbus_request_bus(i2c_dev, sc->sc_dev, IIC_INTRWAIT);
+ struct imx_hdmi_softc *sc;
- if (result) {
- device_printf(sc->sc_dev, "failed to request i2c bus: %d\n", result);
- return (result);
- }
+ sc = device_get_softc(dev);
- result = iicbus_transfer(i2c_dev, msg, 2);
- iicbus_release_bus(i2c_dev, sc->sc_dev);
+ if (sc->i2c_xref == 0)
+ return (NULL);
- if (result) {
- device_printf(sc->sc_dev, "i2c transfer failed: %d\n", result);
- return (result);
- } else {
- *edid_len = sc->sc_edid_len;
- *edid = sc->sc_edid;
- }
-
- return (result);
-}
-
-static void
-imx_hdmi_detect_cable(void *arg)
-{
- struct imx_hdmi_softc *sc;
-
- sc = arg;
- EVENTHANDLER_INVOKE(hdmi_event, sc->sc_dev, HDMI_EVENT_CONNECTED);
- /* Finished with the interrupt hook */
- config_intrhook_disestablish(&sc->sc_mode_hook);
+ return (OF_device_from_xref(sc->i2c_xref));
}
static int
@@ -644,9 +84,9 @@
sc = device_get_softc(dev);
- if (sc->sc_mem_res != NULL)
+ if (sc->base.sc_mem_res != NULL)
bus_release_resource(dev, SYS_RES_MEMORY,
- sc->sc_mem_rid, sc->sc_mem_res);
+ sc->base.sc_mem_rid, sc->base.sc_mem_res);
return (0);
}
@@ -660,51 +100,32 @@
phandle_t node, i2c_xref;
sc = device_get_softc(dev);
- sc->sc_dev = dev;
+ sc->base.sc_dev = dev;
err = 0;
/* Allocate memory resources. */
- sc->sc_mem_rid = 0;
- sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mem_rid,
- RF_ACTIVE);
- if (sc->sc_mem_res == NULL) {
+ sc->base.sc_mem_rid = 0;
+ sc->base.sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->base.sc_mem_rid, RF_ACTIVE);
+ if (sc->base.sc_mem_res == NULL) {
device_printf(dev, "Cannot allocate memory resources\n");
err = ENXIO;
goto out;
}
- sc->sc_mode_hook.ich_func = imx_hdmi_detect_cable;
- sc->sc_mode_hook.ich_arg = sc;
-
- if (config_intrhook_establish(&sc->sc_mode_hook) != 0) {
- err = ENOMEM;
- goto out;
- }
-
node = ofw_bus_get_node(dev);
if (OF_getencprop(node, "ddc-i2c-bus", &i2c_xref, sizeof(i2c_xref)) == -1)
- sc->sc_i2c_xref = 0;
+ sc->i2c_xref = 0;
else
- sc->sc_i2c_xref = i2c_xref;
-
- sc->sc_edid = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO);
- sc->sc_edid_len = EDID_LENGTH;
+ sc->i2c_xref = i2c_xref;
imx_ccm_hdmi_enable();
- device_printf(sc->sc_dev, "HDMI controller %02x:%02x:%02x:%02x\n",
- RD1(sc, HDMI_DESIGN_ID), RD1(sc, HDMI_REVISION_ID),
- RD1(sc, HDMI_PRODUCT_ID0), RD1(sc, HDMI_PRODUCT_ID1));
-
-
gpr3 = imx_iomux_gpr_get(IOMUXC_GPR3);
gpr3 &= ~(IOMUXC_GPR3_HDMI_MASK);
gpr3 |= IOMUXC_GPR3_HDMI_IPU1_DI0;
imx_iomux_gpr_set(IOMUXC_GPR3, gpr3);
- WR1(sc, HDMI_PHY_POL0, HDMI_PHY_HPD);
- WR1(sc, HDMI_IH_PHY_STAT0, HDMI_IH_PHY_STAT0_HPD);
-
out:
if (err != 0)
@@ -725,25 +146,6 @@
return (BUS_PROBE_DEFAULT);
}
-static int
-imx_hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len)
-{
-
- return (hdmi_edid_read(device_get_softc(dev), edid, edid_len));
-}
-
-static int
-imx_hdmi_set_videomode(device_t dev, const struct videomode *mode)
-{
- struct imx_hdmi_softc *sc;
-
- sc = device_get_softc(dev);
- memcpy(&sc->sc_mode, mode, sizeof(*mode));
- imx_hdmi_set_mode(sc);
-
- return (0);
-}
-
static device_method_t imx_hdmi_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, imx_hdmi_probe),
@@ -751,8 +153,8 @@
DEVMETHOD(device_detach, imx_hdmi_detach),
/* HDMI methods */
- DEVMETHOD(hdmi_get_edid, imx_hdmi_get_edid),
- DEVMETHOD(hdmi_set_videomode, imx_hdmi_set_videomode),
+ DEVMETHOD(hdmi_get_edid, dwc_hdmi_get_edid),
+ DEVMETHOD(hdmi_set_videomode, dwc_hdmi_set_videomode),
DEVMETHOD_END
};
Index: sys/conf/files.arm
===================================================================
--- sys/conf/files.arm
+++ sys/conf/files.arm
@@ -60,7 +60,6 @@
arm/arm/generic_timer.c optional generic_timer
arm/arm/gic.c optional gic
arm/arm/gic_fdt.c optional gic fdt
-arm/arm/hdmi_if.m optional hdmi
arm/arm/identcpu-v4.c optional !armv6
arm/arm/identcpu-v6.c optional armv6
arm/arm/in_cksum.c optional inet | inet6
@@ -120,6 +119,7 @@
dev/dwc/if_dwc_if.m optional dwc
dev/fb/fb.c optional sc
dev/fdt/fdt_arm_platform.c optional platform fdt
+dev/hdmi/hdmi_if.m optional hdmi
dev/hwpmc/hwpmc_arm.c optional hwpmc
dev/hwpmc/hwpmc_armv7.c optional hwpmc armv6
dev/iicbus/twsi/twsi.c optional twsi
Index: sys/dev/hdmi/dwc_hdmi.h
===================================================================
--- /dev/null
+++ sys/dev/hdmi/dwc_hdmi.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __DWC_HDMI_H__
+#define __DWC_HDMI_H__
+
+struct dwc_hdmi_softc {
+ device_t sc_dev;
+ struct resource *sc_mem_res;
+ int sc_mem_rid;
+ uint32_t sc_reg_shift;
+ device_t (*sc_get_i2c_dev)(device_t);
+
+ uint8_t *sc_edid;
+ uint8_t sc_edid_len;
+ struct intr_config_hook sc_mode_hook;
+ struct videomode sc_mode;
+};
+
+static inline uint8_t
+RD1(struct dwc_hdmi_softc *sc, bus_size_t off)
+{
+ return (bus_read_1(sc->sc_mem_res, off << sc->sc_reg_shift));
+}
+
+static inline void
+WR1(struct dwc_hdmi_softc *sc, bus_size_t off, uint8_t val)
+{
+ bus_write_1(sc->sc_mem_res, off << sc->sc_reg_shift, val);
+}
+
+int dwc_hdmi_get_edid(device_t, uint8_t **, uint32_t *);
+int dwc_hdmi_set_videomode(device_t, const struct videomode *);
+int dwc_hdmi_init(device_t);
+
+#endif /* __DWC_HDMI_H__ */
Index: sys/dev/hdmi/dwc_hdmi.c
===================================================================
--- /dev/null
+++ sys/dev/hdmi/dwc_hdmi.c
@@ -0,0 +1,691 @@
+/*-
+ * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * HDMI core module
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/edidvar.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/hdmi/dwc_hdmi.h>
+#include <dev/hdmi/dwc_hdmireg.h>
+
+#include "hdmi_if.h"
+
+#define I2C_DDC_ADDR (0x50 << 1)
+#define EDID_LENGTH 0x80
+
+static void
+dwc_hdmi_phy_wait_i2c_done(struct dwc_hdmi_softc *sc, int msec)
+{
+ uint8_t val;
+
+ val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) &
+ (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
+ while (val == 0) {
+ pause("HDMI_PHY", hz/100);
+ msec -= 10;
+ if (msec <= 0)
+ return;
+ val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) &
+ (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
+ }
+}
+
+static void
+dwc_hdmi_phy_i2c_write(struct dwc_hdmi_softc *sc, unsigned short data,
+ unsigned char addr)
+{
+
+ /* clear DONE and ERROR flags */
+ WR1(sc, HDMI_IH_I2CMPHY_STAT0,
+ HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
+ WR1(sc, HDMI_PHY_I2CM_ADDRESS_ADDR, addr);
+ WR1(sc, HDMI_PHY_I2CM_DATAO_1_ADDR, ((data >> 8) & 0xff));
+ WR1(sc, HDMI_PHY_I2CM_DATAO_0_ADDR, ((data >> 0) & 0xff));
+ WR1(sc, HDMI_PHY_I2CM_OPERATION_ADDR, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE);
+ dwc_hdmi_phy_wait_i2c_done(sc, 1000);
+}
+
+static void
+dwc_hdmi_disable_overflow_interrupts(struct dwc_hdmi_softc *sc)
+{
+ WR1(sc, HDMI_IH_MUTE_FC_STAT2, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK);
+ WR1(sc, HDMI_FC_MASK2,
+ HDMI_FC_MASK2_LOW_PRI | HDMI_FC_MASK2_HIGH_PRI);
+}
+
+static void
+dwc_hdmi_av_composer(struct dwc_hdmi_softc *sc)
+{
+ uint8_t inv_val;
+ int is_dvi;
+ int hblank, vblank, hsync_len, hfp, vfp;
+
+ /* Set up HDMI_FC_INVIDCONF */
+ inv_val = ((sc->sc_mode.flags & VID_PVSYNC) ?
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
+
+ inv_val |= ((sc->sc_mode.flags & VID_PHSYNC) ?
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
+
+ inv_val |= HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH;
+
+ inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ?
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
+
+ inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ?
+ HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
+ HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
+
+ /* TODO: implement HDMI part */
+ is_dvi = 1;
+ inv_val |= (is_dvi ?
+ HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
+ HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
+
+ WR1(sc, HDMI_FC_INVIDCONF, inv_val);
+
+ /* Set up horizontal active pixel region width */
+ WR1(sc, HDMI_FC_INHACTV1, sc->sc_mode.hdisplay >> 8);
+ WR1(sc, HDMI_FC_INHACTV0, sc->sc_mode.hdisplay);
+
+ /* Set up vertical blanking pixel region width */
+ WR1(sc, HDMI_FC_INVACTV1, sc->sc_mode.vdisplay >> 8);
+ WR1(sc, HDMI_FC_INVACTV0, sc->sc_mode.vdisplay);
+
+ /* Set up horizontal blanking pixel region width */
+ hblank = sc->sc_mode.htotal - sc->sc_mode.hdisplay;
+ WR1(sc, HDMI_FC_INHBLANK1, hblank >> 8);
+ WR1(sc, HDMI_FC_INHBLANK0, hblank);
+
+ /* Set up vertical blanking pixel region width */
+ vblank = sc->sc_mode.vtotal - sc->sc_mode.vdisplay;
+ WR1(sc, HDMI_FC_INVBLANK, vblank);
+
+ /* Set up HSYNC active edge delay width (in pixel clks) */
+ hfp = sc->sc_mode.hsync_start - sc->sc_mode.hdisplay;
+ WR1(sc, HDMI_FC_HSYNCINDELAY1, hfp >> 8);
+ WR1(sc, HDMI_FC_HSYNCINDELAY0, hfp);
+
+ /* Set up VSYNC active edge delay (in pixel clks) */
+ vfp = sc->sc_mode.vsync_start - sc->sc_mode.vdisplay;
+ WR1(sc, HDMI_FC_VSYNCINDELAY, vfp);
+
+ hsync_len = (sc->sc_mode.hsync_end - sc->sc_mode.hsync_start);
+ /* Set up HSYNC active pulse width (in pixel clks) */
+ WR1(sc, HDMI_FC_HSYNCINWIDTH1, hsync_len >> 8);
+ WR1(sc, HDMI_FC_HSYNCINWIDTH0, hsync_len);
+
+ /* Set up VSYNC active edge delay (in pixel clks) */
+ WR1(sc, HDMI_FC_VSYNCINWIDTH, (sc->sc_mode.vsync_end - sc->sc_mode.vsync_start));
+}
+
+static void
+dwc_hdmi_phy_enable_power(struct dwc_hdmi_softc *sc, uint8_t enable)
+{
+ uint8_t reg;
+
+ reg = RD1(sc, HDMI_PHY_CONF0);
+ reg &= ~HDMI_PHY_CONF0_PDZ_MASK;
+ reg |= (enable << HDMI_PHY_CONF0_PDZ_OFFSET);
+ WR1(sc, HDMI_PHY_CONF0, reg);
+}
+
+static void
+dwc_hdmi_phy_enable_tmds(struct dwc_hdmi_softc *sc, uint8_t enable)
+{
+ uint8_t reg;
+
+ reg = RD1(sc, HDMI_PHY_CONF0);
+ reg &= ~HDMI_PHY_CONF0_ENTMDS_MASK;
+ reg |= (enable << HDMI_PHY_CONF0_ENTMDS_OFFSET);
+ WR1(sc, HDMI_PHY_CONF0, reg);
+}
+
+static void
+dwc_hdmi_phy_gen2_pddq(struct dwc_hdmi_softc *sc, uint8_t enable)
+{
+ uint8_t reg;
+
+ reg = RD1(sc, HDMI_PHY_CONF0);
+ reg &= ~HDMI_PHY_CONF0_GEN2_PDDQ_MASK;
+ reg |= (enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET);
+ WR1(sc, HDMI_PHY_CONF0, reg);
+}
+
+static void
+dwc_hdmi_phy_gen2_txpwron(struct dwc_hdmi_softc *sc, uint8_t enable)
+{
+ uint8_t reg;
+
+ reg = RD1(sc, HDMI_PHY_CONF0);
+ reg &= ~HDMI_PHY_CONF0_GEN2_TXPWRON_MASK;
+ reg |= (enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET);
+ WR1(sc, HDMI_PHY_CONF0, reg);
+}
+
+static void
+dwc_hdmi_phy_sel_data_en_pol(struct dwc_hdmi_softc *sc, uint8_t enable)
+{
+ uint8_t reg;
+
+ reg = RD1(sc, HDMI_PHY_CONF0);
+ reg &= ~HDMI_PHY_CONF0_SELDATAENPOL_MASK;
+ reg |= (enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET);
+ WR1(sc, HDMI_PHY_CONF0, reg);
+}
+
+static void
+dwc_hdmi_phy_sel_interface_control(struct dwc_hdmi_softc *sc, uint8_t enable)
+{
+ uint8_t reg;
+
+ reg = RD1(sc, HDMI_PHY_CONF0);
+ reg &= ~HDMI_PHY_CONF0_SELDIPIF_MASK;
+ reg |= (enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET);
+ WR1(sc, HDMI_PHY_CONF0, reg);
+}
+
+static inline void
+dwc_hdmi_phy_test_clear(struct dwc_hdmi_softc *sc, unsigned char bit)
+{
+ uint8_t val;
+
+ val = RD1(sc, HDMI_PHY_TST0);
+ val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
+ val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
+ HDMI_PHY_TST0_TSTCLR_MASK;
+ WR1(sc, HDMI_PHY_TST0, val);
+}
+
+static void
+dwc_hdmi_clear_overflow(struct dwc_hdmi_softc *sc)
+{
+ int count;
+ uint8_t val;
+
+ /* TMDS software reset */
+ WR1(sc, HDMI_MC_SWRSTZ, (uint8_t)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ);
+
+ val = RD1(sc, HDMI_FC_INVIDCONF);
+
+ for (count = 0 ; count < 4 ; count++)
+ WR1(sc, HDMI_FC_INVIDCONF, val);
+}
+
+static int
+dwc_hdmi_phy_configure(struct dwc_hdmi_softc *sc)
+{
+ uint8_t val;
+ uint8_t msec;
+
+ WR1(sc, HDMI_MC_FLOWCTRL, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS);
+
+ /* gen2 tx power off */
+ dwc_hdmi_phy_gen2_txpwron(sc, 0);
+
+ /* gen2 pddq */
+ dwc_hdmi_phy_gen2_pddq(sc, 1);
+
+ /* PHY reset */
+ WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_DEASSERT);
+ WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_ASSERT);
+
+ WR1(sc, HDMI_MC_HEACPHY_RST, HDMI_MC_HEACPHY_RST_ASSERT);
+
+ dwc_hdmi_phy_test_clear(sc, 1);
+ WR1(sc, HDMI_PHY_I2CM_SLAVE_ADDR, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2);
+ dwc_hdmi_phy_test_clear(sc, 0);
+
+ /*
+ * Following initialization are for 8bit per color case
+ */
+
+ /*
+ * PLL/MPLL config, see section 24.7.22 in TRM
+ * config, see section 24.7.22
+ */
+ if (sc->sc_mode.dot_clock*1000 <= 45250000) {
+ dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_45_25, HDMI_PHY_I2C_CPCE_CTRL);
+ dwc_hdmi_phy_i2c_write(sc, GMPCTRL_45_25, HDMI_PHY_I2C_GMPCTRL);
+ } else if (sc->sc_mode.dot_clock*1000 <= 92500000) {
+ dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_92_50, HDMI_PHY_I2C_CPCE_CTRL);
+ dwc_hdmi_phy_i2c_write(sc, GMPCTRL_92_50, HDMI_PHY_I2C_GMPCTRL);
+ } else if (sc->sc_mode.dot_clock*1000 <= 185000000) {
+ dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_185, HDMI_PHY_I2C_CPCE_CTRL);
+ dwc_hdmi_phy_i2c_write(sc, GMPCTRL_185, HDMI_PHY_I2C_GMPCTRL);
+ } else {
+ dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_370, HDMI_PHY_I2C_CPCE_CTRL);
+ dwc_hdmi_phy_i2c_write(sc, GMPCTRL_370, HDMI_PHY_I2C_GMPCTRL);
+ }
+
+ /*
+ * Values described in TRM section 34.9.2 PLL/MPLL Generic
+ * Configuration Settings. Table 34-23.
+ */
+ if (sc->sc_mode.dot_clock*1000 <= 54000000) {
+ dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
+ } else if (sc->sc_mode.dot_clock*1000 <= 58400000) {
+ dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
+ } else if (sc->sc_mode.dot_clock*1000 <= 72000000) {
+ dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
+ } else if (sc->sc_mode.dot_clock*1000 <= 74250000) {
+ dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
+ } else if (sc->sc_mode.dot_clock*1000 <= 118800000) {
+ dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
+ } else if (sc->sc_mode.dot_clock*1000 <= 216000000) {
+ dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
+ } else {
+ panic("Unsupported mode\n");
+ }
+
+ dwc_hdmi_phy_i2c_write(sc, 0x0000, HDMI_PHY_I2C_PLLPHBYCTRL);
+ dwc_hdmi_phy_i2c_write(sc, MSM_CTRL_FB_CLK, HDMI_PHY_I2C_MSM_CTRL);
+ /* RESISTANCE TERM 133 Ohm */
+ dwc_hdmi_phy_i2c_write(sc, TXTERM_133, HDMI_PHY_I2C_TXTERM);
+
+ /* REMOVE CLK TERM */
+ dwc_hdmi_phy_i2c_write(sc, CKCALCTRL_OVERRIDE, HDMI_PHY_I2C_CKCALCTRL);
+
+ if (sc->sc_mode.dot_clock*1000 > 148500000) {
+ dwc_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON |
+ CKSYMTXCTRL_TX_TRBON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL);
+ dwc_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(9) | VLEVCTRL_CK_LVL(9),
+ HDMI_PHY_I2C_VLEVCTRL);
+ } else {
+ dwc_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON |
+ CKSYMTXCTRL_TX_TRAON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL);
+ dwc_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(13) | VLEVCTRL_CK_LVL(13),
+ HDMI_PHY_I2C_VLEVCTRL);
+ }
+
+ dwc_hdmi_phy_enable_power(sc, 1);
+
+ /* toggle TMDS enable */
+ dwc_hdmi_phy_enable_tmds(sc, 0);
+ dwc_hdmi_phy_enable_tmds(sc, 1);
+
+ /* gen2 tx power on */
+ dwc_hdmi_phy_gen2_txpwron(sc, 1);
+ dwc_hdmi_phy_gen2_pddq(sc, 0);
+
+ /*Wait for PHY PLL lock */
+ msec = 4;
+ val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+ while (val == 0) {
+ DELAY(1000);
+ if (msec-- == 0) {
+ device_printf(sc->sc_dev, "PHY PLL not locked\n");
+ return (-1);
+ }
+ val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+ }
+
+ return true;
+}
+
+static void
+dwc_hdmi_phy_init(struct dwc_hdmi_softc *sc)
+{
+ int i;
+
+ /* HDMI Phy spec says to do the phy initialization sequence twice */
+ for (i = 0 ; i < 2 ; i++) {
+ dwc_hdmi_phy_sel_data_en_pol(sc, 1);
+ dwc_hdmi_phy_sel_interface_control(sc, 0);
+ dwc_hdmi_phy_enable_tmds(sc, 0);
+ dwc_hdmi_phy_enable_power(sc, 0);
+
+ /* Enable CSC */
+ dwc_hdmi_phy_configure(sc);
+ }
+}
+
+static void
+dwc_hdmi_enable_video_path(struct dwc_hdmi_softc *sc)
+{
+ uint8_t clkdis;
+
+ /*
+ * Control period timing
+ * Values are minimal according to HDMI spec 1.4a
+ */
+ WR1(sc, HDMI_FC_CTRLDUR, 12);
+ WR1(sc, HDMI_FC_EXCTRLDUR, 32);
+ WR1(sc, HDMI_FC_EXCTRLSPAC, 1);
+
+ /*
+ * Bits to fill data lines not used to transmit preamble
+ * for channels 0, 1, and 2 respectively
+ */
+ WR1(sc, HDMI_FC_CH0PREAM, 0x0B);
+ WR1(sc, HDMI_FC_CH1PREAM, 0x16);
+ WR1(sc, HDMI_FC_CH2PREAM, 0x21);
+
+ /* Save CEC clock */
+ clkdis = RD1(sc, HDMI_MC_CLKDIS) & HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ clkdis |= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
+
+ /* Enable pixel clock and tmds data path */
+ clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+ WR1(sc, HDMI_MC_CLKDIS, clkdis);
+
+ clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+ WR1(sc, HDMI_MC_CLKDIS, clkdis);
+}
+
+static void
+dwc_hdmi_video_packetize(struct dwc_hdmi_softc *sc)
+{
+ unsigned int color_depth = 0;
+ unsigned int remap_size = HDMI_VP_REMAP_YCC422_16BIT;
+ unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
+ uint8_t val;
+
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+ color_depth = 4;
+
+ /* set the packetizer registers */
+ val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
+ HDMI_VP_PR_CD_COLOR_DEPTH_MASK);
+ WR1(sc, HDMI_VP_PR_CD, val);
+
+ val = RD1(sc, HDMI_VP_STUFF);
+ val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
+ val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
+ WR1(sc, HDMI_VP_STUFF, val);
+
+ val = RD1(sc, HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK);
+ val |= HDMI_VP_CONF_PR_EN_DISABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
+ WR1(sc, HDMI_VP_CONF, val);
+
+ val = RD1(sc, HDMI_VP_STUFF);
+ val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
+ val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
+ WR1(sc, HDMI_VP_STUFF, val);
+
+ WR1(sc, HDMI_VP_REMAP, remap_size);
+
+ if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
+ val = RD1(sc, HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_ENABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
+ WR1(sc, HDMI_VP_CONF, val);
+ } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
+ val = RD1(sc, HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_ENABLE;
+ WR1(sc, HDMI_VP_CONF, val);
+ } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
+ val = RD1(sc, HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
+ WR1(sc, HDMI_VP_CONF, val);
+ } else {
+ return;
+ }
+
+ val = RD1(sc, HDMI_VP_STUFF);
+ val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
+ HDMI_VP_STUFF_YCC422_STUFFING_MASK);
+ val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+ HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
+ WR1(sc, HDMI_VP_STUFF, val);
+
+ val = RD1(sc, HDMI_VP_CONF);
+ val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
+ val |= output_select;
+ WR1(sc, HDMI_VP_CONF, val);
+}
+
+static void
+dwc_hdmi_video_sample(struct dwc_hdmi_softc *sc)
+{
+ int color_format;
+ uint8_t val;
+
+ color_format = 0x01;
+ val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
+ ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
+ HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
+ WR1(sc, HDMI_TX_INVID0, val);
+
+ /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
+ val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
+ HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
+ HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
+ WR1(sc, HDMI_TX_INSTUFFING, val);
+ WR1(sc, HDMI_TX_GYDATA0, 0x0);
+ WR1(sc, HDMI_TX_GYDATA1, 0x0);
+ WR1(sc, HDMI_TX_RCRDATA0, 0x0);
+ WR1(sc, HDMI_TX_RCRDATA1, 0x0);
+ WR1(sc, HDMI_TX_BCBDATA0, 0x0);
+ WR1(sc, HDMI_TX_BCBDATA1, 0x0);
+}
+
+static void
+dwc_hdmi_tx_hdcp_config(struct dwc_hdmi_softc *sc)
+{
+ uint8_t de, val;
+
+ de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
+
+ /* Disable RX detect */
+ val = RD1(sc, HDMI_A_HDCPCFG0);
+ val &= ~HDMI_A_HDCPCFG0_RXDETECT_MASK;
+ val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
+ WR1(sc, HDMI_A_HDCPCFG0, val);
+
+ /* Set polarity */
+ val = RD1(sc, HDMI_A_VIDPOLCFG);
+ val &= ~HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
+ val |= de;
+ WR1(sc, HDMI_A_VIDPOLCFG, val);
+
+ /* Disable encryption */
+ val = RD1(sc, HDMI_A_HDCPCFG1);
+ val &= ~HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
+ val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
+ WR1(sc, HDMI_A_HDCPCFG1, val);
+}
+
+static int
+dwc_hdmi_set_mode(struct dwc_hdmi_softc *sc)
+{
+
+ dwc_hdmi_disable_overflow_interrupts(sc);
+ dwc_hdmi_av_composer(sc);
+ dwc_hdmi_phy_init(sc);
+ dwc_hdmi_enable_video_path(sc);
+ /* TODO: AVI infoframes */
+ dwc_hdmi_video_packetize(sc);
+ /* TODO: dwc_hdmi_video_csc(sc); */
+ dwc_hdmi_video_sample(sc);
+ dwc_hdmi_tx_hdcp_config(sc);
+ dwc_hdmi_clear_overflow(sc);
+
+ return (0);
+}
+
+static int
+hdmi_edid_read(struct dwc_hdmi_softc *sc, uint8_t **edid, uint32_t *edid_len)
+{
+ device_t i2c_dev;
+ int result;
+ uint8_t addr = 0;
+ struct iic_msg msg[] = {
+ { 0, IIC_M_WR, 1, &addr },
+ { 0, IIC_M_RD, EDID_LENGTH, NULL}
+ };
+
+ *edid = NULL;
+ *edid_len = 0;
+ i2c_dev = NULL;
+
+ if (sc->sc_get_i2c_dev != NULL)
+ i2c_dev = sc->sc_get_i2c_dev(sc->sc_dev);
+ if (!i2c_dev) {
+ device_printf(sc->sc_dev, "no DDC device found\n");
+ return (ENXIO);
+ }
+
+ device_printf(sc->sc_dev, "reading EDID from %s, addr %02x\n",
+ device_get_nameunit(i2c_dev), I2C_DDC_ADDR/2);
+
+ msg[0].slave = I2C_DDC_ADDR;
+ msg[1].slave = I2C_DDC_ADDR;
+ msg[1].buf = sc->sc_edid;
+
+ result = iicbus_request_bus(i2c_dev, sc->sc_dev, IIC_INTRWAIT);
+
+ if (result) {
+ device_printf(sc->sc_dev, "failed to request i2c bus: %d\n", result);
+ return (result);
+ }
+
+ result = iicbus_transfer(i2c_dev, msg, 2);
+ iicbus_release_bus(i2c_dev, sc->sc_dev);
+
+ if (result) {
+ device_printf(sc->sc_dev, "i2c transfer failed: %d\n", result);
+ return (result);
+ } else {
+ *edid_len = sc->sc_edid_len;
+ *edid = sc->sc_edid;
+ }
+
+ return (result);
+}
+
+static void
+dwc_hdmi_detect_cable(void *arg)
+{
+ struct dwc_hdmi_softc *sc;
+ uint32_t stat;
+
+ sc = arg;
+
+ stat = RD1(sc, HDMI_IH_PHY_STAT0);
+ if ((stat & HDMI_IH_PHY_STAT0_HPD) != 0) {
+ EVENTHANDLER_INVOKE(hdmi_event, sc->sc_dev,
+ HDMI_EVENT_CONNECTED);
+ }
+
+ /* Finished with the interrupt hook */
+ config_intrhook_disestablish(&sc->sc_mode_hook);
+}
+
+int
+dwc_hdmi_init(device_t dev)
+{
+ struct dwc_hdmi_softc *sc;
+ int err;
+
+ sc = device_get_softc(dev);
+ err = 0;
+
+ sc->sc_edid = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO);
+ sc->sc_edid_len = EDID_LENGTH;
+
+ device_printf(sc->sc_dev, "HDMI controller %02x:%02x:%02x:%02x\n",
+ RD1(sc, HDMI_DESIGN_ID), RD1(sc, HDMI_REVISION_ID),
+ RD1(sc, HDMI_PRODUCT_ID0), RD1(sc, HDMI_PRODUCT_ID1));
+
+ WR1(sc, HDMI_PHY_POL0, HDMI_PHY_POL0_HPD);
+ WR1(sc, HDMI_IH_PHY_STAT0, HDMI_IH_PHY_STAT0_HPD);
+
+ sc->sc_mode_hook.ich_func = dwc_hdmi_detect_cable;
+ sc->sc_mode_hook.ich_arg = sc;
+ if (config_intrhook_establish(&sc->sc_mode_hook) != 0) {
+ err = ENOMEM;
+ goto out;
+ }
+
+out:
+
+ if (err != 0) {
+ free(sc->sc_edid, M_DEVBUF);
+ sc->sc_edid = NULL;
+ }
+
+ return (err);
+}
+
+int
+dwc_hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len)
+{
+
+ return (hdmi_edid_read(device_get_softc(dev), edid, edid_len));
+}
+
+int
+dwc_hdmi_set_videomode(device_t dev, const struct videomode *mode)
+{
+ struct dwc_hdmi_softc *sc;
+
+ sc = device_get_softc(dev);
+ memcpy(&sc->sc_mode, mode, sizeof(*mode));
+
+ dwc_hdmi_set_mode(sc);
+
+ return (0);
+}
Index: sys/dev/hdmi/dwc_hdmi_fdt.c
===================================================================
--- /dev/null
+++ sys/dev/hdmi/dwc_hdmi_fdt.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * HDMI core module
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <dev/videomode/videomode.h>
+
+#include <dev/hdmi/dwc_hdmi.h>
+
+#include "hdmi_if.h"
+
+struct dwc_hdmi_fdt_softc {
+ struct dwc_hdmi_softc base;
+ clk_t clk_hdmi;
+ clk_t clk_ahb;
+ phandle_t i2c_xref;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ { "synopsys,dwc-hdmi", 1 },
+ { NULL, 0 }
+};
+
+static device_t
+dwc_hdmi_fdt_get_i2c_dev(device_t dev)
+{
+ struct dwc_hdmi_fdt_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->i2c_xref == 0)
+ return (NULL);
+
+ return (OF_device_from_xref(sc->i2c_xref));
+}
+
+static int
+dwc_hdmi_fdt_detach(device_t dev)
+{
+ struct dwc_hdmi_fdt_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->clk_ahb != NULL)
+ clk_release(sc->clk_ahb);
+ if (sc->clk_hdmi != NULL)
+ clk_release(sc->clk_hdmi);
+
+ if (sc->base.sc_mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->base.sc_mem_rid, sc->base.sc_mem_res);
+
+ return (0);
+}
+
+static int
+dwc_hdmi_fdt_attach(device_t dev)
+{
+ struct dwc_hdmi_fdt_softc *sc;
+ phandle_t node, i2c_xref;
+ uint32_t freq;
+ int err;
+
+ sc = device_get_softc(dev);
+ sc->base.sc_dev = dev;
+ sc->base.sc_get_i2c_dev = dwc_hdmi_fdt_get_i2c_dev;
+ err = 0;
+
+ /* Allocate memory resources. */
+ sc->base.sc_mem_rid = 0;
+ sc->base.sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->base.sc_mem_rid, RF_ACTIVE);
+ if (sc->base.sc_mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ err = ENXIO;
+ goto out;
+ }
+
+ node = ofw_bus_get_node(dev);
+ if (OF_getencprop(node, "ddc", &i2c_xref, sizeof(i2c_xref)) == -1)
+ sc->i2c_xref = 0;
+ else
+ sc->i2c_xref = i2c_xref;
+
+ if (OF_getencprop(node, "reg-shift", &sc->base.sc_reg_shift,
+ sizeof(sc->base.sc_reg_shift)) <= 0)
+ sc->base.sc_reg_shift = 0;
+
+ if (clk_get_by_ofw_name(dev, 0, "hdmi", &sc->clk_hdmi) != 0 ||
+ clk_get_by_ofw_name(dev, 0, "ahb", &sc->clk_ahb) != 0) {
+ device_printf(dev, "Cannot get clocks\n");
+ err = ENXIO;
+ goto out;
+ }
+ if (OF_getencprop(node, "clock-frequency", &freq, sizeof(freq)) > 0) {
+ err = clk_set_freq(sc->clk_hdmi, freq, CLK_SET_ROUND_DOWN);
+ if (err != 0) {
+ device_printf(dev,
+ "Cannot set HDMI clock frequency to %u Hz\n", freq);
+ goto out;
+ }
+ } else
+ device_printf(dev, "HDMI clock frequency not specified\n");
+ if (clk_enable(sc->clk_hdmi) != 0) {
+ device_printf(dev, "Cannot enable HDMI clock\n");
+ err = ENXIO;
+ goto out;
+ }
+ if (clk_enable(sc->clk_ahb) != 0) {
+ device_printf(dev, "Cannot enable AHB clock\n");
+ err = ENXIO;
+ goto out;
+ }
+
+ return (dwc_hdmi_init(dev));
+
+out:
+
+ dwc_hdmi_fdt_detach(dev);
+
+ return (err);
+}
+
+static int
+dwc_hdmi_fdt_probe(device_t dev)
+{
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Synopsys DesignWare HDMI Controller");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static device_method_t dwc_hdmi_fdt_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, dwc_hdmi_fdt_probe),
+ DEVMETHOD(device_attach, dwc_hdmi_fdt_attach),
+ DEVMETHOD(device_detach, dwc_hdmi_fdt_detach),
+
+ /* HDMI methods */
+ DEVMETHOD(hdmi_get_edid, dwc_hdmi_get_edid),
+ DEVMETHOD(hdmi_set_videomode, dwc_hdmi_set_videomode),
+
+ DEVMETHOD_END
+};
+
+static driver_t dwc_hdmi_fdt_driver = {
+ "dwc_hdmi",
+ dwc_hdmi_fdt_methods,
+ sizeof(struct dwc_hdmi_fdt_softc)
+};
+
+static devclass_t dwc_hdmi_fdt_devclass;
+
+DRIVER_MODULE(dwc_hdmi_fdt, simplebus, dwc_hdmi_fdt_driver,
+ dwc_hdmi_fdt_devclass, 0, 0);
Index: sys/dev/hdmi/dwc_hdmireg.h
===================================================================
--- sys/dev/hdmi/dwc_hdmireg.h
+++ sys/dev/hdmi/dwc_hdmireg.h
@@ -26,8 +26,8 @@
* $FreeBSD$
*/
-#ifndef __IMX6__HDMI_REGS_H__
-#define __IMX6__HDMI_REGS_H__
+#ifndef __DWC_HDMIREG_H__
+#define __DWC_HDMIREG_H__
#define HDMI_DESIGN_ID 0x0000
#define HDMI_REVISION_ID 0x0001
#define HDMI_PRODUCT_ID0 0x0002
@@ -435,11 +435,17 @@
#define HDMI_PHY_TST1 0x3002
#define HDMI_PHY_TST2 0x3003
#define HDMI_PHY_STAT0 0x3004
+#define HDMI_PHY_STAT0_RX_SENSE3 0x80
+#define HDMI_PHY_STAT0_RX_SENSE2 0x40
+#define HDMI_PHY_STAT0_RX_SENSE1 0x20
+#define HDMI_PHY_STAT0_RX_SENSE0 0x10
+#define HDMI_PHY_STAT0_RX_SENSE 0xf0
+#define HDMI_PHY_STAT0_HPD 0x02
#define HDMI_PHY_TX_PHY_LOCK 0x01
#define HDMI_PHY_INT0 0x3005
#define HDMI_PHY_MASK0 0x3006
#define HDMI_PHY_POL0 0x3007
-#define HDMI_PHY_HPD (1 << 1)
+#define HDMI_PHY_POL0_HPD 0x02
/* HDMI Master PHY Registers */
#define HDMI_PHY_I2CM_SLAVE_ADDR 0x3020
@@ -523,7 +529,13 @@
/* HDCP Encryption Engine Registers */
#define HDMI_A_HDCPCFG0 0x5000
+#define HDMI_A_HDCPCFG0_RXDETECT_MASK 0x4
+#define HDMI_A_HDCPCFG0_RXDETECT_ENABLE 0x4
+#define HDMI_A_HDCPCFG0_RXDETECT_DISABLE 0x0
#define HDMI_A_HDCPCFG1 0x5001
+#define HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK 0x2
+#define HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE 0x2
+#define HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE 0x0
#define HDMI_A_HDCPOBS0 0x5002
#define HDMI_A_HDCPOBS1 0x5003
#define HDMI_A_HDCPOBS2 0x5004
@@ -532,6 +544,9 @@
#define HDMI_A_APIINTSTAT 0x5007
#define HDMI_A_APIINTMSK 0x5008
#define HDMI_A_VIDPOLCFG 0x5009
+#define HDMI_A_VIDPOLCFG_DATAENPOL_MASK 0x10
+#define HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH 0x10
+#define HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW 0x0
#define HDMI_A_OESSWCFG 0x500A
#define HDMI_A_TIMER1SETUP0 0x500B
#define HDMI_A_TIMER1SETUP1 0x500C
@@ -648,4 +663,4 @@
#define HDMI_PHY_I2C_TXTERM 0x19
#define TXTERM_133 0x5
-#endif /* __IMX6__HDMI_REGS_H__ */
+#endif /* __DWC_HDMIREG_H__ */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Oct 24, 5:07 AM (4 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24121159
Default Alt Text
D8826.id23036.diff (51 KB)
Attached To
Mode
D8826: Split dwc_hdmi core code out from imx6_hdmi
Attached
Detach File
Event Timeline
Log In to Comment