summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Langlais <philippe.langlais@linaro.org>2011-05-10 17:03:27 +0200
committerUlf Hansson <ulf.hansson@stericsson.com>2011-09-19 15:15:12 +0200
commit5626e5cbf17b1030a1aba01b88bd43ff00739dc2 (patch)
tree3768caa3a23de09e88d8fc77e0729a9cca2423ef
parent74e820748f73001531a9603b74c029878b5d0451 (diff)
video: av8100: Add HDMI support for U5500
This patch adds support for HDMI on S5500 devices. Trig method I2SDAT3 is used. ST-Ericsson ID: 254484 ST-Ericsson Linux next: Not tested, ER 282779 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Iddda36e2c03bf09641800e652040aae104f27e27 Signed-off-by: Jimmy Rubin <jimmy.rubin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/21580 Reviewed-by: QATOOLS Reviewed-by: QATEST Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com> Conflicts: arch/arm/mach-ux500/board-mop500.c arch/arm/mach-ux500/board-u5500-mcde.c arch/arm/mach-ux500/board-u5500.c
-rw-r--r--arch/arm/mach-ux500/Kconfig-arch2
-rw-r--r--arch/arm/mach-ux500/board-mop500.c1
-rw-r--r--arch/arm/mach-ux500/board-u5500-mcde.c198
-rw-r--r--arch/arm/mach-ux500/board-u5500.c14
-rw-r--r--arch/arm/mach-ux500/prcmu-db5500.c2
-rw-r--r--drivers/video/av8100/av8100.c12
-rw-r--r--drivers/video/mcde/mcde_hw.c13
-rw-r--r--include/video/av8100.h1
8 files changed, 210 insertions, 33 deletions
diff --git a/arch/arm/mach-ux500/Kconfig-arch b/arch/arm/mach-ux500/Kconfig-arch
index 596399284ad..cfdf0ea1265 100644
--- a/arch/arm/mach-ux500/Kconfig-arch
+++ b/arch/arm/mach-ux500/Kconfig-arch
@@ -138,7 +138,7 @@ config DISPLAY_AB8500_TERTIARY
config DISPLAY_AV8100_TERTIARY
bool "AV8100 HDMI/CVBS display support"
- depends on MACH_U8500
+ depends on (MACH_U8500_MOP || MACH_U5500)
select MCDE_DISPLAY_AV8100
help
Say yes here if HDMI output support
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index a053246dec6..c5c565eb1bc 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -309,6 +309,7 @@ static struct av8100_platform_data av8100_plat_data = {
.inputclk_id = "sysclk2",
.regulator_pwr_id = "hdmi_1v8",
.alt_powerupseq = true,
+ .mclk_freq = 3, /* MCLK_RNG_31_38 */
};
diff --git a/arch/arm/mach-ux500/board-u5500-mcde.c b/arch/arm/mach-ux500/board-u5500-mcde.c
index 5570f5fd990..2568b0cf183 100644
--- a/arch/arm/mach-ux500/board-u5500-mcde.c
+++ b/arch/arm/mach-ux500/board-u5500-mcde.c
@@ -10,18 +10,30 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/delay.h>
+#include <video/av8100.h>
#include <asm/mach-types.h>
#include <video/mcde_display.h>
#include <video/mcde_display-generic_dsi.h>
+#include <video/mcde_display-av8100.h>
#include <video/mcde_fb.h>
#include <video/mcde_dss.h>
#define DSI_UNIT_INTERVAL_0 0xA
+#define DSI_UNIT_INTERVAL_2 0x5
+
#define PRIMARY_DISPLAY_ID 0
+#define TERTIARY_DISPLAY_ID 1
#ifdef CONFIG_FB_MCDE
-static struct fb_info *fbs[2] = { NULL, NULL };
-static struct mcde_display_device *displays[2] = { NULL, NULL };
+
+/* The initialization of hdmi disp driver must be delayed in order to
+ * ensure that inputclk will be available (needed by hdmi hw) */
+#ifdef CONFIG_DISPLAY_AV8100_TERTIARY
+static struct delayed_work work_dispreg_hdmi;
+#define DISPREG_HDMI_DELAY 6000
+#endif
+
+#define MCDE_NR_OF_DISPLAYS 2
static int display_initialized_during_boot;
static int __init startup_graphics_setup(char *str)
@@ -74,7 +86,7 @@ struct mcde_display_generic_platform_data u5500_generic_display0_pdata = {
.reset_delay = 10,
.sleep_out_delay = 140,
#ifdef CONFIG_REGULATOR
- .regulator_id = "ldo-h",
+ .regulator_id = "v-display",
.min_supply_voltage = 2500000, /* 2.5V */
.max_supply_voltage = 2700000 /* 2.7V */
#endif
@@ -107,6 +119,78 @@ struct mcde_display_device u5500_generic_display0 = {
};
#endif /* CONFIG_DISPLAY_GENERIC_DSI_PRIMARY */
+#ifdef CONFIG_DISPLAY_AV8100_TERTIARY
+static struct mcde_port port2 = {
+ .type = MCDE_PORTTYPE_DSI,
+ .mode = MCDE_PORTMODE_CMD,
+ .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP,
+ .ifc = DSI_VIDEO_MODE,
+ .link = 1,
+#ifdef CONFIG_AV8100_HWTRIG_INT
+ .sync_src = MCDE_SYNCSRC_TE0,
+#endif
+#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3
+ .sync_src = MCDE_SYNCSRC_TE1,
+#endif
+#ifdef CONFIG_AV8100_HWTRIG_DSI_TE
+ .sync_src = MCDE_SYNCSRC_TE_POLLING,
+#endif
+#ifdef CONFIG_AV8100_HWTRIG_NONE
+ .sync_src = MCDE_SYNCSRC_OFF,
+#endif
+ .update_auto_trig = true,
+ .phy = {
+ .dsi = {
+ .virt_id = 0,
+ .num_data_lanes = 2,
+ .ui = DSI_UNIT_INTERVAL_2,
+ .clk_cont = false,
+ .data_lanes_swap = false,
+ },
+ },
+ .hdmi_sdtv_switch = HDMI_SWITCH,
+};
+
+struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = {
+ .reset_gpio = 0,
+ .reset_delay = 1,
+ .regulator_id = NULL,
+ .cvbs_regulator_id = "v-av8100-AV-switch",
+ .ddb_id = 1,
+ .rgb_2_yCbCr_transform = {
+ .matrix = {
+ {0x42, 0x81, 0x19},
+ {0xffda, 0xffb6, 0x70},
+ {0x70, 0xffa2, 0xffee},
+ },
+ .offset = {0x80, 0x10, 0x80},
+ }
+};
+
+struct mcde_display_device av8100_hdmi = {
+ .name = "av8100_hdmi",
+ .id = TERTIARY_DISPLAY_ID,
+ .port = &port2,
+ .chnl_id = MCDE_CHNL_B,
+ .fifo = MCDE_FIFO_B,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+ .native_x_res = 1280,
+ .native_y_res = 720,
+ .synchronized_update = false,
+ .dev = {
+ .platform_data = &av8100_hdmi_pdata,
+ },
+ .platform_enable = NULL,
+ .platform_disable = NULL,
+};
+
+static void delayed_work_dispreg_hdmi(struct work_struct *ptr)
+{
+ if (mcde_display_device_register(&av8100_hdmi))
+ pr_warning("Failed to register av8100_hdmi\n");
+}
+#endif /* CONFIG_DISPLAY_AV8100_TERTIARY */
+
/*
* This function will create the framebuffer for the display that is registered.
*/
@@ -117,11 +201,12 @@ static int display_postregistered_callback(struct notifier_block *nb,
u16 width, height;
u16 virtual_width, virtual_height;
u32 rotate = FB_ROTATE_UR;
+ struct fb_info *fbi;
if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED)
return 0;
- if (ddev->id < PRIMARY_DISPLAY_ID || ddev->id >= ARRAY_SIZE(fbs))
+ if (ddev->id < PRIMARY_DISPLAY_ID || ddev->id >= MCDE_NR_OF_DISPLAYS)
return 0;
mcde_dss_get_native_resolution(ddev, &width, &height);
@@ -154,18 +239,26 @@ static int display_postregistered_callback(struct notifier_block *nb,
virtual_height = height;
#endif
- /* Create frame buffer */
- fbs[ddev->id] = mcde_fb_create(ddev,
- width, height,
- virtual_width, virtual_height,
- ddev->default_pixel_format,
- rotate);
-
- if (IS_ERR(fbs[ddev->id]))
- dev_warn(&ddev->dev, "Failed to create fb for display %s\n",
- ddev->name);
- else
- dev_info(&ddev->dev, "Framebuffer created (%s)\n", ddev->name);
+ if (ddev->id == TERTIARY_DISPLAY_ID) {
+#ifdef CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE
+ hdmi_fb_onoff(ddev, 1, 0, 0);
+#endif /* CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE */
+ } else {
+ /* Create frame buffer */
+ fbi = mcde_fb_create(ddev,
+ width, height,
+ virtual_width, virtual_height,
+ ddev->default_pixel_format,
+ rotate);
+
+ if (IS_ERR(fbi))
+ dev_warn(&ddev->dev,
+ "Failed to create fb for display %s\n",
+ ddev->name);
+ else
+ dev_info(&ddev->dev, "Framebuffer created (%s)\n",
+ ddev->name);
+ }
return 0;
}
@@ -286,10 +379,79 @@ int __init init_display_devices_u5500(void)
ret = mcde_display_device_register(&u5500_generic_display0);
if (ret)
pr_warning("Failed to register generic display device 0\n");
- displays[0] = &u5500_generic_display0;
#endif
+
+#ifdef CONFIG_DISPLAY_AV8100_TERTIARY
+ INIT_DELAYED_WORK_DEFERRABLE(&work_dispreg_hdmi,
+ delayed_work_dispreg_hdmi);
+
+ schedule_delayed_work(&work_dispreg_hdmi,
+ msecs_to_jiffies(DISPREG_HDMI_DELAY));
+#endif
+
return ret;
}
-module_init(init_display_devices_u5500);
+void hdmi_fb_onoff(struct mcde_display_device *ddev,
+ bool enable, u8 cea, u8 vesa_cea_nr)
+{
+ struct fb_info *fbi;
+ u16 w, h;
+ u16 vw, vh;
+ u32 rotate = FB_ROTATE_UR;
+ struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev);
+
+ dev_dbg(&ddev->dev, "%s\n", __func__);
+ dev_dbg(&ddev->dev, "en:%d cea:%d nr:%d\n", enable, cea, vesa_cea_nr);
+
+ if (enable) {
+ if (ddev->enabled) {
+ dev_dbg(&ddev->dev, "Display is already enabled.\n");
+ return;
+ }
+
+ /* Create fb */
+ if (ddev->fbi == NULL) {
+ /* Note: change when dynamic buffering is available */
+ int buffering = 2;
+
+ /* Get default values */
+ mcde_dss_get_native_resolution(ddev, &w, &h);
+ vw = w;
+ vh = h * buffering;
+
+ if (vesa_cea_nr != 0)
+ ddev->ceanr_convert(ddev, cea, vesa_cea_nr,
+ buffering, &w, &h, &vw, &vh);
+
+ fbi = mcde_fb_create(ddev, w, h, vw, vh,
+ ddev->default_pixel_format, rotate);
+
+ if (IS_ERR(fbi)) {
+ dev_warn(&ddev->dev,
+ "Failed to create fb for display %s\n",
+ ddev->name);
+ goto hdmi_fb_onoff_end;
+ } else {
+ dev_info(&ddev->dev,
+ "Framebuffer created (%s)\n",
+ ddev->name);
+ }
+ driver_data->fbdevname = (char *)dev_name(fbi->dev);
+ }
+ } else {
+ if (!ddev->enabled) {
+ dev_dbg(&ddev->dev, "Display %s is already disabled.\n",
+ ddev->name);
+ return;
+ }
+ mcde_fb_destroy(ddev);
+ }
+
+hdmi_fb_onoff_end:
+ return;
+}
+EXPORT_SYMBOL(hdmi_fb_onoff);
+
+module_init(init_display_devices);
#endif
diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c
index b50109e5db1..4693633013b 100644
--- a/arch/arm/mach-ux500/board-u5500.c
+++ b/arch/arm/mach-ux500/board-u5500.c
@@ -19,6 +19,8 @@
#include <../../../drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h>
#include <linux/input/matrix_keypad.h>
+#include <video/av8100.h>
+
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -133,6 +135,14 @@ static struct synaptics_rmi4_platform_data rmi4_i2c_platformdata = {
.regulator_en = true,
};
+static struct av8100_platform_data av8100_plat_data = {
+ .irq = NOMADIK_GPIO_TO_IRQ(223),
+ .reset = 225,
+ .alt_powerupseq = true,
+ .mclk_freq = 1, /* MCLK_RNG_22_27 */
+};
+
+
/*
* leds LM3530
*/
@@ -196,6 +206,10 @@ static struct i2c_board_info __initdata u5500_i2c2_devices[] = {
I2C_BOARD_INFO("lm3530-led", 0x36),
.platform_data = &u5500_als_platform_data,
},
+ {
+ I2C_BOARD_INFO("av8100", 0x70),
+ .platform_data = &av8100_plat_data,
+ },
};
/*
diff --git a/arch/arm/mach-ux500/prcmu-db5500.c b/arch/arm/mach-ux500/prcmu-db5500.c
index 7e4b847441d..1a57aa05997 100644
--- a/arch/arm/mach-ux500/prcmu-db5500.c
+++ b/arch/arm/mach-ux500/prcmu-db5500.c
@@ -116,7 +116,7 @@ enum mb5_header {
#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000135
#define PRCMU_PLLDSI_FREQ_SETTING 0x00020121
#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002
-#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000101
+#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000201
#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00000101
#define PRCMU_ENABLE_PLLDSI 0x00000001
diff --git a/drivers/video/av8100/av8100.c b/drivers/video/av8100/av8100.c
index 3523aaa3e70..d1d77b3bf16 100644
--- a/drivers/video/av8100/av8100.c
+++ b/drivers/video/av8100/av8100.c
@@ -118,11 +118,6 @@
#define MCLK_RNG_76_93 13
#define MCLK_RNG_85_104 14
#define MCLK_RNG_94_115 15
-/*
- * Until there is an API for obtaining the input master clock
- * frequency, the register value is hard coded.
- */
-#define MCLK_FREQ MCLK_RNG_31_38
DEFINE_MUTEX(av8100_hw_mutex);
#define LOCK_AV8100_HW mutex_lock(&av8100_hw_mutex)
@@ -1831,7 +1826,7 @@ static int av8100_powerup1(void)
udelay(AV8100_WATTIME_100US);
retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_LOW,
- AV8100_STANDBY_STBY_HIGH, MCLK_FREQ);
+ AV8100_STANDBY_STBY_HIGH, pdata->mclk_freq);
if (retval) {
dev_err(av8100dev, "%s reg_wr err 3\n", __func__);
goto av8100_powerup1_err;
@@ -1840,7 +1835,7 @@ static int av8100_powerup1(void)
msleep(AV8100_WAITTIME_1MS);
retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_LOW,
- AV8100_STANDBY_STBY_LOW, MCLK_FREQ);
+ AV8100_STANDBY_STBY_LOW, pdata->mclk_freq);
if (retval) {
dev_err(av8100dev, "%s reg_wr err 4\n", __func__);
goto av8100_powerup1_err;
@@ -1894,10 +1889,11 @@ av8100_powerup1_err:
static int av8100_powerup2(void)
{
int retval;
+ struct av8100_platform_data *pdata = av8100dev->platform_data;
/* Master clock timing, running, search for plug */
retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_HIGH,
- AV8100_STANDBY_STBY_HIGH, MCLK_FREQ);
+ AV8100_STANDBY_STBY_HIGH, pdata->mclk_freq);
if (retval) {
dev_err(av8100dev,
"Failed to write the value to av8100 register\n");
diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c
index 0ffba918e53..7a0208df66e 100644
--- a/drivers/video/mcde/mcde_hw.c
+++ b/drivers/video/mcde/mcde_hw.c
@@ -2329,13 +2329,16 @@ static void chnl_update_continous(struct mcde_chnl_state *chnl)
if (!chnl->continous_running) {
if (chnl->transactionid_regs < chnl->transactionid)
chnl_update_registers(chnl);
- if (chnl->port.sync_src == MCDE_SYNCSRC_TE0)
+ 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)
+ } else if (chnl->port.sync_src == MCDE_SYNCSRC_TE1) {
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_8) {
mcde_wfld(MCDE_VSCRC1, VSSEL, 1);
-
- mcde_wfld(MCDE_CRC, SYCEN1, true);
+ mcde_wfld(MCDE_CRC, SYCEN1, true);
+ } else {
+ mcde_wfld(MCDE_VSCRC1, VSSEL, 0);
+ mcde_wfld(MCDE_CRC, SYCEN0, true);
+ }
}
chnl->continous_running = true;
diff --git a/include/video/av8100.h b/include/video/av8100.h
index 5225490420c..6f59cee5b70 100644
--- a/include/video/av8100.h
+++ b/include/video/av8100.h
@@ -25,6 +25,7 @@ struct av8100_platform_data {
const char *inputclk_id;
const char *regulator_pwr_id;
bool alt_powerupseq;
+ unsigned char mclk_freq;
};
enum av8100_error {