diff options
Diffstat (limited to 'drivers/video/mcde/mcde_hw.c')
-rw-r--r-- | drivers/video/mcde/mcde_hw.c | 244 |
1 files changed, 127 insertions, 117 deletions
diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c index c04f06717a2..0ec39e572c8 100644 --- a/drivers/video/mcde/mcde_hw.c +++ b/drivers/video/mcde/mcde_hw.c @@ -181,7 +181,7 @@ struct tv_regs { /* field 1 */ u16 bel1; /* field total vertical blanking lines */ u16 fsl1; /* field vbp */ - /* field 1 *//* REVIEW: Field 2? */ + /* field 2 */ u16 bel2; u16 fsl2; bool interlaced_en; @@ -201,6 +201,8 @@ struct mcde_chnl_state { u32 transactionid_hw; wait_queue_head_t waitq_hw; /* Waitq for transactionid_hw */ + enum mcde_display_power_mode power_mode; + /* Staged settings */ bool synchronized_update; enum mcde_port_pix_fmt pix_fmt; @@ -217,117 +219,6 @@ struct mcde_chnl_state { bool continous_running; }; -/* TODO: give these a place? *//* REVIEW: Remove, move to top move to use? */ -#define MCDE_CONFIG_TVOUT_HBORDER 2 -#define MCDE_CONFIG_TVOUT_VBORDER 2 - -int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl, - struct mcde_video_mode *vmode) -{ - if (chnl == NULL || vmode == NULL) - return -EINVAL; - - disable_channel(chnl); - chnl->vmode = *vmode; - - return 0; -} - -static void tv_video_mode_apply(struct mcde_chnl_state *chnl) -{ - /* assume xres == 720 */ - dev_vdbg(&mcde_dev->dev, "%s\n", __func__); - /* -4 since MCDE doesn't include SAV/EAV, 2 bytes each, to blanking */ - chnl->tv_regs.hbw = chnl->vmode.hbp + chnl->vmode.hfp - 4; - chnl->tv_regs.bel1 = chnl->vmode.vbp1 + chnl->vmode.vfp1; - chnl->tv_regs.fsl1 = chnl->vmode.vbp1; - chnl->tv_regs.bel2 = chnl->vmode.vbp2 + chnl->vmode.vfp2; - chnl->tv_regs.fsl2 = chnl->vmode.vbp2; - chnl->tv_regs.interlaced_en = chnl->vmode.interlaced; - - if (chnl->port.phy.dpi.num_data_lanes == 4) - chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P_BE; - else - chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P; -} - -static void update_tv_registers(enum mcde_chnl chnl_id, struct tv_regs *regs) -{ - u8 idx = chnl_id; - u8 maj_version; - - dev_dbg(&mcde_dev->dev, "%s\n", __func__); - mcde_wreg(MCDE_TVCRA + idx * MCDE_TVCRA_GROUPOFFSET, - MCDE_TVCRA_SEL_MOD(MCDE_TVCRA_SEL_MOD_TV) | - MCDE_TVCRA_INTEREN(regs->interlaced_en) | - MCDE_TVCRA_IFIELD(1) | - MCDE_TVCRA_TVMODE(regs->tv_mode) | - MCDE_TVCRA_SDTVMODE(MCDE_TVCRA_SDTVMODE_Y0CBY1CR) | - MCDE_TVCRA_AVRGEN(0)); - /* REVIEW: Magic values */ - mcde_wreg(MCDE_TVBLUA + idx * MCDE_TVBLUA_GROUPOFFSET, - MCDE_TVBLUA_TVBLU(0x83) | - MCDE_TVBLUA_TVBCB(0x9c) | - MCDE_TVBLUA_TVBCR(0x2c)); - - /* Vertical timing registers */ - mcde_wreg(MCDE_TVDVOA + idx * MCDE_TVDVOA_GROUPOFFSET, - MCDE_TVDVOA_DVO1(MCDE_CONFIG_TVOUT_VBORDER) | - MCDE_TVDVOA_DVO2(MCDE_CONFIG_TVOUT_VBORDER)); - mcde_wreg(MCDE_TVBL1A + idx * MCDE_TVBL1A_GROUPOFFSET, - MCDE_TVBL1A_BEL1(regs->bel1) | - MCDE_TVBL1A_BSL1(MCDE_CONFIG_TVOUT_VBORDER)); - mcde_wreg(MCDE_TVBL2A + idx * MCDE_TVBL1A_GROUPOFFSET, - MCDE_TVBL2A_BEL2(regs->bel2) | - MCDE_TVBL2A_BSL2(MCDE_CONFIG_TVOUT_VBORDER)); - mcde_wreg(MCDE_TVISLA + idx * MCDE_TVISLA_GROUPOFFSET, - MCDE_TVISLA_FSL1(regs->fsl1) | - MCDE_TVISLA_FSL2(regs->fsl2)); - /* Horizontal timing registers */ - maj_version = MCDE_REG2VAL(/* REVIEW: Make global and do on init? */ - MCDE_PID, MAJOR_VERSION, mcde_rreg(MCDE_PID)); - - if (maj_version > 3) { - mcde_wreg(MCDE_TVLBALWA + idx * MCDE_TVLBALWA_GROUPOFFSET, - MCDE_TVLBALWA_LBW(regs->hbw) | - MCDE_TVLBALWA_ALW(MCDE_CONFIG_TVOUT_HBORDER)); - mcde_wreg(MCDE_TVTIM1A + idx * MCDE_TVTIM1A_GROUPOFFSET, - MCDE_TVTIM1A_DHO(MCDE_CONFIG_TVOUT_HBORDER)); - } else { - /* in earlier versions the LBW and DHO fields are swapped */ - mcde_wreg(MCDE_TVLBALWA + idx * MCDE_TVLBALWA_GROUPOFFSET, - MCDE_TVLBALWA_LBW(MCDE_CONFIG_TVOUT_HBORDER) | - MCDE_TVLBALWA_ALW(MCDE_CONFIG_TVOUT_HBORDER)); - mcde_wreg(MCDE_TVTIM1A + idx * MCDE_TVTIM1A_GROUPOFFSET, - MCDE_TVTIM1A_DHO(regs->hbw)); - } -} - -static void update_col_registers(enum mcde_chnl chnl_id, struct col_regs *regs) -{ - u8 idx = chnl_id; - - dev_vdbg(&mcde_dev->dev, "%s\n", __func__); - mcde_wreg(MCDE_RGBCONV1A + idx * MCDE_RGBCONV1A_GROUPOFFSET, - MCDE_RGBCONV1A_YR_RED(regs->y_red) | - MCDE_RGBCONV1A_YR_GREEN(regs->y_green)); - mcde_wreg(MCDE_RGBCONV2A + idx * MCDE_RGBCONV2A_GROUPOFFSET, - MCDE_RGBCONV2A_YR_BLUE(regs->y_blue) | - MCDE_RGBCONV2A_CR_RED(regs->cr_red)); - mcde_wreg(MCDE_RGBCONV3A + idx * MCDE_RGBCONV3A_GROUPOFFSET, - MCDE_RGBCONV3A_CR_GREEN(regs->cr_green) | - MCDE_RGBCONV3A_CR_BLUE(regs->cr_blue)); - mcde_wreg(MCDE_RGBCONV4A + idx * MCDE_RGBCONV4A_GROUPOFFSET, - MCDE_RGBCONV4A_CB_RED(regs->cb_red) | - MCDE_RGBCONV4A_CB_GREEN(regs->cb_green)); - mcde_wreg(MCDE_RGBCONV5A + idx * MCDE_RGBCONV5A_GROUPOFFSET, - MCDE_RGBCONV5A_CB_BLUE(regs->cb_blue) | - MCDE_RGBCONV5A_OFF_RED(regs->off_red)); - mcde_wreg(MCDE_RGBCONV6A + idx * MCDE_RGBCONV6A_GROUPOFFSET, - MCDE_RGBCONV6A_OFF_GREEN(regs->off_green) | - MCDE_RGBCONV6A_OFF_BLUE(regs->off_blue)); -} -/* REVIEW: Move all structs etc to top, don't mix code and declarations */ static struct mcde_chnl_state channels[] = { { .id = MCDE_CHNL_A, @@ -365,6 +256,7 @@ struct chnl_config { bool f01mux; bool f01mux_set; }; + static /* TODO: const, compiler bug? */ struct chnl_config chnl_configs[] = { /* Channel A */ { .path = MCDE_CHNLPATH_CHNLA_FIFOA_DPI_0, @@ -448,8 +340,117 @@ static /* TODO: const, compiler bug? */ struct chnl_config chnl_configs[] = { .fabmux = true, .fabmux_set = true }, }; -/* MCDE internal helpers */ +/* TODO: give these a place? *//* REVIEW: Remove, move to top move to use? */ +#define MCDE_CONFIG_TVOUT_HBORDER 2 +#define MCDE_CONFIG_TVOUT_VBORDER 2 +int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl, + struct mcde_video_mode *vmode) +{ + if (chnl == NULL || vmode == NULL) + return -EINVAL; + + disable_channel(chnl); + chnl->vmode = *vmode; + + return 0; +} + +static void tv_video_mode_apply(struct mcde_chnl_state *chnl) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + /* -4 since MCDE doesn't include SAV/EAV, 2 bytes each, to blanking */ + chnl->tv_regs.hbw = chnl->vmode.hbp + chnl->vmode.hfp - 4; + chnl->tv_regs.bel1 = chnl->vmode.vbp1 + chnl->vmode.vfp1; + chnl->tv_regs.fsl1 = chnl->vmode.vbp1; + chnl->tv_regs.bel2 = chnl->vmode.vbp2 + chnl->vmode.vfp2; + chnl->tv_regs.fsl2 = chnl->vmode.vbp2; + chnl->tv_regs.interlaced_en = chnl->vmode.interlaced; + + if (chnl->port.phy.dpi.num_data_lanes == 4) + chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P_BE; + else + chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P; +} + +static void update_tv_registers(enum mcde_chnl chnl_id, struct tv_regs *regs) +{ + u8 idx = chnl_id; + u8 maj_version; + + dev_dbg(&mcde_dev->dev, "%s\n", __func__); + mcde_wreg(MCDE_TVCRA + idx * MCDE_TVCRA_GROUPOFFSET, + MCDE_TVCRA_SEL_MOD(MCDE_TVCRA_SEL_MOD_TV) | + MCDE_TVCRA_INTEREN(regs->interlaced_en) | + MCDE_TVCRA_IFIELD(1) | + MCDE_TVCRA_TVMODE(regs->tv_mode) | + MCDE_TVCRA_SDTVMODE(MCDE_TVCRA_SDTVMODE_Y0CBY1CR) | + MCDE_TVCRA_AVRGEN(0)); + /* REVIEW: Magic values */ + mcde_wreg(MCDE_TVBLUA + idx * MCDE_TVBLUA_GROUPOFFSET, + MCDE_TVBLUA_TVBLU(0x83) | + MCDE_TVBLUA_TVBCB(0x9c) | + MCDE_TVBLUA_TVBCR(0x2c)); + + /* Vertical timing registers */ + mcde_wreg(MCDE_TVDVOA + idx * MCDE_TVDVOA_GROUPOFFSET, + MCDE_TVDVOA_DVO1(MCDE_CONFIG_TVOUT_VBORDER) | + MCDE_TVDVOA_DVO2(MCDE_CONFIG_TVOUT_VBORDER)); + mcde_wreg(MCDE_TVBL1A + idx * MCDE_TVBL1A_GROUPOFFSET, + MCDE_TVBL1A_BEL1(regs->bel1) | + MCDE_TVBL1A_BSL1(MCDE_CONFIG_TVOUT_VBORDER)); + mcde_wreg(MCDE_TVBL2A + idx * MCDE_TVBL1A_GROUPOFFSET, + MCDE_TVBL2A_BEL2(regs->bel2) | + MCDE_TVBL2A_BSL2(MCDE_CONFIG_TVOUT_VBORDER)); + mcde_wreg(MCDE_TVISLA + idx * MCDE_TVISLA_GROUPOFFSET, + MCDE_TVISLA_FSL1(regs->fsl1) | + MCDE_TVISLA_FSL2(regs->fsl2)); + /* Horizontal timing registers */ + maj_version = MCDE_REG2VAL(/* REVIEW: Make global and do on init? */ + MCDE_PID, MAJOR_VERSION, mcde_rreg(MCDE_PID)); + + if (maj_version > 3) { + mcde_wreg(MCDE_TVLBALWA + idx * MCDE_TVLBALWA_GROUPOFFSET, + MCDE_TVLBALWA_LBW(regs->hbw) | + MCDE_TVLBALWA_ALW(MCDE_CONFIG_TVOUT_HBORDER)); + mcde_wreg(MCDE_TVTIM1A + idx * MCDE_TVTIM1A_GROUPOFFSET, + MCDE_TVTIM1A_DHO(MCDE_CONFIG_TVOUT_HBORDER)); + } else { + /* in earlier versions the LBW and DHO fields are swapped */ + mcde_wreg(MCDE_TVLBALWA + idx * MCDE_TVLBALWA_GROUPOFFSET, + MCDE_TVLBALWA_LBW(MCDE_CONFIG_TVOUT_HBORDER) | + MCDE_TVLBALWA_ALW(MCDE_CONFIG_TVOUT_HBORDER)); + mcde_wreg(MCDE_TVTIM1A + idx * MCDE_TVTIM1A_GROUPOFFSET, + MCDE_TVTIM1A_DHO(regs->hbw)); + } +} + +static void update_col_registers(enum mcde_chnl chnl_id, struct col_regs *regs) +{ + u8 idx = chnl_id; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + mcde_wreg(MCDE_RGBCONV1A + idx * MCDE_RGBCONV1A_GROUPOFFSET, + MCDE_RGBCONV1A_YR_RED(regs->y_red) | + MCDE_RGBCONV1A_YR_GREEN(regs->y_green)); + mcde_wreg(MCDE_RGBCONV2A + idx * MCDE_RGBCONV2A_GROUPOFFSET, + MCDE_RGBCONV2A_YR_BLUE(regs->y_blue) | + MCDE_RGBCONV2A_CR_RED(regs->cr_red)); + mcde_wreg(MCDE_RGBCONV3A + idx * MCDE_RGBCONV3A_GROUPOFFSET, + MCDE_RGBCONV3A_CR_GREEN(regs->cr_green) | + MCDE_RGBCONV3A_CR_BLUE(regs->cr_blue)); + mcde_wreg(MCDE_RGBCONV4A + idx * MCDE_RGBCONV4A_GROUPOFFSET, + MCDE_RGBCONV4A_CB_RED(regs->cb_red) | + MCDE_RGBCONV4A_CB_GREEN(regs->cb_green)); + mcde_wreg(MCDE_RGBCONV5A + idx * MCDE_RGBCONV5A_GROUPOFFSET, + MCDE_RGBCONV5A_CB_BLUE(regs->cb_blue) | + MCDE_RGBCONV5A_OFF_RED(regs->off_red)); + mcde_wreg(MCDE_RGBCONV6A + idx * MCDE_RGBCONV6A_GROUPOFFSET, + MCDE_RGBCONV6A_OFF_GREEN(regs->off_green) | + MCDE_RGBCONV6A_OFF_BLUE(regs->off_blue)); +} + +/* MCDE internal helpers */ static u8 portfmt2dsipacking(enum mcde_port_pix_fmt pix_fmt) { switch (pix_fmt) { @@ -575,10 +576,9 @@ static irqreturn_t mcde_irq_handler(int irq, void *dev) } irq_status = dsi_rfld(i, DSI_CMD_MODE_STS_FLAG, ERR_NO_TE_FLAG); if (irq_status) { - trig = true; dsi_wreg(i, DSI_CMD_MODE_STS_CLR, DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR(true)); - dev_vdbg(&mcde_dev->dev, "NO_TE DSI%d\n", i); + dev_info(&mcde_dev->dev, "NO_TE DSI%d\n", i); } if (!trig) continue; @@ -1351,6 +1351,16 @@ int mcde_chnl_enable_synchronized_update(struct mcde_chnl_state *chnl, return 0; } +int mcde_chnl_set_power_mode(struct mcde_chnl_state *chnl, + enum mcde_display_power_mode power_mode) +{ + if (!chnl->inuse) + return -EINVAL; + + chnl->power_mode = power_mode; + return 0; +} + int mcde_chnl_apply(struct mcde_chnl_state *chnl) { /* TODO: lock *//* REVIEW: MCDE locking! */ @@ -1422,7 +1432,8 @@ static void chnl_update_non_continous(struct mcde_chnl_state *chnl) chnl_update_registers(chnl); /* TODO: look at port sync source and synched_update */ - if (chnl->regs.synchronized_update) { + if (chnl->regs.synchronized_update && + chnl->power_mode == MCDE_DISPLAY_PM_ON) { if (chnl->port.type == MCDE_PORTTYPE_DSI && chnl->port.sync_src == MCDE_SYNCSRC_BTA) { while (dsi_rfld(chnl->port.link, DSI_CMD_MODE_STS, @@ -1430,7 +1441,6 @@ static void chnl_update_non_continous(struct mcde_chnl_state *chnl) udelay(100); dsi_te_request(chnl); } - /* TODO: TE sync */ } else { mcde_wreg(MCDE_CHNL0SYNCHSW + chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET, |