aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Johansson <dan.johansson@stericsson.com>2010-07-01 15:11:24 +0200
committerJohn Rigby <john.rigby@linaro.org>2010-09-02 22:45:50 -0600
commit574724fbbb1bd2f78ee1a626dfa18cf707c741ab (patch)
treeb4984ed38c86b35e862c90bc1ac6acc8a9810381
parent50a1ade75cf1e3c2ff203b6447c59909b1f6fb84 (diff)
downloadlinux-2.6.34-ux500-574724fbbb1bd2f78ee1a626dfa18cf707c741ab.tar.gz
MCDE: V-sync on main and sub display using DSI BTA
* V-sync support for both primary and secondary display. * V-sync is disabled by default. It is enabled in menuconfig (System Type -> Display selection -> Enable v-sync for primary / secondary display). * DSI HS clock is set to 840 MHz, DSI esq clock 19.2 MHz. * Enables VAUX1 if startup graphics is enabled. ST Ericsson Change-Id: WP264234 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/2154 Tested-by: Dan JOHANSSON <dan.johansson@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com> Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> Change-Id: I47f72cb9449e08f089f6bdb25988bd9958644899 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/2809
-rwxr-xr-xarch/arm/mach-ux500/Kconfig-arch14
-rw-r--r--arch/arm/mach-ux500/board-mop500-mcde.c68
-rwxr-xr-xarch/arm/mach-ux500/prcmu-fw.c8
-rw-r--r--drivers/video/mcde/display-generic_dsi.c18
-rw-r--r--drivers/video/mcde/mcde_display.c7
-rw-r--r--drivers/video/mcde/mcde_dss.c31
-rw-r--r--drivers/video/mcde/mcde_fb.c14
-rw-r--r--drivers/video/mcde/mcde_hw.c244
-rw-r--r--include/video/mcde.h5
-rw-r--r--include/video/mcde_dss.h3
-rw-r--r--include/video/mcde_fb.h17
11 files changed, 261 insertions, 168 deletions
diff --git a/arch/arm/mach-ux500/Kconfig-arch b/arch/arm/mach-ux500/Kconfig-arch
index cbfdd4d3758..3e6d35c5c46 100755
--- a/arch/arm/mach-ux500/Kconfig-arch
+++ b/arch/arm/mach-ux500/Kconfig-arch
@@ -48,6 +48,13 @@ config DISPLAY_GENERIC_DSI_PRIMARY
help
Say yes here if main display exists
+config DISPLAY_GENERIC_DSI_PRIMARY_VSYNC
+ bool "Enable v-sync for primary display"
+ depends on DISPLAY_GENERIC_DSI_PRIMARY
+ default n
+ help
+ Say yes to enable v-sync for primary display
+
config DISPLAY_GENERIC_DSI_SECONDARY
bool "Sub display support"
depends on MACH_U8500_MOP && FB_MCDE
@@ -56,6 +63,13 @@ config DISPLAY_GENERIC_DSI_SECONDARY
help
Say yes here if sub display exists
+config DISPLAY_GENERIC_DSI_SECONDARY_VSYNC
+ bool "Enable v-sync for secondary display"
+ depends on DISPLAY_GENERIC_DSI_SECONDARY
+ default n
+ help
+ Say yes to enable v-sync for secondary display
+
config DISPLAY_AB8500_TERTIARY
bool "AB8500 TVout display support"
depends on MACH_U8500_MOP && !AV8100_SDTV && FB_MCDE
diff --git a/arch/arm/mach-ux500/board-mop500-mcde.c b/arch/arm/mach-ux500/board-mop500-mcde.c
index 7fbb35caf22..ef1a7274161 100644
--- a/arch/arm/mach-ux500/board-mop500-mcde.c
+++ b/arch/arm/mach-ux500/board-mop500-mcde.c
@@ -17,12 +17,12 @@
#include <video/mcde_fb.h>
#include <video/mcde_dss.h>
-#define DSI_UNIT_INTERVAL_0 0xA
-#define DSI_UNIT_INTERVAL_1 0xA
-#define DSI_UNIT_INTERVAL_2 0x6
+#define DSI_UNIT_INTERVAL_0 0x9
+#define DSI_UNIT_INTERVAL_1 0x9
+#define DSI_UNIT_INTERVAL_2 0x6
static bool rotate_main = true;
-static bool display_initialize_during_boot;
+static bool display_initialized_during_boot;
static int __init startup_graphics_setup(char *str)
{
@@ -32,14 +32,14 @@ static int __init startup_graphics_setup(char *str)
switch (*str) {
case '0':
pr_info("No Startup graphics support\n");
- display_initialize_during_boot = false;
+ display_initialized_during_boot = false;
break;
case '1':
pr_info("Startup graphics supported\n");
- display_initialize_during_boot = true;
+ display_initialized_during_boot = true;
break;
default:
- display_initialize_during_boot = false;
+ display_initialized_during_boot = false;
break;
};
@@ -84,7 +84,11 @@ struct mcde_display_device generic_display0 = {
.default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
.native_x_res = 864,
.native_y_res = 480,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC
+ .synchronized_update = true,
+#else
.synchronized_update = false,
+#endif
/* TODO: Remove rotation buffers once ESRAM driver is completed */
.rotbuf1 = U8500_ESRAM_BASE + 0x20000 * 4,
.rotbuf2 = U8500_ESRAM_BASE + 0x20000 * 4 + 0x10000,
@@ -132,7 +136,11 @@ static struct mcde_display_device generic_subdisplay = {
.default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
.native_x_res = 864,
.native_y_res = 480,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_VSYNC
+ .synchronized_update = true,
+#else
.synchronized_update = false,
+#endif
.dev = {
.platform_data = &generic_subdisplay_pdata,
},
@@ -366,7 +374,6 @@ static int display_registered_callback(struct notifier_block *nb,
struct mcde_display_device *ddev = dev;
u16 width, height;
bool rotate;
- bool display_initialized;
if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED)
return 0;
@@ -376,7 +383,6 @@ static int display_registered_callback(struct notifier_block *nb,
mcde_dss_get_native_resolution(ddev, &width, &height);
- display_initialized = (ddev->id == 0 && display_initialize_during_boot);
rotate = (ddev->id == 0 && rotate_main);
if (rotate) {
u16 tmp = height;
@@ -389,8 +395,7 @@ static int display_registered_callback(struct notifier_block *nb,
width, height,
width, height * 2,
ddev->default_pixel_format,
- rotate ? FB_ROTATE_CW : FB_ROTATE_UR,
- display_initialized);
+ rotate ? FB_ROTATE_CW : FB_ROTATE_UR);
if (IS_ERR(fbs[ddev->id]))
pr_warning("Failed to create fb for display %s\n", ddev->name);
else
@@ -403,15 +408,56 @@ static struct notifier_block display_nb = {
.notifier_call = display_registered_callback,
};
+static int framebuffer_registered_callback(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ int ret = 0;
+ struct fb_event *event_data = data;
+ struct fb_info *info;
+ struct fb_var_screeninfo var;
+ struct fb_fix_screeninfo fix;
+
+ if (event == FB_EVENT_FB_REGISTERED &&
+ !display_initialized_during_boot) {
+ if (event_data) {
+ u8 *addr;
+ info = event_data->info;
+ if (!lock_fb_info(info))
+ return -ENODEV;
+ var = info->var;
+ fix = info->fix;
+ addr = ioremap(fix.smem_start,
+ var.yres_virtual * fix.line_length);
+ memset(addr, 0x00,
+ var.yres_virtual * fix.line_length);
+ var.yoffset = var.yoffset ? 0 : var.yres;
+ if (info->fbops->fb_pan_display)
+ ret = info->fbops->fb_pan_display(&var, info);
+ unlock_fb_info(info);
+ }
+ }
+ return ret;
+}
+
+static struct notifier_block framebuffer_nb = {
+ .notifier_call = framebuffer_registered_callback,
+};
+
int __init init_display_devices(void)
{
int ret;
+ ret = fb_register_client(&framebuffer_nb);
+ if (ret)
+ pr_warning("Failed to register framebuffer notifier\n");
+
ret = mcde_dss_register_notifier(&display_nb);
if (ret)
pr_warning("Failed to register dss notifier\n");
#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY
+ if (display_initialized_during_boot)
+ generic_display0.power_mode = MCDE_DISPLAY_PM_STANDBY;
ret = mcde_display_device_register(&generic_display0);
if (ret)
pr_warning("Failed to register generic display device 0\n");
diff --git a/arch/arm/mach-ux500/prcmu-fw.c b/arch/arm/mach-ux500/prcmu-fw.c
index 8c98f2fa587..474cb919001 100755
--- a/arch/arm/mach-ux500/prcmu-fw.c
+++ b/arch/arm/mach-ux500/prcmu-fw.c
@@ -92,14 +92,14 @@ static int prcmu_set_hwacc_st(enum hw_acc_t hw_acc, enum hw_accst_t hw_accst);
#define PRCMU_UNCLAMP_DSS_DSIPLL 0x00600C00
#define PRCMU_POWER_ON_DSI 0x00008000
-#define PRCMU_DSI_CLOCK_SETTING 0x00000145
-#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000141
-#define PRCMU_PLLDSI_FREQ_SETTING 0x0004012B
+#define PRCMU_DSI_CLOCK_SETTING 0x00000148
+#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000F00
+#define PRCMU_PLLDSI_FREQ_SETTING 0x00020123
#define PRCMU_ENABLE_PLLDSI 0x00000001
#define PRCMU_RELEASE_RESET_DSS 0x0000400C
#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000202
-#define PRCMU_ENABLE_ESCAPE_CLOCK 0x07031717
+#define PRCMU_ENABLE_ESCAPE_CLOCK 0x07010101
#define PRCMU_DSI_RESET_SW 0x00000007
#define PRCMU_MCDE_DELAY 10
diff --git a/drivers/video/mcde/display-generic_dsi.c b/drivers/video/mcde/display-generic_dsi.c
index 3391d2b3808..15b8ccec59a 100644
--- a/drivers/video/mcde/display-generic_dsi.c
+++ b/drivers/video/mcde/display-generic_dsi.c
@@ -106,6 +106,22 @@ static int __devinit generic_probe(struct mcde_display_device *dev)
regulator_set_voltage(pdata->regulator,
pdata->min_supply_voltage,
pdata->max_supply_voltage);
+ /*
+ * When u-boot has display a startup screen.
+ * U-boot has turned on display power however the
+ * regulator framework does not know about that
+ * This is the case here, the display driver has to
+ * enable the regulator for the display.
+ */
+ if (dev->power_mode == MCDE_DISPLAY_PM_STANDBY) {
+ ret = regulator_enable(pdata->regulator);
+ if (ret < 0) {
+ dev_err(&dev->dev,
+ "%s:Failed to enable regulator\n"
+ , __func__);
+ goto regulator_enable_failed;
+ }
+ }
}
dev->platform_enable = generic_platform_enable;
dev->platform_disable = generic_platform_disable;
@@ -119,7 +135,7 @@ static int __devinit generic_probe(struct mcde_display_device *dev)
dev_info(&dev->dev, "Generic display probed\n");
goto out;
-
+regulator_enable_failed:
regulator_get_failed:
if (pdata->generic_platform_enable && pdata->reset_gpio)
gpio_free(pdata->reset_gpio);
diff --git a/drivers/video/mcde/mcde_display.c b/drivers/video/mcde/mcde_display.c
index aa52eee7475..1537980dcaf 100644
--- a/drivers/video/mcde/mcde_display.c
+++ b/drivers/video/mcde/mcde_display.c
@@ -92,6 +92,8 @@ static int mcde_display_set_power_mode_default(struct mcde_display_device *ddev,
ddev->power_mode = MCDE_DISPLAY_PM_OFF;
}
+ mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode);
+
return ret;
}
@@ -205,11 +207,12 @@ static int mcde_display_set_synchronized_update_default(
int ret = 0;
if (ddev->port->type == MCDE_PORTTYPE_DSI) {
if (ddev->port->sync_src == MCDE_SYNCSRC_TE0 ||
- ddev->port->sync_src == MCDE_SYNCSRC_TE1) {
+ ddev->port->sync_src == MCDE_SYNCSRC_TE1 ||
+ ddev->port->sync_src == MCDE_SYNCSRC_BTA) {
u8 m = 0;
ret = mcde_display_dsi_dcs_write(ddev,
DCS_CMD_SET_TEAR_ON, &m, 1);
- } else if (ddev->port->sync_src != MCDE_SYNCSRC_BTA) {
+ } else {
ret = -EINVAL;
}
} else {
diff --git a/drivers/video/mcde/mcde_dss.c b/drivers/video/mcde/mcde_dss.c
index d6930a6ad70..846d7c33e33 100644
--- a/drivers/video/mcde/mcde_dss.c
+++ b/drivers/video/mcde/mcde_dss.c
@@ -67,8 +67,7 @@ static int apply_overlay(struct mcde_overlay *ovly,
/* MCDE DSS operations */
-int mcde_dss_enable_display(struct mcde_display_device *ddev,
- bool display_initialized)
+int mcde_dss_enable_display(struct mcde_display_device *ddev)
{
int ret;
struct mcde_chnl_state *chnl;
@@ -84,22 +83,20 @@ int mcde_dss_enable_display(struct mcde_display_device *ddev,
goto get_chnl_failed;
}
ddev->chnl_state = chnl;
- if (!display_initialized) {
- /* Initiate display communication */
- ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
- if (ret < 0) {
- dev_warn(&ddev->dev, "Failed to initialize display\n");
- goto display_failed;
- }
-
- dev_dbg(&ddev->dev, "Display enabled, chnl=%d\n",
- ddev->chnl_id);
- } else {
- dev_dbg(&ddev->dev, "Display already enabled, chnl=%d\n",
- ddev->chnl_id);
- ddev->power_mode = MCDE_DISPLAY_PM_ON;
- ret = 0;
+ /* Initiate display communication */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "Failed to initialize display\n");
+ goto display_failed;
}
+
+ ret = ddev->set_synchronized_update(ddev, ddev->synchronized_update);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "Failed to set sync\n");
+ /* TODO: call driver for all defaults like sync_update above */
+
+ dev_dbg(&ddev->dev, "Display enabled, chnl=%d\n",
+ ddev->chnl_id);
ddev->enabled = true;
out:
return ret;
diff --git a/drivers/video/mcde/mcde_fb.c b/drivers/video/mcde/mcde_fb.c
index fc77e5be1d8..f9697d2e9df 100644
--- a/drivers/video/mcde/mcde_fb.c
+++ b/drivers/video/mcde/mcde_fb.c
@@ -411,6 +411,7 @@ static int apply_var(struct fb_info *fbi, struct mcde_display_device *ddev)
/* Reallocate memory */
line_len = (fbi->var.bits_per_pixel * var->xres_virtual) / 8;
+ line_len = ALIGN(line_len, MCDE_BUF_LINE_ALIGMENT);
size = line_len * var->yres_virtual;
ret = reallocate_fb_mem(fbi, size);
if (ret) {
@@ -432,7 +433,6 @@ static int apply_var(struct fb_info *fbi, struct mcde_display_device *ddev)
memset(&vmode, 0, sizeof(struct mcde_video_mode));
var_to_vmode(var, &vmode);
mcde_dss_set_video_mode(ddev, &vmode);
-
mcde_dss_apply_channel(ddev);
}
@@ -531,7 +531,7 @@ static struct fb_ops fb_ops = {
struct fb_info *mcde_fb_create(struct mcde_display_device *ddev,
u16 w, u16 h, u16 vw, u16 vh, enum mcde_ovly_pix_fmt pix_fmt,
- u32 rotate, bool display_initialized)
+ u32 rotate)
{
int ret = 0;
struct fb_info *fbi;
@@ -554,7 +554,7 @@ struct fb_info *mcde_fb_create(struct mcde_display_device *ddev,
init_fb(fbi);
mfb = to_mcde_fb(fbi);
- ret = mcde_dss_enable_display(ddev, display_initialized);
+ ret = mcde_dss_enable_display(ddev);
if (ret)
goto display_enable_failed;
@@ -584,15 +584,7 @@ struct fb_info *mcde_fb_create(struct mcde_display_device *ddev,
if (ret)
goto fb_register_failed;
- if (!display_initialized) {
- ret = mcde_dss_update_overlay(ovly);
- if (ret)
- goto ovly_update_failed;
- }
-
goto out;
-ovly_update_failed:
- unregister_framebuffer(fbi);
fb_register_failed:
mcde_dss_disable_overlay(ovly);
ovly_enable_failed:
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,
diff --git a/include/video/mcde.h b/include/video/mcde.h
index d7ea581d190..415d9db960a 100644
--- a/include/video/mcde.h
+++ b/include/video/mcde.h
@@ -205,6 +205,8 @@ enum mcde_display_rotation {
#define MCDE_MIN_HEIGHT 16
#define MCDE_MAX_WIDTH 2048
#define MCDE_MAX_HEIGHT 2048
+#define MCDE_BUF_START_ALIGMENT 8
+#define MCDE_BUF_LINE_ALIGMENT 8
#define MCDE_FIFO_AB_SIZE 640
#define MCDE_FIFO_C0C1_SIZE 160
@@ -273,6 +275,9 @@ int mcde_chnl_set_rotation(struct mcde_chnl_state *chnl,
enum mcde_display_rotation rotation, u32 rotbuf1, u32 rotbuf2);
int mcde_chnl_enable_synchronized_update(struct mcde_chnl_state *chnl,
bool enable);
+int mcde_chnl_set_power_mode(struct mcde_chnl_state *chnl,
+ enum mcde_display_power_mode power_mode);
+
int mcde_chnl_apply(struct mcde_chnl_state *chnl);
int mcde_chnl_update(struct mcde_chnl_state *chnl,
struct mcde_rectangle *update_area);
diff --git a/include/video/mcde_dss.h b/include/video/mcde_dss.h
index 648b46d0528..a32b2dfdeba 100644
--- a/include/video/mcde_dss.h
+++ b/include/video/mcde_dss.h
@@ -19,8 +19,7 @@
/* Public MCDE dss (Used by MCDE fb ioctl & MCDE display sysfs) */
-int mcde_dss_enable_display(struct mcde_display_device *ddev,
- bool display_initialized);
+int mcde_dss_enable_display(struct mcde_display_device *ddev);
void mcde_dss_disable_display(struct mcde_display_device *ddev);
int mcde_dss_apply_channel(struct mcde_display_device *ddev);
struct mcde_overlay *mcde_dss_create_overlay(struct mcde_display_device *ddev,
diff --git a/include/video/mcde_fb.h b/include/video/mcde_fb.h
index 871b0225c46..6d05f612184 100644
--- a/include/video/mcde_fb.h
+++ b/include/video/mcde_fb.h
@@ -12,9 +12,18 @@
#define __MCDE_FB__H__
#include <linux/fb.h>
-
+#include <linux/ioctl.h>
+#if !defined(__KERNEL__) && !defined(_KERNEL)
+#include <stdint.h>
+#else
+#include <linux/types.h>
+#endif
+
+#ifdef __KERNEL__
#include "mcde_dss.h"
+#endif
+#ifdef __KERNEL__
#define to_mcde_fb(x) ((struct mcde_fb *)(x)->par)
#define MCDE_FB_MAX_NUM_OVERLAYS 3
@@ -28,8 +37,9 @@ struct mcde_fb {
/* MCDE fbdev API */
struct fb_info *mcde_fb_create(struct mcde_display_device *ddev,
- u16 w, u16 h, u16 vw, u16 vh, enum mcde_ovly_pix_fmt pix_fmt,
- u32 rotate, bool display_initialized);
+ uint16_t w, uint16_t h, uint16_t vw, uint16_t vh,
+ enum mcde_ovly_pix_fmt pix_fmt, uint32_t rotate);
+
int mcde_fb_attach_overlay(struct fb_info *fb_info,
struct mcde_overlay *ovl);
void mcde_fb_destroy(struct fb_info *fb_info);
@@ -37,6 +47,7 @@ void mcde_fb_destroy(struct fb_info *fb_info);
/* MCDE fb driver */
int mcde_fb_init(void);
void mcde_fb_exit(void);
+#endif
#endif /* __MCDE_FB__H__ */