aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/mcde/mcde_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/mcde/mcde_hw.c')
-rw-r--r--drivers/video/mcde/mcde_hw.c244
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,