diff options
author | Philippe Langlais <philippe.langlais@linaro.org> | 2011-05-10 17:03:27 +0200 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@stericsson.com> | 2011-09-19 15:15:12 +0200 |
commit | 5626e5cbf17b1030a1aba01b88bd43ff00739dc2 (patch) | |
tree | 3768caa3a23de09e88d8fc77e0729a9cca2423ef | |
parent | 74e820748f73001531a9603b74c029878b5d0451 (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-arch | 2 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-mop500.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-mcde.c | 198 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500.c | 14 | ||||
-rw-r--r-- | arch/arm/mach-ux500/prcmu-db5500.c | 2 | ||||
-rw-r--r-- | drivers/video/av8100/av8100.c | 12 | ||||
-rw-r--r-- | drivers/video/mcde/mcde_hw.c | 13 | ||||
-rw-r--r-- | include/video/av8100.h | 1 |
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 { |