summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNaveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>2011-08-26 21:33:14 +0530
committerUlf Hansson <ulf.hansson@stericsson.com>2011-09-19 16:00:17 +0200
commitbe6bef0765a85c9ed462076a19c192d836faaa9c (patch)
tree0c14af0ce14259c3cf2633c8b8e66376b2e43bfd
parent5cd8f50015bb3804537680d426d082a81cc88e98 (diff)
mcde:Migrate the patches for kernel3.0
Migrate the following commits for mcde driver files 0c80403 video: mcde: Add sony display support for DB5500 42c4245 Revert "video: mcde: Add sony display support for DB5500" 190e10f video: mcde: check for driver at suspend - resume 8a5da1e video: mcde: Configure channels and overlays for DB5500 4b15316 video: mcde: apply color conversion for DPI mode 409f44a video: mcde: Add sony display support for DB5500 585663b video: mcde: don't fail on no VANA 04ad4ac video: av8100: Add HDMI AVI Infoframe 7587405 video: mcde: Add DB5500 V2 support 91406cb video: mcde: remove PDP config 6bf7c79 video: mcde: fix suspend crash if no channel state 6d71d02 video: av8100: Add new firmware version de0af16 mcde: fix crash on unsupported hardware version 5d46943 video: mcde: remove mdelay in DSI write bc272e8 video: av8100: Reduce power consumption 2a22b39 video: mcde: enable mcde channel for DSI command b441a21 video: mcde: enable reading > 1 byte in DCS cmd ST-Ericsson ID: 352334 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: If64e30ccb3bb789f0c6bc062d95623c4aad08be1 Signed-off-by: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/29549
-rw-r--r--drivers/video/mcde/Kconfig4
-rw-r--r--drivers/video/mcde/Makefile1
-rw-r--r--drivers/video/mcde/display-ab8500.c5
-rw-r--r--drivers/video/mcde/display-av8100.c94
-rw-r--r--drivers/video/mcde/display-sony_acx424akp_dsi.c400
-rw-r--r--drivers/video/mcde/dsilink_regs.h1
-rw-r--r--drivers/video/mcde/mcde_bus.c4
-rw-r--r--drivers/video/mcde/mcde_fb.c61
-rw-r--r--drivers/video/mcde/mcde_hw.c170
-rw-r--r--include/video/mcde.h10
-rw-r--r--include/video/mcde_display-sony_acx424akp_dsi.h41
-rw-r--r--include/video/mcde_display.h1
12 files changed, 730 insertions, 62 deletions
diff --git a/drivers/video/mcde/Kconfig b/drivers/video/mcde/Kconfig
index a1310332cf9..a2bca06b128 100644
--- a/drivers/video/mcde/Kconfig
+++ b/drivers/video/mcde/Kconfig
@@ -15,6 +15,10 @@ config MCDE_DISPLAY_GENERIC_DSI
tristate "Generic DSI display driver"
depends on FB_MCDE
+config MCDE_DISPLAY_SONY_ACX424AKP_DSI
+ tristate "Sony acx424akp DSI display driver"
+ depends on FB_MCDE
+
config MCDE_DISPLAY_SONY_SY35560_DSI
tristate "Sony sy35560 display driver"
depends on FB_MCDE
diff --git a/drivers/video/mcde/Makefile b/drivers/video/mcde/Makefile
index 7c9324ded3a..1c6e5cde42b 100644
--- a/drivers/video/mcde/Makefile
+++ b/drivers/video/mcde/Makefile
@@ -3,6 +3,7 @@ mcde-objs := mcde_mod.o mcde_hw.o mcde_dss.o mcde_display.o mcde_bus.o mcde_fb
obj-$(CONFIG_FB_MCDE) += mcde.o
obj-$(CONFIG_MCDE_DISPLAY_GENERIC_DSI) += display-generic_dsi.o
+obj-$(CONFIG_MCDE_DISPLAY_SONY_ACX424AKP_DSI) += display-sony_acx424akp_dsi.o
obj-$(CONFIG_MCDE_DISPLAY_SONY_SY35560_DSI) += display-sony_sy35560_dsi.o
obj-$(CONFIG_MCDE_DISPLAY_VUIB500_DPI) += display-vuib500-dpi.o
obj-$(CONFIG_MCDE_DISPLAY_AB8500_DENC) += display-ab8500.o
diff --git a/drivers/video/mcde/display-ab8500.c b/drivers/video/mcde/display-ab8500.c
index 5d7f1bb92a6..789bf28cdf1 100644
--- a/drivers/video/mcde/display-ab8500.c
+++ b/drivers/video/mcde/display-ab8500.c
@@ -75,7 +75,8 @@ static int set_video_mode(struct mcde_display_device *ddev,
static int set_power_mode(struct mcde_display_device *ddev,
enum mcde_display_power_mode power_mode);
static int on_first_update(struct mcde_display_device *ddev);
-static int display_update(struct mcde_display_device *ddev, bool tripple_buf);
+static int display_update(struct mcde_display_device *ddev,
+ bool tripple_buffer);
static int __devinit ab8500_probe(struct mcde_display_device *ddev)
{
@@ -461,7 +462,7 @@ static int display_update(struct mcde_display_device *ddev, bool tripple_buffer)
goto error;
}
ret = mcde_chnl_update(ddev->chnl_state, &ddev->update_area,
- tripple_buffer);
+ tripple_buffer);
if (ret < 0)
goto error;
out:
diff --git a/drivers/video/mcde/display-av8100.c b/drivers/video/mcde/display-av8100.c
index 688a4d17688..5602ec37ba5 100644
--- a/drivers/video/mcde/display-av8100.c
+++ b/drivers/video/mcde/display-av8100.c
@@ -24,6 +24,13 @@
#define SWITCH_HELPSTR ", 0=HDMI, 1=SDTV, 2=DVI\n"
+/* AVI Infoframe */
+#define AVI_INFOFRAME_DATA_SIZE 13
+#define AVI_INFOFRAME_TYPE 0x82
+#define AVI_INFOFRAME_VERSION 0x02
+#define AVI_INFOFRAME_DB1 0x10 /* Active Information present */
+#define AVI_INFOFRAME_DB2 0x08 /* Active Portion Aspect ratio */
+
struct cea_vesa_video_mode {
u32 cea;
u32 vesa_cea_nr;
@@ -672,6 +679,40 @@ static struct mcde_video_mode *video_mode_get(struct mcde_display_device *ddev,
return NULL;
}
+static u8 ceanr_get(struct mcde_display_device *ddev)
+{
+ int cnt;
+ int cea;
+ int vesa_cea_nr;
+ struct mcde_video_mode *vmode = &ddev->video_mode;
+ struct mcde_video_mode *vmode_try;
+
+ if (!vmode)
+ return 0;
+
+ dev_dbg(&ddev->dev, "%s\n", __func__);
+
+ for (cnt = 0; cnt < ARRAY_SIZE(cea_vesa_video_mode); cnt++) {
+ vmode_try = cea_vesa_video_mode[cnt].video_mode;
+ cea = cea_vesa_video_mode[cnt].cea;
+ vesa_cea_nr = cea_vesa_video_mode[cnt].vesa_cea_nr;
+
+ if (cea && vmode_try->xres == vmode->xres &&
+ vmode_try->yres == vmode->yres &&
+ vmode_try->pixclock == vmode->pixclock &&
+ vmode_try->hbp == vmode->hbp &&
+ vmode_try->hfp == vmode->hfp &&
+ vmode_try->vbp == vmode->vbp &&
+ vmode_try->vfp == vmode->vfp &&
+ vmode_try->interlaced == vmode->interlaced) {
+ dev_dbg(&ddev->dev, "ceanr:%d\n", vesa_cea_nr);
+ return vesa_cea_nr;
+ }
+ }
+
+ return 0;
+}
+
#define AV8100_MAX_LEVEL 255
static int hdmi_try_video_mode(
@@ -1167,6 +1208,9 @@ static int hdmi_on_first_update(struct mcde_display_device *dev)
{
int ret;
union av8100_configuration av8100_config;
+ u8 *infofr_data;
+ int infofr_crc;
+ int cnt;
dev->first_update = false;
@@ -1235,6 +1279,45 @@ static int hdmi_on_first_update(struct mcde_display_device *dev)
return ret;
}
+ /* AVI Infoframe only if HDMI */
+ if (dev->port->hdmi_sdtv_switch != HDMI_SWITCH)
+ goto hdmi_on_first_update_end;
+
+ /* Create AVI Infoframe */
+ av8100_config.infoframes_format.type = AVI_INFOFRAME_TYPE;
+ av8100_config.infoframes_format.version = AVI_INFOFRAME_VERSION;
+ av8100_config.infoframes_format.length = AVI_INFOFRAME_DATA_SIZE;
+
+ /* AVI Infoframe data */
+ infofr_data = &av8100_config.infoframes_format.data[0];
+ memset(infofr_data, 0, AVI_INFOFRAME_DATA_SIZE);
+ infofr_data[0] = AVI_INFOFRAME_DB1;
+ infofr_data[1] = AVI_INFOFRAME_DB2;
+ infofr_data[3] = ceanr_get(dev);
+
+ /* Calculate AVI Infoframe checksum */
+ infofr_crc = av8100_config.infoframes_format.type +
+ av8100_config.infoframes_format.version +
+ av8100_config.infoframes_format.length;
+ for (cnt = 0; cnt < AVI_INFOFRAME_DATA_SIZE; cnt++)
+ infofr_crc += infofr_data[cnt];
+ infofr_crc &= 0xFF;
+ av8100_config.infoframes_format.crc = 0x100 - infofr_crc;
+
+ /* Send AVI Infoframe */
+ if (av8100_conf_prep(AV8100_COMMAND_INFOFRAMES,
+ &av8100_config) != 0) {
+ dev_err(&dev->dev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_INFOFRAMES,
+ NULL, NULL, I2C_INTERFACE) != 0) {
+ dev_err(&dev->dev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+hdmi_on_first_update_end:
return ret;
}
@@ -1285,7 +1368,10 @@ static int hdmi_set_power_mode(struct mcde_display_device *ddev,
if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY &&
power_mode == MCDE_DISPLAY_PM_OFF) {
memset(&(ddev->video_mode), 0, sizeof(struct mcde_video_mode));
-
+ ret = av8100_powerscan();
+ if (ret)
+ dev_err(&ddev->dev, "%s:av8100_powerscan failed\n"
+ , __func__);
if (ddev->platform_disable) {
ret = ddev->platform_disable(ddev);
if (ret)
@@ -1422,6 +1508,9 @@ static int hdmi_resume(struct mcde_display_device *ddev)
{
int ret;
+ if (ddev->chnl_state == NULL)
+ return 0;
+
/* set_power_mode will handle call platform_enable */
ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
if (ret < 0)
@@ -1435,6 +1524,9 @@ static int hdmi_suspend(struct mcde_display_device *ddev, pm_message_t state)
{
int ret;
+ if (ddev->chnl_state == NULL)
+ return 0;
+
/* set_power_mode will handle call platform_disable */
ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF);
if (ret < 0)
diff --git a/drivers/video/mcde/display-sony_acx424akp_dsi.c b/drivers/video/mcde/display-sony_acx424akp_dsi.c
new file mode 100644
index 00000000000..602c85f229f
--- /dev/null
+++ b/drivers/video/mcde/display-sony_acx424akp_dsi.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE Sony acx424akp DCS display driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+
+#include <video/mcde_display.h>
+#include <video/mcde_display-sony_acx424akp_dsi.h>
+
+static int display_read_deviceid(struct mcde_display_device *dev, u16 *id)
+{
+ struct mcde_chnl_state *chnl;
+
+ u8 id1, id2, id3;
+ int len = 1;
+ int ret = 0;
+ int readret = 0;
+
+ dev_dbg(&dev->dev, "%s: Read device id of the display\n", __func__);
+
+ /* Acquire MCDE resources */
+ chnl = mcde_chnl_get(dev->chnl_id, dev->fifo, dev->port);
+ if (IS_ERR(chnl)) {
+ ret = PTR_ERR(chnl);
+ dev_warn(&dev->dev, "Failed to acquire MCDE channel\n");
+ goto out;
+ }
+
+ /* plugnplay: use registers DA, DBh and DCh to detect display */
+ readret = mcde_dsi_dcs_read(chnl, 0xDA, (u32 *)&id1, &len);
+ if (!readret)
+ readret = mcde_dsi_dcs_read(chnl, 0xDB, (u32 *)&id2, &len);
+ if (!readret)
+ readret = mcde_dsi_dcs_read(chnl, 0xDC, (u32 *)&id3, &len);
+
+ if (readret) {
+ dev_info(&dev->dev,
+ "mcde_dsi_dcs_read failed to read display ID\n");
+ goto read_fail;
+ }
+
+ *id = (id3 << 8) | id2;
+read_fail:
+ /* close MCDE channel */
+ mcde_chnl_put(chnl);
+out:
+ return 0;
+}
+
+static int sony_acx424akp_platform_enable(struct mcde_display_device *dev)
+{
+ struct mcde_display_sony_acx424akp_platform_data *pdata =
+ dev->dev.platform_data;
+
+ dev_dbg(&dev->dev, "%s: Reset & power on sony display\n", __func__);
+
+ if (pdata->regulator) {
+ if (regulator_enable(pdata->regulator) < 0) {
+ dev_err(&dev->dev, "%s:Failed to enable regulator\n"
+ , __func__);
+ return -EINVAL;
+ }
+ }
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, pdata->reset_high);
+ msleep(pdata->reset_delay); /* as per sony lcd spec */
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, !pdata->reset_high);
+ msleep(pdata->reset_low_delay); /* as per sony lcd spec */
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, pdata->reset_high);
+ msleep(pdata->reset_delay); /* as per sony lcd spec */
+
+ return 0;
+}
+
+static int sony_acx424akp_platform_disable(struct mcde_display_device *dev)
+{
+ struct mcde_display_sony_acx424akp_platform_data *pdata =
+ dev->dev.platform_data;
+
+ dev_dbg(&dev->dev, "%s:Reset & power off sony display\n", __func__);
+
+ if (pdata->regulator) {
+ if (regulator_disable(pdata->regulator) < 0) {
+ dev_err(&dev->dev, "%s:Failed to disable regulator\n"
+ , __func__);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int sony_acx424akp_set_scan_mode(struct mcde_display_device *ddev,
+ enum mcde_display_power_mode power_mode)
+{
+ int ret = 0;
+ u8 param[MCDE_MAX_DSI_DIRECT_CMD_WRITE];
+
+ dev_dbg(&ddev->dev, "%s:Set Power mode\n", __func__);
+
+ /* 180 rotation for SONY ACX424AKP display */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY) {
+ param[0] = 0xAA;
+ ret = mcde_dsi_dcs_write(ddev->chnl_state, 0xf3, param, 1);
+ if (ret)
+ return ret;
+
+ param[0] = 0x00;
+ param[1] = 0x00;
+ ret = mcde_dsi_generic_write(ddev->chnl_state, param, 3);
+ if (ret)
+ return ret;
+
+ param[0] = 0xC9;
+ param[1] = 0x01;
+ ret = mcde_dsi_generic_write(ddev->chnl_state, param, 3);
+ if (ret)
+ return ret;
+
+ param[0] = 0xA2;
+ param[1] = 0x00;
+ ret = mcde_dsi_generic_write(ddev->chnl_state, param, 3);
+ if (ret)
+ return ret;
+
+ param[0] = 0xFF;
+ param[1] = 0xAA;
+ ret = mcde_dsi_generic_write(ddev->chnl_state, param, 3);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static int sony_acx424akp_set_power_mode(struct mcde_display_device *ddev,
+ enum mcde_display_power_mode power_mode)
+{
+ int ret = 0;
+ struct mcde_display_sony_acx424akp_platform_data *pdata =
+ ddev->dev.platform_data;
+
+ dev_dbg(&ddev->dev, "%s:Set Power mode\n", __func__);
+
+ /* OFF -> STANDBY */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_OFF &&
+ power_mode != MCDE_DISPLAY_PM_OFF) {
+
+ if (ddev->platform_enable) {
+ ret = ddev->platform_enable(ddev);
+ if (ret)
+ return ret;
+ }
+
+ ddev->power_mode = MCDE_DISPLAY_PM_STANDBY;
+ }
+
+ /* STANDBY -> ON */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY &&
+ power_mode == MCDE_DISPLAY_PM_ON) {
+
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_EXIT_SLEEP_MODE, NULL, 0);
+ if (ret)
+ return ret;
+
+ msleep(pdata->sleep_out_delay);
+
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_SET_DISPLAY_ON, NULL, 0);
+ if (ret)
+ return ret;
+
+ ddev->power_mode = MCDE_DISPLAY_PM_ON;
+ goto set_power_and_exit;
+ }
+ /* ON -> STANDBY */
+ else if (ddev->power_mode == MCDE_DISPLAY_PM_ON &&
+ power_mode <= MCDE_DISPLAY_PM_STANDBY) {
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_SET_DISPLAY_OFF, NULL, 0);
+ if (ret)
+ return ret;
+
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_ENTER_SLEEP_MODE, NULL, 0);
+ if (ret)
+ return ret;
+
+ ddev->power_mode = MCDE_DISPLAY_PM_STANDBY;
+ }
+
+ /* SLEEP -> OFF */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY &&
+ power_mode == MCDE_DISPLAY_PM_OFF) {
+ if (ddev->platform_disable) {
+ ret = ddev->platform_disable(ddev);
+ if (ret)
+ return ret;
+ }
+ ddev->power_mode = MCDE_DISPLAY_PM_OFF;
+ }
+
+set_power_and_exit:
+ mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode);
+ ret = sony_acx424akp_set_scan_mode(ddev, power_mode);
+
+ return ret;
+}
+
+static int __devinit sony_acx424akp_probe(struct mcde_display_device *dev)
+{
+ int ret = 0;
+ u16 id;
+ struct mcde_display_sony_acx424akp_platform_data *pdata =
+ dev->dev.platform_data;
+
+ if (pdata == NULL) {
+ dev_err(&dev->dev, "%s:Platform data missing\n", __func__);
+ return -EINVAL;
+ }
+
+ if (dev->port->type != MCDE_PORTTYPE_DSI) {
+ dev_err(&dev->dev,
+ "%s:Invalid port type %d\n",
+ __func__, dev->port->type);
+ return -EINVAL;
+ }
+
+ if (!dev->platform_enable && !dev->platform_disable) {
+ pdata->sony_acx424akp_platform_enable = true;
+ if (pdata->reset_gpio) {
+ ret = gpio_request(pdata->reset_gpio, NULL);
+ if (ret) {
+ dev_warn(&dev->dev,
+ "%s:Failed to request gpio %d\n",
+ __func__, pdata->reset_gpio);
+ goto gpio_request_failed;
+ }
+ gpio_direction_output(pdata->reset_gpio,
+ !pdata->reset_high);
+ }
+ if (pdata->regulator_id) {
+ pdata->regulator = regulator_get(NULL,
+ pdata->regulator_id);
+ if (IS_ERR(pdata->regulator)) {
+ ret = PTR_ERR(pdata->regulator);
+ dev_warn(&dev->dev,
+ "%s:Failed to get regulator '%s'\n",
+ __func__, pdata->regulator_id);
+ pdata->regulator = NULL;
+ goto regulator_get_failed;
+ }
+ 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;
+ }
+ }
+ }
+ }
+
+ /* TODO: Remove when DSI send command uses interrupts */
+ dev->prepare_for_update = NULL;
+ dev->platform_enable = sony_acx424akp_platform_enable,
+ dev->platform_disable = sony_acx424akp_platform_disable,
+ dev->set_power_mode = sony_acx424akp_set_power_mode;
+
+ ret = display_read_deviceid(dev, &id);
+
+ switch (id) {
+ case DISPLAY_SONY_ACX424AKP:
+ pdata->disp_panel = DISPLAY_SONY_ACX424AKP;
+ dev_info(&dev->dev, "Sony ACX424AKP display (ID 0x%.4X) \
+ probed\n", id);
+ goto out;
+
+ default:
+ pdata->disp_panel = DISPLAY_NONE;
+ dev_warn(&dev->dev, "Display not recognized\n");
+ break;
+ }
+
+regulator_enable_failed:
+regulator_get_failed:
+ if (pdata->sony_acx424akp_platform_enable && pdata->reset_gpio)
+ gpio_free(pdata->reset_gpio);
+gpio_request_failed:
+out:
+ return ret;
+}
+
+static int __devexit sony_acx424akp_remove(struct mcde_display_device *dev)
+{
+ struct mcde_display_sony_acx424akp_platform_data *pdata =
+ dev->dev.platform_data;
+
+ dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF);
+
+ if (!pdata->sony_acx424akp_platform_enable)
+ return 0;
+
+ if (pdata->regulator)
+ regulator_put(pdata->regulator);
+ if (pdata->reset_gpio) {
+ gpio_direction_input(pdata->reset_gpio);
+ gpio_free(pdata->reset_gpio);
+ }
+
+ return 0;
+}
+
+#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM)
+static int sony_acx424akp_resume(struct mcde_display_device *ddev)
+{
+ int ret;
+
+ /* set_power_mode will handle call platform_enable */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "%s:Failed to resume display\n"
+ , __func__);
+ ddev->set_synchronized_update(ddev,
+ ddev->get_synchronized_update(ddev));
+ return ret;
+}
+
+static int sony_acx424akp_suspend(struct mcde_display_device *ddev, \
+ pm_message_t state)
+{
+ int ret;
+
+ /* set_power_mode will handle call platform_disable */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "%s:Failed to suspend display\n"
+ , __func__);
+ return ret;
+}
+#endif
+
+static struct mcde_display_driver sony_acx424akp_driver = {
+ .probe = sony_acx424akp_probe,
+ .remove = sony_acx424akp_remove,
+#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM)
+ .suspend = sony_acx424akp_suspend,
+ .resume = sony_acx424akp_resume,
+#else
+ .suspend = NULL,
+ .resume = NULL,
+#endif
+ .driver = {
+ .name = "mcde_disp_sony_acx424akp",
+ },
+};
+
+/* Module init */
+static int __init mcde_display_sony_acx424akp_init(void)
+{
+ pr_info("%s\n", __func__);
+
+ return mcde_display_driver_register(&sony_acx424akp_driver);
+}
+module_init(mcde_display_sony_acx424akp_init);
+
+static void __exit mcde_display_sony_acx424akp_exit(void)
+{
+ pr_info("%s\n", __func__);
+
+ mcde_display_driver_unregister(&sony_acx424akp_driver);
+}
+module_exit(mcde_display_sony_acx424akp_exit);
+
+MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson MCDE Sony ACX424AKP DCS display driver");
diff --git a/drivers/video/mcde/dsilink_regs.h b/drivers/video/mcde/dsilink_regs.h
index 2322041ffec..29fa75a1752 100644
--- a/drivers/video/mcde/dsilink_regs.h
+++ b/drivers/video/mcde/dsilink_regs.h
@@ -474,6 +474,7 @@
#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_1 21
#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_LONG_WRITE 57
#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_READ 6
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SET_MAX_PKT_SIZE 55
#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(__x) \
DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_HEAD, \
DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_##__x)
diff --git a/drivers/video/mcde/mcde_bus.c b/drivers/video/mcde/mcde_bus.c
index 3d7049652a1..a742aea5b3d 100644
--- a/drivers/video/mcde/mcde_bus.c
+++ b/drivers/video/mcde/mcde_bus.c
@@ -30,14 +30,14 @@ struct bus_type mcde_bus_type;
static int mcde_suspend_device(struct device *dev, void *data)
{
pm_message_t* state = (pm_message_t *) data;
- if (dev->driver->suspend)
+ if (dev->driver && dev->driver->suspend)
return dev->driver->suspend(dev, *state);
return 0;
}
static int mcde_resume_device(struct device *dev, void *data)
{
- if (dev->driver->resume)
+ if (dev->driver && dev->driver->resume)
return dev->driver->resume(dev);
return 0;
}
diff --git a/drivers/video/mcde/mcde_fb.c b/drivers/video/mcde/mcde_fb.c
index 628b10953f6..332e371d54b 100644
--- a/drivers/video/mcde/mcde_fb.c
+++ b/drivers/video/mcde/mcde_fb.c
@@ -485,6 +485,8 @@ static int apply_var(struct fb_info *fbi, struct mcde_display_device *ddev)
var = &fbi->var;
+ ddev->check_transparency = 60;
+
/* Reallocate memory */
line_len = (fbi->var.bits_per_pixel * var->xres_virtual) / 8;
line_len = ALIGN(line_len, MCDE_BUF_LINE_ALIGMENT);
@@ -564,31 +566,47 @@ static int mcde_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
static int mcde_fb_set_par(struct fb_info *fbi)
{
+ struct mcde_fb *mfb = to_mcde_fb(fbi);
+ struct mcde_display_device *ddev = fb_to_display(fbi);
dev_vdbg(fbi->dev, "%s\n", __func__);
- return apply_var(fbi, fb_to_display(fbi));
-}
-
-static int mcde_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *fbi)
-{
- dev_vdbg(fbi->dev, "%s\n", __func__);
+ if (mfb->ovlys[0]->state == NULL &&
+ ddev->fictive == false) {
+ printk(KERN_INFO "%s() - Enable fb %p\n",
+ __func__,
+ mfb->ovlys[0]);
+ mcde_dss_enable_overlay(mfb->ovlys[0]);
+ }
- /*Nothing to see here, move along*/
- return 0;
+ return apply_var(fbi, ddev);
}
-static int mcde_fb_setcmap(struct fb_cmap *cmap, struct fb_info *fbi)
+static int mcde_fb_blank(int blank, struct fb_info *fbi)
{
+ int ret = 0;
+ struct mcde_display_device *ddev = fb_to_display(fbi);
+
dev_vdbg(fbi->dev, "%s\n", __func__);
- /*Nothing to see here, move along*/
- return 0;
-}
+ if (ddev->fictive)
+ goto mcde_fb_blank_end;
+
+ switch (blank) {
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+ mcde_dss_disable_display(ddev);
+ break;
+ case FB_BLANK_UNBLANK:
+ ret = mcde_dss_enable_display(ddev);
+ break;
+ default:
+ ret = -EINVAL;
+ }
-static int mcde_fb_blank(int blank, struct fb_info *fbi)
-{
- return 0;
+mcde_fb_blank_end:
+ return ret;
}
static int mcde_fb_pan_display(struct fb_var_screeninfo *var,
@@ -633,8 +651,6 @@ static struct fb_ops fb_ops = {
.fb_imageblit = sys_imageblit,
.fb_check_var = mcde_fb_check_var,
.fb_set_par = mcde_fb_set_par,
- .fb_setcolreg = mcde_fb_setcolreg,
- .fb_setcmap = mcde_fb_setcmap,
.fb_blank = mcde_fb_blank,
.fb_pan_display = mcde_fb_pan_display,
.fb_rotate = mcde_fb_rotate,
@@ -711,10 +727,6 @@ struct fb_info *mcde_fb_create(struct mcde_display_device *ddev,
if (ret)
goto fb_register_failed;
- ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
- if (ret)
- dev_warn(&ddev->dev, "%s: Allocate color map memory failed!\n", __func__);
-
ddev->fbi = fbi;
#ifdef CONFIG_HAS_EARLYSUSPEND
@@ -771,10 +783,9 @@ void mcde_fb_destroy(struct mcde_display_device *dev)
mcde_dss_destroy_overlay(mfb->ovlys[i]);
}
- fb_dealloc_cmap(&dev->fbi->cmap);
-
#ifdef CONFIG_HAS_EARLYSUSPEND
- unregister_early_suspend(&mfb->early_suspend);
+ if (dev->fictive == false)
+ unregister_early_suspend(&mfb->early_suspend);
#endif
unregister_framebuffer(dev->fbi);
free_fb_mem(dev->fbi);
diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c
index 585b22f9111..4653f148b7f 100644
--- a/drivers/video/mcde/mcde_hw.c
+++ b/drivers/video/mcde/mcde_hw.c
@@ -32,6 +32,7 @@
static void disable_channel(struct mcde_chnl_state *chnl);
static void watchdog_auto_sync_timer_function(unsigned long arg);
+static int _mcde_chnl_enable(struct mcde_chnl_state *chnl);
static int _mcde_chnl_apply(struct mcde_chnl_state *chnl);
static void disable_flow(struct mcde_chnl_state *chnl);
static void enable_channel(struct mcde_chnl_state *chnl);
@@ -654,7 +655,8 @@ static void dpi_video_mode_apply(struct mcde_chnl_state *chnl)
chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P_BE;
else
chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P;
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8)
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4)
chnl->tv_regs.inv_clk = true;
else {
chnl->tv_regs.dho = MCDE_CONFIG_TVOUT_HBORDER;
@@ -720,7 +722,8 @@ static void update_dpi_registers(enum mcde_chnl chnl_id, struct tv_regs *regs)
/* Horizontal timing registers */
if (!regs->sel_mode_tv ||
- hardware_version == MCDE_CHIP_VERSION_3_0_8) {
+ hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4) {
mcde_wreg(MCDE_TVLBALWA + idx * MCDE_TVLBALWA_GROUPOFFSET,
MCDE_TVLBALWA_LBW(regs->hsw) |
MCDE_TVLBALWA_ALW(regs->alw));
@@ -898,14 +901,16 @@ static inline void mcde_handle_vcmp(struct mcde_chnl_state *chnl, u32 int_fld)
chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
chnl->port.type == MCDE_PORTTYPE_DSI &&
chnl->continous_running) {
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8)
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4)
enable_channel(chnl);
mcde_wreg(MCDE_CHNL0SYNCHSW +
chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
MCDE_CHNL0SYNCHSW_SW_TRIG(true));
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8)
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4)
disable_flow(chnl);
mod_timer(&chnl->auto_sync_timer,
jiffies +
@@ -1025,7 +1030,8 @@ static irqreturn_t mcde_irq_handler(int irq, void *dev)
irq_status = dsi_rfld(i, DSI_DIRECT_CMD_STS_FLAG,
TE_RECEIVED_FLAG);
if (irq_status) {
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8)
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4)
disable_flow(chnl_from_dsi);
dsi_wreg(i, DSI_DIRECT_CMD_STS_CLR,
DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR(true));
@@ -1037,7 +1043,8 @@ 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) {
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8)
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4)
disable_flow(chnl_from_dsi);
dsi_wreg(i, DSI_CMD_MODE_STS_CLR,
DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR(true));
@@ -1130,7 +1137,8 @@ static int update_channel_static_registers(struct mcde_chnl_state *chnl)
(port->sync_src == MCDE_SYNCSRC_TE1))
mcde_wreg(MCDE_CTRLC1, MCDE_CTRLC1_FIFOWTRMRK(
get_output_fifo_size(MCDE_FIFO_C1)));
- } else if (hardware_version == MCDE_CHIP_VERSION_3_0_8) {
+ } else if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4) {
switch (chnl->fifo) {
case MCDE_FIFO_A:
mcde_wreg(MCDE_CHNL0MUXING_V2 + chnl->id *
@@ -1480,6 +1488,18 @@ static void chnl_ovly_pixel_format_apply(struct mcde_chnl_state *chnl,
mcde_chnl_col_convert_apply(chnl, &chnl->rgb_2_ycbcr);
else
mcde_chnl_col_convert_apply(chnl, &crycb_2_ycbcr);
+ } else if (port->type == MCDE_PORTTYPE_DPI) {
+ /* Note: YUV is not support port pixel format for DPI */
+ if (ovly->pix_fmt != MCDE_OVLYPIXFMT_YCbCr422) {
+ /* standard case: DPI: RGB -> RGB */
+ regs->col_conv = MCDE_OVL0CR_COLCCTRL_DISABLED;
+ } else {
+ /* DPI: YUV -> RGB */
+ regs->col_conv =
+ MCDE_OVL0CR_COLCCTRL_ENABLED_SAT;
+ mcde_chnl_col_convert_apply(chnl,
+ &chnl->ycbcr_2_rgb);
+ }
}
}
@@ -1611,7 +1631,8 @@ static void do_softwaretrig(struct mcde_chnl_state *chnl)
* However FLOWEN must not be triggered before SOFTWARE TRIG
* if rotation is enabled
*/
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8)
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4)
enable_channel(chnl);
else if ((!is_channel_enabled(chnl) && !chnl->regs.roten)
|| chnl->power_mode != MCDE_DISPLAY_PM_ON)
@@ -1621,7 +1642,8 @@ static void do_softwaretrig(struct mcde_chnl_state *chnl)
chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
MCDE_CHNL0SYNCHSW_SW_TRIG(true));
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8)
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4)
disable_flow(chnl);
else
enable_channel(chnl);
@@ -2116,17 +2138,18 @@ static int enable_mcde_hw(void)
return 0;
}
+#define DSI_WRITE_CMD_TIMEOUT 1000
+
/* DSI */
static int mcde_dsi_direct_cmd_write(struct mcde_chnl_state *chnl,
bool dcs, u8 cmd, u8 *data, int len)
{
- int i;
+ int i, ret = 0;
u32 wrdat[4] = { 0, 0, 0, 0 };
u32 settings;
u8 link = chnl->port.link;
u8 virt_id = chnl->port.phy.dsi.virt_id;
- u32 ok;
- u32 error;
+ u32 counter = DSI_WRITE_CMD_TIMEOUT;
if (len > MCDE_MAX_DSI_DIRECT_CMD_WRITE ||
chnl->port.type != MCDE_PORTTYPE_DSI)
@@ -2134,6 +2157,7 @@ static int mcde_dsi_direct_cmd_write(struct mcde_chnl_state *chnl,
mutex_lock(&mcde_hw_lock);
+ _mcde_chnl_enable(chnl);
if (enable_mcde_hw()) {
mutex_unlock(&mcde_hw_lock);
return -EINVAL;
@@ -2193,21 +2217,35 @@ static int mcde_dsi_direct_cmd_write(struct mcde_chnl_state *chnl,
if (len > 11)
dsi_wreg(link, DSI_DIRECT_CMD_WRDAT3, wrdat[3]);
dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0);
+ dsi_wreg(link, DSI_CMD_MODE_STS_CLR, ~0);
dsi_wreg(link, DSI_DIRECT_CMD_SEND, true);
- /* TODO: irq wait and error check */
- mdelay(10);
+ /* loop will normally run zero or one time until WRITE_COMPLETED */
+ while (!dsi_rfld(link, DSI_DIRECT_CMD_STS, WRITE_COMPLETED)
+ && --counter)
+ cpu_relax();
- ok = dsi_rreg(link, DSI_DIRECT_CMD_STS);
- error = dsi_rreg(link, DSI_CMD_MODE_STS);
- dev_vdbg(&mcde_dev->dev, "DSI Write ok %x error %x\n", ok, error);
+ if (!counter) {
+ dev_err(&mcde_dev->dev,
+ "%s: DSI write cmd 0x%x timeout on DSI link %u!\n",
+ __func__, cmd, link);
+ ret = -ETIME;
+ } else {
+ /* inform if >100 loops before command completion */
+ if (counter < (DSI_WRITE_CMD_TIMEOUT-DSI_WRITE_CMD_TIMEOUT/10))
+ dev_vdbg(&mcde_dev->dev,
+ "%s: %u loops for DSI command %x completion\n",
+ __func__, (DSI_WRITE_CMD_TIMEOUT - counter),
+ cmd);
- dsi_wreg(link, DSI_CMD_MODE_STS_CLR, ~0);
- dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0);
+ dev_vdbg(&mcde_dev->dev, "DSI Write ok %x error %x\n",
+ dsi_rreg(link, DSI_DIRECT_CMD_STS_FLAG),
+ dsi_rreg(link, DSI_CMD_MODE_STS_FLAG));
+ }
mutex_unlock(&mcde_hw_lock);
- return 0;
+ return ret;
}
int mcde_dsi_generic_write(struct mcde_chnl_state *chnl, u8* para, int len)
@@ -2220,7 +2258,8 @@ int mcde_dsi_dcs_write(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int len)
return mcde_dsi_direct_cmd_write(chnl, true, cmd, data, len);
}
-int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int *len)
+int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl,
+ u8 cmd, u32 *data, int *len)
{
int ret = 0;
u8 link = chnl->port.link;
@@ -2234,6 +2273,7 @@ int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int *len)
mutex_lock(&mcde_hw_lock);
+ _mcde_chnl_enable(chnl);
if (enable_mcde_hw()) {
mutex_unlock(&mcde_hw_lock);
return -EINVAL;
@@ -2288,6 +2328,61 @@ int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int *len)
return ret;
}
+/*
+ * Set Maximum Return Packet size is a command that specifies the
+ * maximum size of the payload transmitted from peripheral back to
+ * the host processor.
+ *
+ * During power-on or reset sequence, the Maximum Return Packet Size
+ * is set to a default value of one. In order to be able to use
+ * mcde_dsi_dcs_read for reading more than 1 byte at a time, this
+ * parameter should be set by the host processor to the desired value
+ * in the initialization routine before commencing normal operation.
+ */
+int mcde_dsi_set_max_pkt_size(struct mcde_chnl_state *chnl, int size)
+{
+ u32 settings;
+ u8 link = chnl->port.link;
+ u8 virt_id = chnl->port.phy.dsi.virt_id;
+
+ if (chnl->port.type != MCDE_PORTTYPE_DSI)
+ return -EINVAL;
+
+ if (size > 4)
+ return -EINVAL;
+
+ mutex_lock(&mcde_hw_lock);
+
+ if (enable_mcde_hw()) {
+ mutex_unlock(&mcde_hw_lock);
+ return -EINVAL;
+ }
+
+ /*
+ * Set Maximum Return Packet Size is a four-byte command packet
+ * (including ECC) that specifies the maximum size of the payload.
+ * The order of bytes is:
+ * Data ID, two-byte value for maximum return packet size,
+ * followed by the ECC byte.
+ */
+
+ settings = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(WRITE) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(1) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(virt_id) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(size) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(true);
+ settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(
+ SET_MAX_PKT_SIZE);
+ dsi_wreg(link, DSI_DIRECT_CMD_MAIN_SETTINGS, settings);
+ dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0);
+ dsi_wreg(link, DSI_DIRECT_CMD_SEND, true);
+
+ dsi_wreg(link, DSI_CMD_MODE_STS_CLR, ~0);
+ dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0);
+
+ mutex_unlock(&mcde_hw_lock);
+ return 0;
+}
static void dsi_te_poll_req(struct mcde_chnl_state *chnl)
{
@@ -2562,7 +2657,8 @@ static void chnl_update_continous(struct mcde_chnl_state *chnl,
if (chnl->port.sync_src == MCDE_SYNCSRC_TE0) {
mcde_wfld(MCDE_CRC, SYCEN0, true);
} else if (chnl->port.sync_src == MCDE_SYNCSRC_TE1) {
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8) {
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4) {
mcde_wfld(MCDE_VSCRC1, VSSEL, 1);
mcde_wfld(MCDE_CRC, SYCEN1, true);
} else {
@@ -2582,7 +2678,8 @@ static void chnl_update_continous(struct mcde_chnl_state *chnl,
if (chnl->port.type == MCDE_PORTTYPE_DSI &&
chnl->port.sync_src == MCDE_SYNCSRC_OFF) {
chnl->disable_software_trig = false;
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8) {
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4) {
mcde_wreg(MCDE_CHNL0SYNCHSW +
chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
MCDE_CHNL0SYNCHSW_SW_TRIG(true));
@@ -2607,7 +2704,8 @@ static void chnl_update_non_continous(struct mcde_chnl_state *chnl)
chnl->power_mode == MCDE_DISPLAY_PM_ON) {
if (chnl->port.type == MCDE_PORTTYPE_DSI &&
chnl->port.sync_src == MCDE_SYNCSRC_BTA) {
- if (hardware_version == MCDE_CHIP_VERSION_3_0_8)
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8 ||
+ hardware_version == MCDE_CHIP_VERSION_4_0_4)
enable_channel(chnl);
wait_while_dsi_running(chnl->port.link);
dsi_te_request(chnl);
@@ -2633,6 +2731,8 @@ static void chnl_update_overlay(struct mcde_chnl_state *chnl,
chnl->fifo, chnl->regs.x, chnl->regs.y,
chnl->regs.ppl, chnl->regs.lpf, ovly->stride,
chnl->vmode.interlaced, chnl->rotation);
+ if (chnl->id == MCDE_CHNL_A || chnl->id == MCDE_CHNL_B)
+ update_col_registers(chnl->id, &chnl->col_regs);
}
}
@@ -2678,6 +2778,13 @@ static int _mcde_chnl_update(struct mcde_chnl_state *chnl,
return 0;
}
+static int _mcde_chnl_enable(struct mcde_chnl_state *chnl)
+{
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+ chnl->enabled = true;
+ return 0;
+}
+
/* API entry points */
/* MCDE channels */
struct mcde_chnl_state *mcde_chnl_get(enum mcde_chnl chnl_id,
@@ -2928,7 +3035,7 @@ void mcde_chnl_enable(struct mcde_chnl_state *chnl)
dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
mutex_lock(&mcde_hw_lock);
- chnl->enabled = true;
+ _mcde_chnl_enable(chnl);
mutex_unlock(&mcde_hw_lock);
dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__);
@@ -3209,8 +3316,6 @@ static int init_clocks_and_power(struct platform_device *pdev)
} else {
dev_dbg(&pdev->dev, "%s: No regulator id supplied\n",
__func__);
- ret = -EINVAL;
- goto regulator_vana_err;
}
#endif
@@ -3421,7 +3526,13 @@ static int __devinit mcde_probe(struct platform_device *pdev)
development_version >= 4) {
hardware_version = MCDE_CHIP_VERSION_1_0_4;
mcde_dynamic_power_management = false;
+ num_channels = 2;
+ num_overlays = 3;
dev_info(&mcde_dev->dev, "V1_U5500 HW\n");
+ } else if (major_version == 4 && minor_version == 0 &&
+ development_version >= 4) {
+ hardware_version = MCDE_CHIP_VERSION_4_0_4;
+ dev_info(&mcde_dev->dev, "V2_U5500 HW\n");
} else {
dev_err(&mcde_dev->dev, "Unsupported HW version\n");
ret = -ENOTSUPP;
@@ -3458,6 +3569,7 @@ static int __devinit mcde_probe(struct platform_device *pdev)
init_timer(&channels[i].auto_sync_timer);
channels[i].auto_sync_timer.function =
watchdog_auto_sync_timer_function;
+
init_timer(&channels[i].dsi_te_timer);
channels[i].dsi_te_timer.function =
dsi_te_timer_function;
@@ -3467,7 +3579,6 @@ static int __devinit mcde_probe(struct platform_device *pdev)
return 0;
failed_hardware_version:
- free_irq(mcde_irq, &pdev->dev);
failed_request_irq:
disable_mcde_hw(true);
failed_enable_clocks:
@@ -3492,6 +3603,8 @@ failed_overlays_alloc:
kfree(channels);
channels = NULL;
failed_channels_alloc:
+ num_channels = 0;
+ num_overlays = 0;
return ret;
}
@@ -3570,7 +3683,6 @@ static struct platform_driver mcde_driver = {
int __init mcde_init(void)
{
mutex_init(&mcde_hw_lock);
-
return platform_driver_register(&mcde_driver);
}
diff --git a/include/video/mcde.h b/include/video/mcde.h
index 213f33e43fe..75992bf7d57 100644
--- a/include/video/mcde.h
+++ b/include/video/mcde.h
@@ -236,7 +236,7 @@ enum mcde_display_rotation {
#define MCDE_FIFO_AB_SIZE 640
#define MCDE_FIFO_C0C1_SIZE 160
-#define MCDE_PIXFETCH_LARGE_WTRMRKLVL 128
+#define MCDE_PIXFETCH_LARGE_WTRMRKLVL 256
#define MCDE_PIXFETCH_MEDIUM_WTRMRKLVL 64
#define MCDE_PIXFETCH_SMALL_WTRMRKLVL 16
@@ -251,6 +251,7 @@ enum mcde_display_rotation {
#define MCDE_AUTO_SYNC_WATCHDOG 5
/* Hardware versions */
+#define MCDE_CHIP_VERSION_4_0_4 4 /* U5500 V2 */
#define MCDE_CHIP_VERSION_1_0_4 3 /* U5500 V1 */
#define MCDE_CHIP_VERSION_3_0_8 2 /* U8500 V2 */
#define MCDE_CHIP_VERSION_3_0_5 1 /* U8500 V1 */
@@ -412,8 +413,11 @@ void mcde_ovly_put(struct mcde_ovly_state *ovly);
#define MCDE_MAX_DSI_DIRECT_CMD_WRITE 15
int mcde_dsi_generic_write(struct mcde_chnl_state *chnl, u8* para, int len);
-int mcde_dsi_dcs_write(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int len);
-int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int *len);
+int mcde_dsi_dcs_write(struct mcde_chnl_state *chnl,
+ u8 cmd, u8 *data, int len);
+int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl,
+ u8 cmd, u32 *data, int *len);
+int mcde_dsi_set_max_pkt_size(struct mcde_chnl_state *chnl, int size);
/* MCDE */
diff --git a/include/video/mcde_display-sony_acx424akp_dsi.h b/include/video/mcde_display-sony_acx424akp_dsi.h
new file mode 100644
index 00000000000..de862a3f28b
--- /dev/null
+++ b/include/video/mcde_display-sony_acx424akp_dsi.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE Sony acx424akp DCS display driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __MCDE_DISPLAY_SONY_ACX424AKP__H__
+#define __MCDE_DISPLAY_SONY_ACX424AKP__H__
+
+#include <linux/regulator/consumer.h>
+
+#include "mcde_display.h"
+
+enum display_panel_type {
+ DISPLAY_NONE = 0,
+ DISPLAY_SONY_ACX424AKP = 0x1b81,
+};
+
+struct mcde_display_sony_acx424akp_platform_data {
+ /* Platform info */
+ int reset_gpio;
+ bool reset_high;
+ const char *regulator_id;
+ int reset_delay; /* ms */
+ int reset_low_delay; /* ms */
+ int sleep_out_delay; /* ms */
+ enum display_panel_type disp_panel; /* display panel types */
+
+ /* Driver data */
+ bool sony_acx424akp_platform_enable;
+ struct regulator *regulator;
+ int max_supply_voltage;
+ int min_supply_voltage;
+};
+
+#endif /* __MCDE_DISPLAY_SONY_ACX424AKP__H__ */
+
diff --git a/include/video/mcde_display.h b/include/video/mcde_display.h
index a5e449f6b5b..6519660f489 100644
--- a/include/video/mcde_display.h
+++ b/include/video/mcde_display.h
@@ -60,6 +60,7 @@ struct mcde_display_device {
struct mcde_video_mode video_mode;
int update_flags;
bool stay_alive;
+ int check_transparency;
/* Driver API */
void (*get_native_resolution)(struct mcde_display_device *dev,