diff options
author | Colin Cross <ccross@android.com> | 2011-06-14 11:47:19 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-06-14 11:47:19 -0700 |
commit | 43632c1867030b138c17532c0ed60f873878f20c (patch) | |
tree | 975504b58f5633a4b6b8c748caa1de1442c3e58e | |
parent | ad1f9adb36d07438bd38270744f190b49d094ad8 (diff) | |
parent | c46da983367966c4122cdcef489df0fc3c31838f (diff) | |
download | kernel_samsung_tuna-43632c1867030b138c17532c0ed60f873878f20c.zip kernel_samsung_tuna-43632c1867030b138c17532c0ed60f873878f20c.tar.gz kernel_samsung_tuna-43632c1867030b138c17532c0ed60f873878f20c.tar.bz2 |
Merge branch 'linux-omap-dss-3.0' into linux-omap-3.0
Conflicts:
arch/arm/mach-omap2/clock44xx_data.c
arch/arm/plat-omap/include/plat/omap-pm.h
Change-Id: Id9eb61c401ec94198b9efd8b581fb19c3a319d25
32 files changed, 1619 insertions, 1069 deletions
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 3ed043c..541ca0e 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -37,6 +37,7 @@ #include <plat/mmc.h> #include <plat/omap4-keypad.h> #include <video/omapdss.h> +#include <video/omap-panel-nokia-dsi.h> #include "mux.h" #include "hsmmc.h" @@ -52,6 +53,11 @@ #define OMAP4_SFH7741_ENABLE_GPIO 188 #define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define LCD_BL_GPIO 27 /* LCD Backlight GPIO */ +/* PWM2 and TOGGLE3 register offsets */ +#define LED_PWM2ON 0x03 +#define LED_PWM2OFF 0x04 +#define TWL6030_TOGGLE3 0x92 #define TPS62361_GPIO 7 @@ -274,24 +280,13 @@ static int __init omap_ethernet_init(void) return status; } -static struct platform_device sdp4430_lcd_device = { - .name = "sdp4430_lcd", - .id = -1, -}; - static struct platform_device *sdp4430_devices[] __initdata = { - &sdp4430_lcd_device, &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, &sdp4430_leds_pwm, }; -static struct omap_lcd_config sdp4430_lcd_config __initdata = { - .ctrl_name = "internal", -}; - static struct omap_board_config_kernel sdp4430_config[] __initdata = { - { OMAP_TAG_LCD, &sdp4430_lcd_config }, }; static void __init omap_4430sdp_init_early(void) @@ -347,6 +342,10 @@ static struct regulator_consumer_supply sdp4430_vmmc_supply[] = { .dev_name = "omap_hsmmc.0", }, }; +static struct regulator_consumer_supply sdp4430_vcxio_supply[] = { + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dss"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"), +}; static int omap4_twl6030_hsmmc_late_init(struct device *dev) { @@ -493,7 +492,10 @@ static struct regulator_init_data sdp4430_vcxio = { | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + .always_on = true, }, + .num_consumer_supplies = ARRAY_SIZE(sdp4430_vcxio_supply), + .consumer_supplies = sdp4430_vcxio_supply, }; static struct regulator_init_data sdp4430_vdac = { @@ -579,6 +581,76 @@ static void __init omap_sfh7741prox_init(void) __func__, OMAP4_SFH7741_ENABLE_GPIO, error); } +static int dsi1_panel_set_backlight(struct omap_dss_device *dssdev, int level) +{ + int r; + + r = twl_i2c_write_u8(TWL_MODULE_PWM, 0x7F, LED_PWM2OFF); + if (r) + return r; + + if (level > 1) { + if (level == 255) + level = 0x7F; + else + level = (~(level/2)) & 0x7F; + + r = twl_i2c_write_u8(TWL_MODULE_PWM, level, LED_PWM2ON); + if (r) + return r; + r = twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x30, TWL6030_TOGGLE3); + if (r) + return r; + } else if (level <= 1) { + r = twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x08, TWL6030_TOGGLE3); + if (r) + return r; + r = twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x28, TWL6030_TOGGLE3); + if (r) + return r; + r = twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x00, TWL6030_TOGGLE3); + if (r) + return r; + } + + return 0; +} + +static struct nokia_dsi_panel_data dsi1_panel; + +static void sdp4430_lcd_init(void) +{ + u32 reg; + int status; + + /* Enable 3 lanes in DSI1 module, disable pull down */ + reg = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY); + reg &= ~OMAP4_DSI1_LANEENABLE_MASK; + reg |= 0x7 << OMAP4_DSI1_LANEENABLE_SHIFT; + reg &= ~OMAP4_DSI1_PIPD_MASK; + reg |= 0x7 << OMAP4_DSI1_PIPD_SHIFT; + omap4_ctrl_pad_writel(reg, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY); + + /* Panel Taal reset and backlight GPIO init */ + status = gpio_request_one(dsi1_panel.reset_gpio, GPIOF_DIR_OUT, + "lcd_reset_gpio"); + if (status) + pr_err("%s: Could not get lcd_reset_gpio\n", __func__); + + if (dsi1_panel.use_ext_te) { + status = omap_mux_init_signal("gpmc_ncs4.gpio_101", + OMAP_PIN_INPUT_PULLUP); + if (status) + pr_err("%s: Could not get ext_te gpio\n", __func__); + } + + status = gpio_request_one(LCD_BL_GPIO, GPIOF_DIR_OUT, "lcd_bl_gpio"); + if (status) + pr_err("%s: Could not get lcd_bl_gpio\n", __func__); + + gpio_set_value(LCD_BL_GPIO, 0); +} + static void sdp4430_hdmi_mux_init(void) { /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ @@ -616,6 +688,52 @@ static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev) gpio_free(HDMI_GPIO_HPD); } +static struct nokia_dsi_panel_data dsi1_panel = { + .name = "taal", + .reset_gpio = 102, + .use_ext_te = false, + .ext_te_gpio = 101, + .esd_interval = 0, + .set_backlight = dsi1_panel_set_backlight, +}; + +static struct omap_dss_device sdp4430_lcd_device = { + .name = "lcd", + .driver_name = "taal", + .type = OMAP_DISPLAY_TYPE_DSI, + .data = &dsi1_panel, + .phy.dsi = { + .clk_lane = 1, + .clk_pol = 0, + .data1_lane = 2, + .data1_pol = 0, + .data2_lane = 3, + .data2_pol = 0, + }, + + .clocks = { + .dispc = { + .channel = { + .lck_div = 1, /* Logic Clock = 172.8 MHz */ + .pck_div = 5, /* Pixel Clock = 34.56 MHz */ + .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, + }, + .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, + }, + + .dsi = { + .regn = 16, /* Fint = 2.4 MHz */ + .regm = 180, /* DDR Clock = 216 MHz */ + .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */ + .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */ + + .lp_clk_div = 10, /* LP Clock = 8.64 MHz */ + .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, + }, + }, + .channel = OMAP_DSS_CHANNEL_LCD, +}; + static struct omap_dss_device sdp4430_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", @@ -635,17 +753,19 @@ static struct omap_dss_device sdp4430_hdmi_device = { }; static struct omap_dss_device *sdp4430_dss_devices[] = { + &sdp4430_lcd_device, &sdp4430_hdmi_device, }; static struct omap_dss_board_info sdp4430_dss_data = { .num_devices = ARRAY_SIZE(sdp4430_dss_devices), .devices = sdp4430_dss_devices, - .default_device = &sdp4430_hdmi_device, + .default_device = &sdp4430_lcd_device, }; void omap_4430sdp_display_init(void) { + sdp4430_lcd_init(); sdp4430_hdmi_mux_init(); omap_display_init(&sdp4430_dss_data); } diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 7dfa65f..a97525d 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -3151,11 +3151,11 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_44XX), CLK(NULL, "dmic_fck", &dmic_fck, CK_44XX), CLK(NULL, "dsp_fck", &dsp_fck, CK_44XX), - CLK("omapdss_dss", "sys_clk", &dss_sys_clk, CK_44XX), - CLK("omapdss_dss", "tv_clk", &dss_tv_clk, CK_44XX), - CLK("omapdss_dss", "video_clk", &dss_48mhz_clk, CK_44XX), - CLK("omapdss_dss", "fck", &dss_dss_clk, CK_44XX), - CLK("omapdss_dss", "ick", &dss_fck, CK_44XX), + CLK(NULL, "sys_clk", &dss_sys_clk, CK_44XX), + CLK(NULL, "tv_clk", &dss_tv_clk, CK_44XX), + CLK(NULL, "video_clk", &dss_48mhz_clk, CK_44XX), + CLK(NULL, "fck", &dss_dss_clk, CK_44XX), + CLK(NULL, "ick", &dss_fck, CK_44XX), CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_44XX), CLK(NULL, "emif1_fck", &emif1_fck, CK_44XX), CLK(NULL, "emif2_fck", &emif2_fck, CK_44XX), diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 543fcb8..a5b7a23 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -25,6 +25,7 @@ #include <video/omapdss.h> #include <plat/omap_hwmod.h> #include <plat/omap_device.h> +#include <plat/omap-pm.h> static struct platform_device omap_display_device = { .name = "omapdss", @@ -42,20 +43,6 @@ static struct omap_device_pm_latency omap_dss_latency[] = { }, }; -/* oh_core is used for getting opt-clocks */ -static struct omap_hwmod *oh_core; - -static bool opt_clock_available(const char *clk_role) -{ - int i; - - for (i = 0; i < oh_core->opt_clks_cnt; i++) { - if (!strcmp(oh_core->opt_clks[i].role, clk_role)) - return true; - } - return false; -} - struct omap_dss_hwmod_data { const char *oh_name; const char *dev_name; @@ -109,16 +96,9 @@ int __init omap_display_init(struct omap_dss_board_info *board_data) oh_count = ARRAY_SIZE(omap4_dss_hwmod_data); } - /* opt_clks are always associated with dss hwmod */ - oh_core = omap_hwmod_lookup("dss_core"); - if (!oh_core) { - pr_err("Could not look up dss_core.\n"); - return -ENODEV; - } - pdata.board_data = board_data; - pdata.board_data->get_last_off_on_transaction_id = NULL; - pdata.opt_clock_available = opt_clock_available; + pdata.board_data->get_context_loss_count = + omap_pm_get_dev_context_loss_count; for (i = 0; i < oh_count; i++) { oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name); diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index f4f6dae..085731c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2339,7 +2339,7 @@ ohsps_unlock: * Returns the context loss count of the powerdomain assocated with @oh * upon success, or zero if no powerdomain exists for @oh. */ -u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) +int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) { struct powerdomain *pwrdm; int ret = 0; diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index c4d0ae8..d87019d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -1208,6 +1208,7 @@ static struct omap_hwmod_ocp_if *omap2420_dss_slaves[] = { }; static struct omap_hwmod_opt_clk dss_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_fck" }, { .role = "tv_clk", .clk = "dss_54m_fck" }, { .role = "sys_clk", .clk = "dss2_fck" }, }; @@ -1291,6 +1292,10 @@ static struct omap_hwmod_ocp_if *omap2420_dss_dispc_slaves[] = { &omap2420_l4_core__dss_dispc, }; +static struct omap_hwmod_opt_clk dispc_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_fck" }, +}; + static struct omap_hwmod omap2420_dss_dispc_hwmod = { .name = "dss_dispc", .class = &omap2420_dispc_hwmod_class, @@ -1306,6 +1311,8 @@ static struct omap_hwmod omap2420_dss_dispc_hwmod = { .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT, }, }, + .opt_clks = dispc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dispc_opt_clks), .slaves = omap2420_dss_dispc_slaves, .slaves_cnt = ARRAY_SIZE(omap2420_dss_dispc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), @@ -1361,6 +1368,10 @@ static struct omap_hwmod_ocp_if *omap2420_dss_rfbi_slaves[] = { &omap2420_l4_core__dss_rfbi, }; +static struct omap_hwmod_opt_clk rfbi_opt_clks[] = { + { .role = "rfbi_iclk", .clk = "dss_ick" }, +}; + static struct omap_hwmod omap2420_dss_rfbi_hwmod = { .name = "dss_rfbi", .class = &omap2420_rfbi_hwmod_class, @@ -1372,6 +1383,8 @@ static struct omap_hwmod omap2420_dss_rfbi_hwmod = { .module_offs = CORE_MOD, }, }, + .opt_clks = rfbi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(rfbi_opt_clks), .slaves = omap2420_dss_rfbi_slaves, .slaves_cnt = ARRAY_SIZE(omap2420_dss_rfbi_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), @@ -1418,6 +1431,10 @@ static struct omap_hwmod_ocp_if *omap2420_dss_venc_slaves[] = { &omap2420_l4_core__dss_venc, }; +static struct omap_hwmod_opt_clk venc_opt_clks[] = { + { .role = "tv_clk", .clk = "dss_54m_fck" }, +}; + static struct omap_hwmod omap2420_dss_venc_hwmod = { .name = "dss_venc", .class = &omap2420_venc_hwmod_class, @@ -1429,6 +1446,8 @@ static struct omap_hwmod omap2420_dss_venc_hwmod = { .module_offs = CORE_MOD, }, }, + .opt_clks = venc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(venc_opt_clks), .slaves = omap2420_dss_venc_slaves, .slaves_cnt = ARRAY_SIZE(omap2420_dss_venc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index 9682dd5..8009945 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -1302,6 +1302,7 @@ static struct omap_hwmod_ocp_if *omap2430_dss_slaves[] = { }; static struct omap_hwmod_opt_clk dss_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_fck" }, { .role = "tv_clk", .clk = "dss_54m_fck" }, { .role = "sys_clk", .clk = "dss2_fck" }, }; @@ -1379,6 +1380,10 @@ static struct omap_hwmod_ocp_if *omap2430_dss_dispc_slaves[] = { &omap2430_l4_core__dss_dispc, }; +static struct omap_hwmod_opt_clk dispc_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_fck" }, +}; + static struct omap_hwmod omap2430_dss_dispc_hwmod = { .name = "dss_dispc", .class = &omap2430_dispc_hwmod_class, @@ -1394,6 +1399,8 @@ static struct omap_hwmod omap2430_dss_dispc_hwmod = { .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT, }, }, + .opt_clks = dispc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dispc_opt_clks), .slaves = omap2430_dss_dispc_slaves, .slaves_cnt = ARRAY_SIZE(omap2430_dss_dispc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), @@ -1443,6 +1450,10 @@ static struct omap_hwmod_ocp_if *omap2430_dss_rfbi_slaves[] = { &omap2430_l4_core__dss_rfbi, }; +static struct omap_hwmod_opt_clk rfbi_opt_clks[] = { + { .role = "rfbi_iclk", .clk = "dss_ick" }, +}; + static struct omap_hwmod omap2430_dss_rfbi_hwmod = { .name = "dss_rfbi", .class = &omap2430_rfbi_hwmod_class, @@ -1454,6 +1465,8 @@ static struct omap_hwmod omap2430_dss_rfbi_hwmod = { .module_offs = CORE_MOD, }, }, + .opt_clks = rfbi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(rfbi_opt_clks), .slaves = omap2430_dss_rfbi_slaves, .slaves_cnt = ARRAY_SIZE(omap2430_dss_rfbi_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), @@ -1494,6 +1507,10 @@ static struct omap_hwmod_ocp_if *omap2430_dss_venc_slaves[] = { &omap2430_l4_core__dss_venc, }; +static struct omap_hwmod_opt_clk venc_opt_clks[] = { + { .role = "tv_clk", .clk = "dss_54m_fck" }, +}; + static struct omap_hwmod omap2430_dss_venc_hwmod = { .name = "dss_venc", .class = &omap2430_venc_hwmod_class, @@ -1505,6 +1522,8 @@ static struct omap_hwmod omap2430_dss_venc_hwmod = { .module_offs = CORE_MOD, }, }, + .opt_clks = venc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(venc_opt_clks), .slaves = omap2430_dss_venc_slaves, .slaves_cnt = ARRAY_SIZE(omap2430_dss_venc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index eb639d1..3dad446 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1543,9 +1543,15 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_slaves[] = { }; static struct omap_hwmod_opt_clk dss_opt_clks[] = { - { .role = "tv_clk", .clk = "dss_tv_fck" }, - { .role = "video_clk", .clk = "dss_96m_fck" }, + { .role = "dss_clk", .clk = "dss1_alwon_fck" }, + /* + * The rest of the clocks are not needed by the driver, + * but are needed by the hwmod to reset DSS properly. + */ { .role = "sys_clk", .clk = "dss2_alwon_fck" }, + { .role = "tv_clk", .clk = "dss_tv_fck" }, + /* required only on OMAP3430 */ + { .role = "tv_dac_clk", .clk = "dss_96m_fck" }, }; static struct omap_hwmod omap3430es1_dss_core_hwmod = { @@ -1657,6 +1663,10 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_dispc_slaves[] = { &omap3xxx_l4_core__dss_dispc, }; +static struct omap_hwmod_opt_clk dispc_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_alwon_fck" }, +}; + static struct omap_hwmod omap3xxx_dss_dispc_hwmod = { .name = "dss_dispc", .class = &omap3xxx_dispc_hwmod_class, @@ -1670,6 +1680,8 @@ static struct omap_hwmod omap3xxx_dss_dispc_hwmod = { .module_offs = OMAP3430_DSS_MOD, }, }, + .opt_clks = dispc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dispc_opt_clks), .slaves = omap3xxx_dss_dispc_slaves, .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_dispc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | @@ -1721,6 +1733,11 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_dsi1_slaves[] = { &omap3xxx_l4_core__dss_dsi1, }; +static struct omap_hwmod_opt_clk dsi1_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_alwon_fck" }, + { .role = "sys_clk", .clk = "dss2_alwon_fck" }, +}; + static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = { .name = "dss_dsi1", .class = &omap3xxx_dsi_hwmod_class, @@ -1734,6 +1751,8 @@ static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = { .module_offs = OMAP3430_DSS_MOD, }, }, + .opt_clks = dsi1_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dsi1_opt_clks), .slaves = omap3xxx_dss_dsi1_slaves, .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_dsi1_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | @@ -1792,6 +1811,10 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_rfbi_slaves[] = { &omap3xxx_l4_core__dss_rfbi, }; +static struct omap_hwmod_opt_clk rfbi_opt_clks[] = { + { .role = "rfbi_iclk", .clk = "dss_ick" }, +}; + static struct omap_hwmod omap3xxx_dss_rfbi_hwmod = { .name = "dss_rfbi", .class = &omap3xxx_rfbi_hwmod_class, @@ -1803,6 +1826,8 @@ static struct omap_hwmod omap3xxx_dss_rfbi_hwmod = { .module_offs = OMAP3430_DSS_MOD, }, }, + .opt_clks = rfbi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(rfbi_opt_clks), .slaves = omap3xxx_dss_rfbi_slaves, .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_rfbi_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | @@ -1852,6 +1877,12 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_venc_slaves[] = { &omap3xxx_l4_core__dss_venc, }; +static struct omap_hwmod_opt_clk venc_opt_clks[] = { + { .role = "tv_clk", .clk = "dss_tv_fck" }, + /* required only on OMAP3430 */ + { .role = "tv_dac_clk", .clk = "dss_96m_fck" }, +}; + static struct omap_hwmod omap3xxx_dss_venc_hwmod = { .name = "dss_venc", .class = &omap3xxx_venc_hwmod_class, @@ -1863,6 +1894,8 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = { .module_offs = OMAP3430_DSS_MOD, }, }, + .opt_clks = venc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(venc_opt_clks), .slaves = omap3xxx_dss_venc_slaves, .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_venc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 926ba72..c67af87 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1355,9 +1355,15 @@ static struct omap_hwmod_class_sysconfig omap44xx_dss_sysc = { .sysc_flags = SYSS_HAS_RESET_STATUS, }; +int omap44xx_dss_reset(struct omap_hwmod *oh) { + omap_hwmod_write(0x0, oh, 0x40); + return 0; +} + static struct omap_hwmod_class omap44xx_dss_hwmod_class = { .name = "dss", .sysc = &omap44xx_dss_sysc, + .reset = omap44xx_dss_reset, }; /* dss */ @@ -1409,10 +1415,7 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_slaves[] = { }; static struct omap_hwmod_opt_clk dss_opt_clks[] = { - { .role = "sys_clk", .clk = "dss_sys_clk" }, - { .role = "tv_clk", .clk = "dss_tv_clk" }, { .role = "dss_clk", .clk = "dss_dss_clk" }, - { .role = "video_clk", .clk = "dss_48mhz_clk" }, }; static struct omap_hwmod omap44xx_dss_hwmod = { @@ -1508,9 +1511,21 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_dispc_slaves[] = { &omap44xx_l4_per__dss_dispc, }; +static struct omap_hwmod_opt_clk dispc_opt_clks[] = { + { .role = "dss_clk", .clk = "dss_dss_clk" }, + /* + * The rest of the clocks are not needed by the driver, + * but are needed by the hwmod to reset DSS properly. + */ + { .role = "sys_clk", .clk = "dss_sys_clk" }, + { .role = "tv_clk", .clk = "dss_tv_clk" }, + { .role = "hdmi_clk", .clk = "dss_48mhz_clk" }, +}; + static struct omap_hwmod omap44xx_dss_dispc_hwmod = { .name = "dss_dispc", .class = &omap44xx_dispc_hwmod_class, + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_dss_dispc_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_dispc_irqs), .sdma_reqs = omap44xx_dss_dispc_sdma_reqs, @@ -1521,6 +1536,8 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = dispc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dispc_opt_clks), .slaves = omap44xx_dss_dispc_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dispc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), @@ -1599,6 +1616,11 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_dsi1_slaves[] = { &omap44xx_l4_per__dss_dsi1, }; +static struct omap_hwmod_opt_clk dsi1_opt_clks[] = { + { .role = "dss_clk", .clk = "dss_dss_clk" }, + { .role = "sys_clk", .clk = "dss_sys_clk" }, +}; + static struct omap_hwmod omap44xx_dss_dsi1_hwmod = { .name = "dss_dsi1", .class = &omap44xx_dsi_hwmod_class, @@ -1612,6 +1634,8 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = dsi1_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dsi1_opt_clks), .slaves = omap44xx_dss_dsi1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), @@ -1759,6 +1783,11 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_hdmi_slaves[] = { &omap44xx_l4_per__dss_hdmi, }; +static struct omap_hwmod_opt_clk hdmi_opt_clks[] = { + { .role = "sys_clk", .clk = "dss_sys_clk" }, + { .role = "hdmi_clk", .clk = "dss_48mhz_clk" }, +}; + static struct omap_hwmod omap44xx_dss_hdmi_hwmod = { .name = "dss_hdmi", .class = &omap44xx_hdmi_hwmod_class, @@ -1772,6 +1801,8 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = hdmi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(hdmi_opt_clks), .slaves = omap44xx_dss_hdmi_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), @@ -1845,6 +1876,10 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_rfbi_slaves[] = { &omap44xx_l4_per__dss_rfbi, }; +static struct omap_hwmod_opt_clk rfbi_opt_clks[] = { + { .role = "rfbi_iclk", .clk = "dss_fck" }, +}; + static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { .name = "dss_rfbi", .class = &omap44xx_rfbi_hwmod_class, @@ -1856,6 +1891,8 @@ static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = rfbi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(rfbi_opt_clks), .slaves = omap44xx_dss_rfbi_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_rfbi_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), @@ -1914,6 +1951,10 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_venc_slaves[] = { &omap44xx_l4_per__dss_venc, }; +static struct omap_hwmod_opt_clk venc_opt_clks[] = { + { .role = "tv_clk", .clk = "dss_tv_clk" }, +}; + static struct omap_hwmod omap44xx_dss_venc_hwmod = { .name = "dss_venc", .class = &omap44xx_venc_hwmod_class, @@ -1923,6 +1964,8 @@ static struct omap_hwmod omap44xx_dss_venc_hwmod = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = venc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(venc_opt_clks), .slaves = omap44xx_dss_venc_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_venc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 4e4ea7b..71d9b75 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -968,16 +968,16 @@ int pwrdm_post_transition(void) * @pwrdm: struct powerdomain * to wait for * * Context loss count is the sum of powerdomain off-mode counter, the - * logic off counter and the per-bank memory off counter. Returns 0 + * logic off counter and the per-bank memory off counter. Returns negative * (and WARNs) upon error, otherwise, returns the context loss count. */ -u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm) +int pwrdm_get_context_loss_count(struct powerdomain *pwrdm) { int i, count; if (!pwrdm) { WARN(1, "powerdomain: %s: pwrdm is null\n", __func__); - return 0; + return -ENODEV; } count = pwrdm->state_counter[PWRDM_POWER_OFF]; @@ -986,7 +986,13 @@ u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm) for (i = 0; i < pwrdm->banks; i++) count += pwrdm->ret_mem_off_counter[i]; - pr_debug("powerdomain: %s: context loss count = %u\n", + /* + * Context loss count has to be a non-negative value. Clear the sign + * bit to get a value range from 0 to INT_MAX. + */ + count &= INT_MAX; + + pr_debug("powerdomain: %s: context loss count = %d\n", pwrdm->name, count); return count; diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 1ab4a16..12108f7 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -254,7 +254,7 @@ int pwrdm_clkdm_state_switch(struct clockdomain *clkdm); int pwrdm_pre_transition(void); int pwrdm_post_transition(void); int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); -u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm); +int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); extern void omap2xxx_powerdomains_init(void); diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h index e4c349f..70d31d0 100644 --- a/arch/arm/plat-omap/include/plat/omap_device.h +++ b/arch/arm/plat-omap/include/plat/omap_device.h @@ -107,7 +107,7 @@ void __iomem *omap_device_get_rt_va(struct omap_device *od); int omap_device_align_pm_lat(struct platform_device *pdev, u32 new_wakeup_lat_limit); struct powerdomain *omap_device_get_pwrdm(struct omap_device *od); -u32 omap_device_get_context_loss_count(struct platform_device *pdev); +int omap_device_get_context_loss_count(struct platform_device *pdev); /* Other */ diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 39d809a..a74663a 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -596,7 +596,7 @@ int omap_hwmod_for_each_by_class(const char *classname, void *user); int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state); -u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh); +int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh); int omap_hwmod_no_setup_reset(struct omap_hwmod *oh); diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c index 614c80e..348f0cc 100644 --- a/arch/arm/plat-omap/omap-pm-noop.c +++ b/arch/arm/plat-omap/omap-pm-noop.c @@ -27,7 +27,7 @@ #include <plat/omap_device.h> static bool off_mode_enabled; -static u32 dummy_context_loss_counter; +static int dummy_context_loss_counter; /* * Device-driver-originated constraints (via board-*.c files) @@ -313,19 +313,29 @@ void omap_pm_disable_off_mode(void) int omap_pm_get_dev_context_loss_count(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - u32 count; + int count; if (WARN_ON(!dev)) - return 0; + return -ENODEV; if (dev->parent == &omap_device_parent) { count = omap_device_get_context_loss_count(pdev); } else { WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context loss counter; device %s should be converted to omap_device", dev_name(dev)); - if (off_mode_enabled) - dummy_context_loss_counter++; + count = dummy_context_loss_counter; + + if (off_mode_enabled) { + count++; + /* + * Context loss count has to be a non-negative value. + * Clear the sign bit to get a value range from 0 to + * INT_MAX. + */ + count &= INT_MAX; + dummy_context_loss_counter = count; + } } pr_debug("OMAP PM: context loss count for dev %s = %d\n", @@ -336,7 +346,7 @@ int omap_pm_get_dev_context_loss_count(struct device *dev) #else -u32 omap_pm_get_dev_context_loss_count(struct device *dev) +int omap_pm_get_dev_context_loss_count(struct device *dev) { return dummy_context_loss_counter; } diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index c2b8461..92b4496 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -311,7 +311,7 @@ static void _add_optional_clock_clkdev(struct omap_device *od, * return the context loss counter for that hwmod, otherwise return * zero. */ -u32 omap_device_get_context_loss_count(struct platform_device *pdev) +int omap_device_get_context_loss_count(struct platform_device *pdev) { struct omap_device *od; u32 ret = 0; diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index fdd5d4ae..b82bcc1 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -504,14 +504,18 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) return 0; r = omapdss_dsi_display_enable(dssdev); - if (r) - goto err; + if (r) { + dev_err(&dssdev->dev, "failed to enable DSI\n"); + goto err1; + } omapdss_dsi_vc_enable_hs(dssdev, td->channel, true); r = _taal_enable_te(dssdev, true); - if (r) - goto err; + if (r) { + dev_err(&dssdev->dev, "failed to re-enable TE"); + goto err2; + } enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); @@ -521,13 +525,15 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) return 0; -err: - dev_err(&dssdev->dev, "exit ULPS failed"); - r = taal_panel_reset(dssdev); - - enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); - td->ulps_enabled = false; +err2: + dev_err(&dssdev->dev, "failed to exit ULPS"); + r = taal_panel_reset(dssdev); + if (!r) { + enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + td->ulps_enabled = false; + } +err1: taal_queue_ulps_work(dssdev); return r; @@ -1317,8 +1323,11 @@ static void taal_disable(struct omap_dss_device *dssdev) dsi_bus_lock(dssdev); if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - taal_wake_up(dssdev); - taal_power_off(dssdev); + int r; + + r = taal_wake_up(dssdev); + if (!r) + taal_power_off(dssdev); } dsi_bus_unlock(dssdev); diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 6b3e2da..0d12524 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -117,18 +117,6 @@ config OMAP2_DSS_MIN_FCK_PER_PCK Max FCK is 173MHz, so this doesn't work if your PCK is very high. -config OMAP2_DSS_SLEEP_BEFORE_RESET - bool "Sleep 50ms before DSS reset" - default y - help - For some unknown reason we may get SYNC_LOST errors from the display - subsystem at initialization time if we don't sleep before resetting - the DSS. See the source (dss.c) for more comments. - - However, 50ms is quite long time to sleep, and with some - configurations the SYNC_LOST may never happen, so the sleep can - be disabled here. - config OMAP2_DSS_SLEEP_AFTER_VENC_RESET bool "Sleep 20ms after VENC reset" default y diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 3da4267..f0bae6d 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -183,8 +183,11 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_dss; } - /* keep clocks enabled to prevent context saves/restores during init */ - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + r = dispc_init_platform_driver(); + if (r) { + DSSERR("Failed to initialize dispc platform driver\n"); + goto err_dispc; + } r = rfbi_init_platform_driver(); if (r) { @@ -192,12 +195,6 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_rfbi; } - r = dispc_init_platform_driver(); - if (r) { - DSSERR("Failed to initialize dispc platform driver\n"); - goto err_dispc; - } - r = venc_init_platform_driver(); if (r) { DSSERR("Failed to initialize venc platform driver\n"); @@ -238,8 +235,6 @@ static int omap_dss_probe(struct platform_device *pdev) pdata->default_device = dssdev; } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); - return 0; err_register: diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 7a9a2e7..62aa77c 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -33,6 +33,8 @@ #include <linux/workqueue.h> #include <linux/hardirq.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <plat/sram.h> #include <plat/clock.h> @@ -92,16 +94,25 @@ struct dispc_irq_stats { static struct { struct platform_device *pdev; void __iomem *base; + + int ctx_loss_cnt; + struct mutex runtime_lock; + int runtime_count; + int irq; + struct clk *dss_clk; u32 fifo_size[3]; + u32 channel_irq[3]; /* Max channels hardcoded to 3*/ + spinlock_t irq_lock; u32 irq_error_mask; struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; u32 error_irqs; struct work_struct error_work; + bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -134,18 +145,34 @@ static inline u32 dispc_read_reg(const u16 idx) return __raw_readl(dispc.base + idx); } +static int dispc_get_ctx_loss_count(void) +{ + struct device *dev = &dispc.pdev->dev; + struct omap_display_platform_data *pdata = dev->platform_data; + struct omap_dss_board_info *board_data = pdata->board_data; + int cnt; + + if (!board_data->get_context_loss_count) + return -ENOENT; + + cnt = board_data->get_context_loss_count(dev); + + WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); + + return cnt; +} + #define SR(reg) \ dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) #define RR(reg) \ dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)]) -void dispc_save_context(void) +static void dispc_save_context(void) { int i; - if (cpu_is_omap24xx()) - return; - SR(SYSCONFIG); + DSSDBG("dispc_save_context\n"); + SR(IRQENABLE); SR(CONTROL); SR(CONFIG); @@ -158,7 +185,8 @@ void dispc_save_context(void) SR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); SR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); - SR(GLOBAL_ALPHA); + if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + SR(GLOBAL_ALPHA); SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -188,20 +216,25 @@ void dispc_save_context(void) SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + if (dss_has_feature(FEAT_CPR)) { + SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + } if (dss_has_feature(FEAT_MGR_LCD2)) { - SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + if (dss_has_feature(FEAT_CPR)) { + SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + } SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); } - SR(OVL_PRELOAD(OMAP_DSS_GFX)); + if (dss_has_feature(FEAT_PRELOAD)) + SR(OVL_PRELOAD(OMAP_DSS_GFX)); /* VID1 */ SR(OVL_BA0(OMAP_DSS_VIDEO1)); @@ -226,8 +259,10 @@ void dispc_save_context(void) for (i = 0; i < 5; i++) SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); + } if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { SR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); @@ -248,7 +283,8 @@ void dispc_save_context(void) if (dss_has_feature(FEAT_ATTR2)) SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); + if (dss_has_feature(FEAT_PRELOAD)) + SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); /* VID2 */ SR(OVL_BA0(OMAP_DSS_VIDEO2)); @@ -273,8 +309,10 @@ void dispc_save_context(void) for (i = 0; i < 5; i++) SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + } if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { SR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); @@ -295,16 +333,35 @@ void dispc_save_context(void) if (dss_has_feature(FEAT_ATTR2)) SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); + if (dss_has_feature(FEAT_PRELOAD)) + SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) SR(DIVISOR); + + dispc.ctx_loss_cnt = dispc_get_ctx_loss_count(); + dispc.ctx_valid = true; + + DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); } -void dispc_restore_context(void) +static void dispc_restore_context(void) { - int i; - RR(SYSCONFIG); + int i, ctx; + + DSSDBG("dispc_restore_context\n"); + + if (!dispc.ctx_valid) + return; + + ctx = dispc_get_ctx_loss_count(); + + if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) + return; + + DSSDBG("ctx_loss_count: saved %d, current %d\n", + dispc.ctx_loss_cnt, ctx); + /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); @@ -317,7 +374,8 @@ void dispc_restore_context(void) RR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); RR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); - RR(GLOBAL_ALPHA); + if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + RR(GLOBAL_ALPHA); RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -347,20 +405,25 @@ void dispc_restore_context(void) RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + if (dss_has_feature(FEAT_CPR)) { + RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + } if (dss_has_feature(FEAT_MGR_LCD2)) { RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + if (dss_has_feature(FEAT_CPR)) { + RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + } } - RR(OVL_PRELOAD(OMAP_DSS_GFX)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(OMAP_DSS_GFX)); /* VID1 */ RR(OVL_BA0(OMAP_DSS_VIDEO1)); @@ -385,8 +448,10 @@ void dispc_restore_context(void) for (i = 0; i < 5; i++) RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); + } if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { RR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); @@ -407,7 +472,8 @@ void dispc_restore_context(void) if (dss_has_feature(FEAT_ATTR2)) RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); /* VID2 */ RR(OVL_BA0(OMAP_DSS_VIDEO2)); @@ -432,8 +498,10 @@ void dispc_restore_context(void) for (i = 0; i < 5; i++) RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + } if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { RR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); @@ -454,7 +522,8 @@ void dispc_restore_context(void) if (dss_has_feature(FEAT_ATTR2)) RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) RR(DIVISOR); @@ -471,19 +540,73 @@ void dispc_restore_context(void) * the context is fully restored */ RR(IRQENABLE); + + DSSDBG("context restored\n"); } #undef SR #undef RR -static inline void enable_clocks(bool enable) +int dispc_runtime_get(void) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + int r; + + mutex_lock(&dispc.runtime_lock); + + if (dispc.runtime_count++ == 0) { + DSSDBG("dispc_runtime_get\n"); + + r = dss_runtime_get(); + if (r) + goto err_dss_get; + + /* XXX dispc fclk can also come from DSI PLL */ + clk_enable(dispc.dss_clk); + + r = pm_runtime_get_sync(&dispc.pdev->dev); + WARN_ON(r); + if (r < 0) + goto err_runtime_get; + + dispc_restore_context(); + } + + mutex_unlock(&dispc.runtime_lock); + + return 0; + +err_runtime_get: + clk_disable(dispc.dss_clk); + dss_runtime_put(); +err_dss_get: + mutex_unlock(&dispc.runtime_lock); + + return r; } +void dispc_runtime_put(void) +{ + mutex_lock(&dispc.runtime_lock); + + if (--dispc.runtime_count == 0) { + int r; + + DSSDBG("dispc_runtime_put\n"); + + dispc_save_context(); + + r = pm_runtime_put_sync(&dispc.pdev->dev); + WARN_ON(r); + + clk_disable(dispc.dss_clk); + + dss_runtime_put(); + } + + mutex_unlock(&dispc.runtime_lock); +} + + bool dispc_go_busy(enum omap_channel channel) { int bit; @@ -505,8 +628,6 @@ void dispc_go(enum omap_channel channel) int bit; bool enable_bit, go_bit; - enable_clocks(1); - if (channel == OMAP_DSS_CHANNEL_LCD || channel == OMAP_DSS_CHANNEL_LCD2) bit = 0; /* LCDENABLE */ @@ -520,7 +641,7 @@ void dispc_go(enum omap_channel channel) enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; if (!enable_bit) - goto end; + return; if (channel == OMAP_DSS_CHANNEL_LCD || channel == OMAP_DSS_CHANNEL_LCD2) @@ -535,7 +656,7 @@ void dispc_go(enum omap_channel channel) if (go_bit) { DSSERR("GO bit not down for channel %d\n", channel); - goto end; + return; } DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : @@ -545,8 +666,6 @@ void dispc_go(enum omap_channel channel) REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); else REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); -end: - enable_clocks(0); } static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value) @@ -920,7 +1039,7 @@ static void _dispc_set_color_mode(enum omap_plane plane, REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); } -static void _dispc_set_channel_out(enum omap_plane plane, +void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel) { int shift; @@ -973,8 +1092,6 @@ void dispc_set_burst_size(enum omap_plane plane, int shift; u32 val; - enable_clocks(1); - switch (plane) { case OMAP_DSS_GFX: shift = 6; @@ -991,8 +1108,6 @@ void dispc_set_burst_size(enum omap_plane plane, val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); val = FLD_MOD(val, burst_size, shift+1, shift); dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); - - enable_clocks(0); } void dispc_enable_gamma_table(bool enable) @@ -1029,9 +1144,7 @@ void dispc_enable_replication(enum omap_plane plane, bool enable) else bit = 10; - enable_clocks(1); REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); - enable_clocks(0); } void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) @@ -1039,9 +1152,7 @@ void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) u32 val; BUG_ON((width > (1 << 11)) || (height > (1 << 11))); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); - enable_clocks(1); dispc_write_reg(DISPC_SIZE_MGR(channel), val); - enable_clocks(0); } void dispc_set_digit_size(u16 width, u16 height) @@ -1049,9 +1160,7 @@ void dispc_set_digit_size(u16 width, u16 height) u32 val; BUG_ON((width > (1 << 11)) || (height > (1 << 11))); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); - enable_clocks(1); dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val); - enable_clocks(0); } static void dispc_read_plane_fifo_sizes(void) @@ -1060,8 +1169,6 @@ static void dispc_read_plane_fifo_sizes(void) int plane; u8 start, end; - enable_clocks(1); - dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { @@ -1069,8 +1176,6 @@ static void dispc_read_plane_fifo_sizes(void) start, end); dispc.fifo_size[plane] = size; } - - enable_clocks(0); } u32 dispc_get_plane_fifo_size(enum omap_plane plane) @@ -1085,8 +1190,6 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); - enable_clocks(1); - DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n", plane, REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), @@ -1098,18 +1201,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), FLD_VAL(high, hi_start, hi_end) | FLD_VAL(low, lo_start, lo_end)); - - enable_clocks(0); } void dispc_enable_fifomerge(bool enable) { - enable_clocks(1); - DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); - - enable_clocks(0); } static void _dispc_set_fir(enum omap_plane plane, @@ -1729,14 +1826,7 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, return dispc_pclk_rate(channel) * vf * hf; } -void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out) -{ - enable_clocks(1); - _dispc_set_channel_out(plane, channel_out); - enable_clocks(0); -} - -static int _dispc_setup_plane(enum omap_plane plane, +int dispc_setup_plane(enum omap_plane plane, u32 paddr, u16 screen_width, u16 pos_x, u16 pos_y, u16 width, u16 height, @@ -1744,7 +1834,7 @@ static int _dispc_setup_plane(enum omap_plane plane, enum omap_color_mode color_mode, bool ilace, enum omap_dss_rotation_type rotation_type, - u8 rotation, int mirror, + u8 rotation, bool mirror, u8 global_alpha, u8 pre_mult_alpha, enum omap_channel channel, u32 puv_addr) { @@ -1758,6 +1848,14 @@ static int _dispc_setup_plane(enum omap_plane plane, u16 frame_height = height; unsigned int field_offset = 0; + DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> " + "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n", + plane, paddr, screen_width, pos_x, pos_y, + width, height, + out_width, out_height, + ilace, color_mode, + rotation, mirror, channel); + if (paddr == 0) return -EINVAL; @@ -1903,9 +2001,13 @@ static int _dispc_setup_plane(enum omap_plane plane, return 0; } -static void _dispc_enable_plane(enum omap_plane plane, bool enable) +int dispc_enable_plane(enum omap_plane plane, bool enable) { + DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); + + return 0; } static void dispc_disable_isr(void *data, u32 mask) @@ -1922,6 +2024,17 @@ static void _enable_lcd_out(enum omap_channel channel, bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); } +void omap_dispc_set_irq_type(int channel, enum omap_dispc_irq_type type) +{ + if (type == OMAP_DISPC_IRQ_TYPE_VSYNC) { + dispc.channel_irq[channel] = channel == OMAP_DSS_CHANNEL_LCD2 ? + DISPC_IRQ_VSYNC2 : DISPC_IRQ_VSYNC; + } else { + dispc.channel_irq[channel] = channel == OMAP_DSS_CHANNEL_LCD2 ? + DISPC_IRQ_FRAMEDONE2 : DISPC_IRQ_FRAMEDONE; + } +} + static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) { struct completion frame_done_completion; @@ -1929,8 +2042,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) int r; u32 irq; - enable_clocks(1); - /* When we disable LCD output, we need to wait until frame is done. * Otherwise the DSS is still working, and turning off the clocks * prevents DSS from going to OFF mode */ @@ -1938,8 +2049,7 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) REG_GET(DISPC_CONTROL2, 0, 0) : REG_GET(DISPC_CONTROL, 0, 0); - irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 : - DISPC_IRQ_FRAMEDONE; + irq = dispc.channel_irq[channel]; if (!enable && is_on) { init_completion(&frame_done_completion); @@ -1964,8 +2074,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) if (r) DSSERR("failed to unregister FRAMEDONE isr\n"); } - - enable_clocks(0); } static void _enable_digit_out(bool enable) @@ -1978,12 +2086,8 @@ static void dispc_enable_digit_out(bool enable) struct completion frame_done_completion; int r; - enable_clocks(1); - - if (REG_GET(DISPC_CONTROL, 1, 1) == enable) { - enable_clocks(0); + if (REG_GET(DISPC_CONTROL, 1, 1) == enable) return; - } if (enable) { unsigned long flags; @@ -2035,8 +2139,6 @@ static void dispc_enable_digit_out(bool enable) _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); } - - enable_clocks(0); } bool dispc_is_channel_enabled(enum omap_channel channel) @@ -2067,9 +2169,7 @@ void dispc_lcd_enable_signal_polarity(bool act_high) if (!dss_has_feature(FEAT_LCDENABLEPOL)) return; - enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); - enable_clocks(0); } void dispc_lcd_enable_signal(bool enable) @@ -2077,9 +2177,7 @@ void dispc_lcd_enable_signal(bool enable) if (!dss_has_feature(FEAT_LCDENABLESIGNAL)) return; - enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); - enable_clocks(0); } void dispc_pck_free_enable(bool enable) @@ -2087,19 +2185,15 @@ void dispc_pck_free_enable(bool enable) if (!dss_has_feature(FEAT_PCKFREEENABLE)) return; - enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); - enable_clocks(0); } void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) { - enable_clocks(1); if (channel == OMAP_DSS_CHANNEL_LCD2) REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); else REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); - enable_clocks(0); } @@ -2122,27 +2216,21 @@ void dispc_set_lcd_display_type(enum omap_channel channel, return; } - enable_clocks(1); if (channel == OMAP_DSS_CHANNEL_LCD2) REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); else REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); - enable_clocks(0); } void dispc_set_loadmode(enum omap_dss_load_mode mode) { - enable_clocks(1); REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); - enable_clocks(0); } void dispc_set_default_color(enum omap_channel channel, u32 color) { - enable_clocks(1); dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); - enable_clocks(0); } u32 dispc_get_default_color(enum omap_channel channel) @@ -2153,9 +2241,7 @@ u32 dispc_get_default_color(enum omap_channel channel) channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2); - enable_clocks(1); l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); - enable_clocks(0); return l; } @@ -2164,7 +2250,6 @@ void dispc_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2173,14 +2258,12 @@ void dispc_set_trans_key(enum omap_channel ch, REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); - enable_clocks(0); } void dispc_get_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type *type, u32 *trans_key) { - enable_clocks(1); if (type) { if (ch == OMAP_DSS_CHANNEL_LCD) *type = REG_GET(DISPC_CONFIG, 11, 11); @@ -2194,33 +2277,28 @@ void dispc_get_trans_key(enum omap_channel ch, if (trans_key) *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); - enable_clocks(0); } void dispc_enable_trans_key(enum omap_channel ch, bool enable) { - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); else /* OMAP_DSS_CHANNEL_LCD2 */ REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); - enable_clocks(0); } void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) { if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); else /* OMAP_DSS_CHANNEL_LCD2 */ REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18); - enable_clocks(0); } bool dispc_alpha_blending_enabled(enum omap_channel ch) { @@ -2229,7 +2307,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return false; - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2238,7 +2315,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG2, 18, 18); else BUG(); - enable_clocks(0); return enabled; } @@ -2248,7 +2324,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch) { bool enabled; - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 10, 10); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2257,7 +2332,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG2, 10, 10); else BUG(); - enable_clocks(0); return enabled; } @@ -2285,12 +2359,10 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) return; } - enable_clocks(1); if (channel == OMAP_DSS_CHANNEL_LCD2) REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); else REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); - enable_clocks(0); } void dispc_set_parallel_interface_mode(enum omap_channel channel, @@ -2322,8 +2394,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, return; } - enable_clocks(1); - if (channel == OMAP_DSS_CHANNEL_LCD2) { l = dispc_read_reg(DISPC_CONTROL2); l = FLD_MOD(l, stallmode, 11, 11); @@ -2335,8 +2405,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, l = FLD_MOD(l, gpout1, 16, 16); dispc_write_reg(DISPC_CONTROL, l); } - - enable_clocks(0); } static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, @@ -2389,10 +2457,8 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, FLD_VAL(vbp, 31, 20); } - enable_clocks(1); dispc_write_reg(DISPC_TIMING_H(channel), timing_h); dispc_write_reg(DISPC_TIMING_V(channel), timing_v); - enable_clocks(0); } /* change name to mode? */ @@ -2435,10 +2501,8 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, BUG_ON(lck_div < 1); BUG_ON(pck_div < 2); - enable_clocks(1); dispc_write_reg(DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); - enable_clocks(0); } static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, @@ -2457,7 +2521,7 @@ unsigned long dispc_fclk_rate(void) switch (dss_get_dispc_clk_source()) { case OMAP_DSS_CLK_SRC_FCK: - r = dss_clk_get_rate(DSS_CLK_FCK); + r = clk_get_rate(dispc.dss_clk); break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: dsidev = dsi_get_dsidev_from_id(0); @@ -2487,7 +2551,7 @@ unsigned long dispc_lclk_rate(enum omap_channel channel) switch (dss_get_lcd_clk_source(channel)) { case OMAP_DSS_CLK_SRC_FCK: - r = dss_clk_get_rate(DSS_CLK_FCK); + r = clk_get_rate(dispc.dss_clk); break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: dsidev = dsi_get_dsidev_from_id(0); @@ -2526,7 +2590,8 @@ void dispc_dump_clocks(struct seq_file *s) enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); enum omap_dss_clk_source lcd_clk_src; - enable_clocks(1); + if (dispc_runtime_get()) + return; seq_printf(s, "- DISPC -\n"); @@ -2574,7 +2639,8 @@ void dispc_dump_clocks(struct seq_file *s) seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); } - enable_clocks(0); + + dispc_runtime_put(); } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -2629,7 +2695,8 @@ void dispc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + if (dispc_runtime_get()) + return; DUMPREG(DISPC_REVISION); DUMPREG(DISPC_SYSCONFIG); @@ -2649,7 +2716,8 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_GLOBAL_ALPHA); + if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -2680,20 +2748,25 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + if (dss_has_feature(FEAT_CPR)) { + DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + } if (dss_has_feature(FEAT_MGR_LCD2)) { DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + if (dss_has_feature(FEAT_CPR)) { + DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + } } - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); + if (dss_has_feature(FEAT_PRELOAD)) + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1)); DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1)); @@ -2744,14 +2817,16 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7)); + } if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1)); @@ -2812,14 +2887,17 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7)); + + if (dss_has_feature(FEAT_FIR_COEF_V)) { + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6)); + DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7)); + } if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2)); @@ -2858,10 +2936,12 @@ void dispc_dump_regs(struct seq_file *s) if (dss_has_feature(FEAT_ATTR2)) DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); + if (dss_has_feature(FEAT_PRELOAD)) { + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); + } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dispc_runtime_put(); #undef DUMPREG } @@ -2882,9 +2962,7 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, l |= FLD_VAL(acbi, 11, 8); l |= FLD_VAL(acb, 7, 0); - enable_clocks(1); dispc_write_reg(DISPC_POL_FREQ(channel), l); - enable_clocks(0); } void dispc_set_pol_freq(enum omap_channel channel, @@ -3005,15 +3083,11 @@ static void _omap_dispc_set_irqs(void) mask |= isr_data->mask; } - enable_clocks(1); - old_mask = dispc_read_reg(DISPC_IRQENABLE); /* clear the irqstatus for newly enabled irqs */ dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask); dispc_write_reg(DISPC_IRQENABLE, mask); - - enable_clocks(0); } int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) @@ -3522,13 +3596,6 @@ static void _omap_dispc_initial_config(void) { u32 l; - l = dispc_read_reg(DISPC_SYSCONFIG); - l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */ - l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */ - l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */ - l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */ - dispc_write_reg(DISPC_SYSCONFIG, l); - /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ if (dss_has_feature(FEAT_CORE_CLK_DIV)) { l = dispc_read_reg(DISPC_DIVISOR); @@ -3554,67 +3621,25 @@ static void _omap_dispc_initial_config(void) dispc_read_plane_fifo_sizes(); } -int dispc_enable_plane(enum omap_plane plane, bool enable) -{ - DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); - - enable_clocks(1); - _dispc_enable_plane(plane, enable); - enable_clocks(0); - - return 0; -} - -int dispc_setup_plane(enum omap_plane plane, - u32 paddr, u16 screen_width, - u16 pos_x, u16 pos_y, - u16 width, u16 height, - u16 out_width, u16 out_height, - enum omap_color_mode color_mode, - bool ilace, - enum omap_dss_rotation_type rotation_type, - u8 rotation, bool mirror, u8 global_alpha, - u8 pre_mult_alpha, enum omap_channel channel, - u32 puv_addr) -{ - int r = 0; - - DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d, %d, %dx%d -> " - "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n", - plane, paddr, screen_width, pos_x, pos_y, - width, height, - out_width, out_height, - ilace, color_mode, - rotation, mirror, channel); - - enable_clocks(1); - - r = _dispc_setup_plane(plane, - paddr, screen_width, - pos_x, pos_y, - width, height, - out_width, out_height, - color_mode, ilace, - rotation_type, - rotation, mirror, - global_alpha, - pre_mult_alpha, - channel, puv_addr); - - enable_clocks(0); - - return r; -} - /* DISPC HW IP initialisation */ static int omap_dispchw_probe(struct platform_device *pdev) { u32 rev; int r = 0; struct resource *dispc_mem; + struct clk *clk; dispc.pdev = pdev; + clk = clk_get(&pdev->dev, "dss_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get dss_clk\n"); + r = PTR_ERR(clk); + goto err_get_clk; + } + + dispc.dss_clk = clk; + spin_lock_init(&dispc.irq_lock); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -3628,51 +3653,65 @@ static int omap_dispchw_probe(struct platform_device *pdev) if (!dispc_mem) { DSSERR("can't get IORESOURCE_MEM DISPC\n"); r = -EINVAL; - goto fail0; + goto err_ioremap; } dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); if (!dispc.base) { DSSERR("can't ioremap DISPC\n"); r = -ENOMEM; - goto fail0; + goto err_ioremap; } dispc.irq = platform_get_irq(dispc.pdev, 0); if (dispc.irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto fail1; + goto err_irq; } r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED, "OMAP DISPC", dispc.pdev); if (r < 0) { DSSERR("request_irq failed\n"); - goto fail1; + goto err_irq; } - enable_clocks(1); + mutex_init(&dispc.runtime_lock); + + pm_runtime_enable(&pdev->dev); + + r = dispc_runtime_get(); + if (r) + goto err_runtime_get; _omap_dispc_initial_config(); _omap_dispc_initialize_irq(); - dispc_save_context(); - rev = dispc_read_reg(DISPC_REVISION); dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - enable_clocks(0); + dispc_runtime_put(); return 0; -fail1: + +err_runtime_get: + pm_runtime_disable(&pdev->dev); + free_irq(dispc.irq, dispc.pdev); +err_irq: iounmap(dispc.base); -fail0: +err_ioremap: + clk_put(dispc.dss_clk); +err_get_clk: return r; } static int omap_dispchw_remove(struct platform_device *pdev) { + pm_runtime_disable(&pdev->dev); + + clk_put(dispc.dss_clk); + free_irq(dispc.irq, dispc.pdev); iounmap(dispc.base); return 0; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index ff6bd30..f053b18 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -23,7 +23,6 @@ #define DSS_SUBSYS_NAME "DPI" #include <linux/kernel.h> -#include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/errno.h> @@ -130,8 +129,6 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) bool is_tft; int r = 0; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, dssdev->panel.acbi, dssdev->panel.acb); @@ -144,7 +141,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, &lck_div, &pck_div); if (r) - goto err0; + return r; pck = fck / lck_div / pck_div / 1000; @@ -158,12 +155,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) dispc_set_lcd_timings(dssdev->manager->id, t); -err0: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); - return r; + return 0; } -static int dpi_basic_init(struct omap_dss_device *dssdev) +static void dpi_basic_init(struct omap_dss_device *dssdev) { bool is_tft; @@ -175,8 +170,6 @@ static int dpi_basic_init(struct omap_dss_device *dssdev) OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); dispc_set_tft_data_lines(dssdev->manager->id, dssdev->phy.dpi.data_lines); - - return 0; } int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) @@ -186,31 +179,38 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err0; + goto err_start_dev; } if (cpu_is_omap34xx()) { r = regulator_enable(dpi.vdds_dsi_reg); if (r) - goto err1; + goto err_reg_enable; } - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + r = dss_runtime_get(); + if (r) + goto err_get_dss; - r = dpi_basic_init(dssdev); + r = dispc_runtime_get(); if (r) - goto err2; + goto err_get_dispc; + + dpi_basic_init(dssdev); if (dpi_use_dsi_pll(dssdev)) { - dss_clk_enable(DSS_CLK_SYSCK); + r = dsi_runtime_get(dpi.dsidev); + if (r) + goto err_get_dsi; + r = dsi_pll_init(dpi.dsidev, 0, 1); if (r) - goto err3; + goto err_dsi_pll_init; } r = dpi_set_mode(dssdev); if (r) - goto err4; + goto err_set_mode; mdelay(2); @@ -218,19 +218,22 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) return 0; -err4: +err_set_mode: if (dpi_use_dsi_pll(dssdev)) dsi_pll_uninit(dpi.dsidev, true); -err3: +err_dsi_pll_init: if (dpi_use_dsi_pll(dssdev)) - dss_clk_disable(DSS_CLK_SYSCK); -err2: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dsi_runtime_put(dpi.dsidev); +err_get_dsi: + dispc_runtime_put(); +err_get_dispc: + dss_runtime_put(); +err_get_dss: if (cpu_is_omap34xx()) regulator_disable(dpi.vdds_dsi_reg); -err1: +err_reg_enable: omap_dss_stop_device(dssdev); -err0: +err_start_dev: return r; } EXPORT_SYMBOL(omapdss_dpi_display_enable); @@ -242,10 +245,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) if (dpi_use_dsi_pll(dssdev)) { dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dsi_pll_uninit(dpi.dsidev, true); - dss_clk_disable(DSS_CLK_SYSCK); + dsi_runtime_put(dpi.dsidev); } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dispc_runtime_put(); + dss_runtime_put(); if (cpu_is_omap34xx()) regulator_disable(dpi.vdds_dsi_reg); @@ -257,11 +261,26 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable); void dpi_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { + int r; + DSSDBG("dpi_set_timings\n"); dssdev->panel.timings = *timings; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + r = dss_runtime_get(); + if (r) + return; + + r = dispc_runtime_get(); + if (r) { + dss_runtime_put(); + return; + } + dpi_set_mode(dssdev); dispc_go(dssdev->manager->id); + + dispc_runtime_put(); + dss_runtime_put(); } } EXPORT_SYMBOL(dpi_set_timings); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 345757c..4a49a8c 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -36,6 +36,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/debugfs.h> +#include <linux/pm_runtime.h> #include <video/omapdss.h> #include <plat/clock.h> @@ -267,8 +268,15 @@ struct dsi_isr_tables { struct dsi_data { struct platform_device *pdev; void __iomem *base; + + struct mutex runtime_lock; + int runtime_count; + int irq; + struct clk *dss_clk; + struct clk *sys_clk; + void (*dsi_mux_pads)(bool enable); struct dsi_clock_info current_cinfo; @@ -389,15 +397,6 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev, return __raw_readl(dsi->base + idx.idx); } - -void dsi_save_context(void) -{ -} - -void dsi_restore_context(void) -{ -} - void dsi_bus_lock(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -493,9 +492,18 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) total_bytes * 1000 / total_us); } #else -#define dsi_perf_mark_setup(x) -#define dsi_perf_mark_start(x) -#define dsi_perf_show(x, y) +static inline void dsi_perf_mark_setup(struct platform_device *dsidev) +{ +} + +static inline void dsi_perf_mark_start(struct platform_device *dsidev) +{ +} + +static inline void dsi_perf_show(struct platform_device *dsidev, + const char *name) +{ +} #endif static void print_irq_status(u32 status) @@ -1039,13 +1047,69 @@ static u32 dsi_get_errors(struct platform_device *dsidev) return e; } -/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */ -static inline void enable_clocks(bool enable) +int dsi_runtime_get(struct platform_device *dsidev) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + int r; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->runtime_lock); + + if (dsi->runtime_count++ == 0) { + DSSDBG("dsi_runtime_get\n"); + + r = dss_runtime_get(); + if (r) + goto err_get_dss; + + r = dispc_runtime_get(); + if (r) + goto err_get_dispc; + + /* XXX dsi fclk can also come from DSI PLL */ + clk_enable(dsi->dss_clk); + + r = pm_runtime_get_sync(&dsi->pdev->dev); + WARN_ON(r); + if (r < 0) + goto err_runtime_get; + } + + mutex_unlock(&dsi->runtime_lock); + + return 0; + +err_runtime_get: + clk_disable(dsi->dss_clk); + dispc_runtime_put(); +err_get_dispc: + dss_runtime_put(); +err_get_dss: + mutex_unlock(&dsi->runtime_lock); + + return r; +} + +void dsi_runtime_put(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->runtime_lock); + + if (--dsi->runtime_count == 0) { + int r; + + DSSDBG("dsi_runtime_put\n"); + + r = pm_runtime_put_sync(&dsi->pdev->dev); + WARN_ON(r); + + clk_disable(dsi->dss_clk); + + dispc_runtime_put(); + dss_runtime_put(); + } + + mutex_unlock(&dsi->runtime_lock); } /* source clock for DSI PLL. this could also be PCLKFREE */ @@ -1055,9 +1119,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (enable) - dss_clk_enable(DSS_CLK_SYSCK); + clk_enable(dsi->sys_clk); else - dss_clk_disable(DSS_CLK_SYSCK); + clk_disable(dsi->sys_clk); if (enable && dsi->pll_locked) { if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) @@ -1150,10 +1214,11 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) { unsigned long r; int dsi_module = dsi_get_dsidev_id(dsidev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS_CLK_FCK */ - r = dss_clk_get_rate(DSS_CLK_FCK); + r = clk_get_rate(dsi->dss_clk); } else { /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */ r = dsi_get_pll_hsdiv_dsi_rate(dsidev); @@ -1262,7 +1327,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, return -EINVAL; if (cinfo->use_sys_clk) { - cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK); + cinfo->clkin = clk_get_rate(dsi->sys_clk); /* XXX it is unclear if highfreq should be used * with DSS_SYS_CLK source also */ cinfo->highfreq = 0; @@ -1311,7 +1376,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, int match = 0; unsigned long dss_sys_clk, max_dss_fck; - dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK); + dss_sys_clk = clk_get_rate(dsi->sys_clk); max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); @@ -1539,6 +1604,9 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ + + if (cpu_is_omap44xx()) + l = FLD_MOD(l, 3, 22, 21); /* DSI_REF_SEL */ dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ @@ -1601,7 +1669,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, dsi->vdds_dsi_reg = vdds_dsi; } - enable_clocks(1); dsi_enable_pll_clock(dsidev, 1); /* * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. @@ -1653,7 +1720,6 @@ err1: } err0: dsi_disable_scp_clk(dsidev); - enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); return r; } @@ -1671,7 +1737,6 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) } dsi_disable_scp_clk(dsidev); - enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); DSSDBG("PLL uninit done\n"); @@ -1688,7 +1753,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, dispc_clk_src = dss_get_dispc_clk_source(); dsi_clk_src = dss_get_dsi_clk_source(dsi_module); - enable_clocks(1); + if (dsi_runtime_get(dsidev)) + return; seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); @@ -1731,7 +1797,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk); - enable_clocks(0); + dsi_runtime_put(dsidev); } void dsi_dump_clocks(struct seq_file *s) @@ -1873,7 +1939,8 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + if (dsi_runtime_get(dsidev)) + return; dsi_enable_scp_clk(dsidev); DUMPREG(DSI_REVISION); @@ -1947,7 +2014,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, DUMPREG(DSI_PLL_CONFIGURATION2); dsi_disable_scp_clk(dsidev); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dsi_runtime_put(dsidev); #undef DUMPREG } @@ -1994,6 +2061,10 @@ static int dsi_cio_power(struct platform_device *dsidev, /* PWR_CMD */ REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27); + if (cpu_is_omap44xx()) + /*bit 30 has to be set to 1 to GO in omap4*/ + REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, 1, 30, 30); + /* PWR_STATUS */ while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1), 26, 25) != state) { @@ -2354,6 +2425,13 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) if (dsi->dsi_mux_pads) dsi->dsi_mux_pads(true); + if (cpu_is_omap44xx()) { + /* DDR_CLK_ALWAYS_ON */ + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 13, 13); + /* HS_AUTO_STOP_ENABLE */ + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 18, 18); + } + dsi_enable_scp_clk(dsidev); /* A dummy read using the SCP interface to any DSIPHY register is @@ -2463,28 +2541,6 @@ static void dsi_cio_uninit(struct platform_device *dsidev) dsi->dsi_mux_pads(false); } -static int _dsi_wait_reset(struct platform_device *dsidev) -{ - int t = 0; - - while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) { - if (++t > 5) { - DSSERR("soft reset failed\n"); - return -ENODEV; - } - udelay(1); - } - - return 0; -} - -static int _dsi_reset(struct platform_device *dsidev) -{ - /* Soft reset */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1); - return _dsi_wait_reset(dsidev); -} - static void dsi_config_tx_fifo(struct platform_device *dsidev, enum fifo_size size1, enum fifo_size size2, enum fifo_size size3, enum fifo_size size4) @@ -2722,6 +2778,8 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */ if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH)) r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */ + if (channel == 0) + r = FLD_MOD(r, 1, 11, 10); /* OCP_WIDTH = 32 bit */ r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ @@ -3386,6 +3444,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); + /* Reset LANEx_ULPS_SIG2 */ + REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), + 7, 5); + dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); dsi_if_enable(dsidev, false); @@ -3401,7 +3463,7 @@ err: } static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned ticks, bool x4, bool x16, bool to) { unsigned long fck; unsigned long total_ticks; @@ -3413,7 +3475,7 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, fck = dsi_fclk_rate(dsidev); r = dsi_read_reg(dsidev, DSI_TIMING2); - r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ + r = FLD_MOD(r, to ? 1 : 0, 15, 15); /* LP_RX_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */ r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ @@ -3428,7 +3490,7 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, } static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, - bool x8, bool x16) + bool x8, bool x16, bool to) { unsigned long fck; unsigned long total_ticks; @@ -3440,7 +3502,7 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, fck = dsi_fclk_rate(dsidev); r = dsi_read_reg(dsidev, DSI_TIMING1); - r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ + r = FLD_MOD(r, to ? 1 : 0, 31, 31); /* TA_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */ r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */ r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ @@ -3455,7 +3517,8 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, } static void dsi_set_stop_state_counter(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned ticks, bool x4, bool x16, + bool stop_mode) { unsigned long fck; unsigned long total_ticks; @@ -3467,7 +3530,7 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, fck = dsi_fclk_rate(dsidev); r = dsi_read_reg(dsidev, DSI_TIMING1); - r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ + r = FLD_MOD(r, stop_mode ? 1 : 0, 15, 15); /* FORCE_TX_STOP_MODE_IO */ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */ r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ @@ -3482,7 +3545,7 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, } static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned ticks, bool x4, bool x16, bool to) { unsigned long fck; unsigned long total_ticks; @@ -3494,7 +3557,7 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, fck = dsi_get_txbyteclkhs(dsidev); r = dsi_read_reg(dsidev, DSI_TIMING2); - r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ + r = FLD_MOD(r, to ? 1 : 0, 31, 31); /* HS_TX_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */ r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */ r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ @@ -3507,7 +3570,8 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, ticks, x4 ? " x4" : "", x16 ? " x16" : "", (total_ticks * 1000) / (fck / 1000 / 1000)); } -static int dsi_proto_config(struct omap_dss_device *dssdev) + +static int dsi_cmd_proto_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); u32 r; @@ -3524,10 +3588,10 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) DSI_FIFO_SIZE_32); /* XXX what values for the timeouts? */ - dsi_set_stop_state_counter(dsidev, 0x1000, false, false); - dsi_set_ta_timeout(dsidev, 0x1fff, true, true); - dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); - dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); + dsi_set_stop_state_counter(dsidev, 0x1000, false, false, true); + dsi_set_ta_timeout(dsidev, 0x1fff, true, true, true); + dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true, true); + dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true, true); switch (dssdev->ctrl.pixel_size) { case 16: @@ -3569,6 +3633,156 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) return 0; } +static int dispc_to_dsi_clock(int val, int bytes_per_pixel, int lanes) +{ + return (val * bytes_per_pixel + lanes / 2) / lanes; +} +static int dsi_video_proto_config(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct omap_video_timings *timings = &dssdev->panel.timings; + int buswidth = 0; + u32 r; + int bytes_per_pixel; + int hbp, hfp, hsa, tl; + + dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32); + + dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32); + + dsi_set_stop_state_counter(dsidev, 0x1fff, true, true, false); + dsi_set_ta_timeout(dsidev, 0x1fff, true, true, true); + dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true, false); + dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true, true); + + switch (dssdev->ctrl.pixel_size) { + case 16: + buswidth = 0; + bytes_per_pixel = 2; + break; + case 18: + buswidth = 1; + bytes_per_pixel = 3; + break; + case 24: + buswidth = 2; + bytes_per_pixel = 3; + break; + default: + BUG(); + } + + r = dsi_read_reg(dsidev, DSI_CTRL); + r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */ + r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/ + r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */ + r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */ + r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */ + r = FLD_MOD(r, 0, 10, 10); /* VP_HSYNC_POL */ + r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */ + r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER */ + r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */ + r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */ + r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ + r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */ + r = FLD_MOD(r, 1, 21, 21); /* HFP_BLANKING */ + r = FLD_MOD(r, 1, 22, 22); /* HBP_BLANKING */ + r = FLD_MOD(r, 1, 23, 23); /* HSA_BLANKING */ + dsi_write_reg(dsidev, DSI_CTRL, r); + + dsi_vc_initial_config(dsidev, 0); + dsi_vc_initial_config(dsidev, 1); + dsi_vc_initial_config(dsidev, 2); + dsi_vc_initial_config(dsidev, 3); + + hbp = dispc_to_dsi_clock(timings->hbp, bytes_per_pixel, 4); + hfp = dispc_to_dsi_clock(timings->hfp, bytes_per_pixel, 4); + hsa = dispc_to_dsi_clock(timings->hsw, bytes_per_pixel, 4); + tl = hbp + hfp + hsa + + dispc_to_dsi_clock(timings->x_res, bytes_per_pixel, 4); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING1); + r = FLD_MOD(r, hbp - 1, 11, 0); /* HBP */ + r = FLD_MOD(r, hfp - 1, 23, 12); /* HFP */ + r = FLD_MOD(r, hsa - 1, 31, 24); /* HSA */ + dsi_write_reg(dsidev, DSI_VM_TIMING1, r); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING2); + r = FLD_MOD(r, timings->vbp, 7, 0); /* VBP */ + r = FLD_MOD(r, timings->vfp, 15, 8); /* VFP */ + r = FLD_MOD(r, timings->vsw, 23, 16); /* VSA */ + r = FLD_MOD(r, 4, 27, 24); /* WINDOW_SYNC */ + dsi_write_reg(dsidev, DSI_VM_TIMING2, r); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING3); + r = FLD_MOD(r, timings->y_res, 14, 0); + r = FLD_MOD(r, tl - 1, 31, 16); + dsi_write_reg(dsidev, DSI_VM_TIMING3, r); + + /* TODO: either calculate these values or make them configurable */ + r = FLD_VAL(72, 23, 16) | /* HSA_HS_INTERLEAVING */ + FLD_VAL(114, 15, 8) | /* HFB_HS_INTERLEAVING */ + FLD_VAL(150, 7, 0); /* HbB_HS_INTERLEAVING */ + dsi_write_reg(dsidev, DSI_VM_TIMING4, r); + + r = FLD_VAL(130, 23, 16) | /* HSA_LP_INTERLEAVING */ + FLD_VAL(223, 15, 8) | /* HFB_LP_INTERLEAVING */ + FLD_VAL(59, 7, 0); /* HBB_LP_INTERLEAVING */ + dsi_write_reg(dsidev, DSI_VM_TIMING5, r); + + r = FLD_VAL(0x7A67, 31, 16) | /* BL_HS_INTERLEAVING */ + FLD_VAL(0x31D1, 15, 0); /* BL_LP_INTERLEAVING */ + dsi_write_reg(dsidev, DSI_VM_TIMING6, r); + + r = FLD_VAL(18, 31, 16) | /* ENTER_HS_MODE_LATENCY */ + FLD_VAL(15, 15, 0); /* EXIT_HS_MODE_LATENCY */ + dsi_write_reg(dsidev, DSI_VM_TIMING7, r); + + return 0; +} + +int dsi_video_mode_enable(struct omap_dss_device *dssdev, u8 data_type) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + u16 word_count; + u32 r; + u32 header; + + dsi_if_enable(dsidev, 0); + dsi_vc_enable(dsidev, 1, 0); + dsi_vc_enable(dsidev, 0, 0); + + r = dsi_read_reg(dsidev, DSI_TIMING1); + r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ + dsi_write_reg(dsidev, DSI_TIMING1, r); + + if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 15, 0) != 0) + BUG(); + + r = dsi_read_reg(dsidev, DSI_VC_CTRL(0)); + r = FLD_MOD(r, 1, 4, 4); + r = FLD_MOD(r, 1, 9, 9); + dsi_write_reg(dsidev, DSI_VC_CTRL(0), r); + + word_count = dssdev->panel.timings.x_res * 3; + header = FLD_VAL(0, 31, 24) | /* ECC */ + FLD_VAL(word_count, 23, 8) | /* WORD_COUNT */ + FLD_VAL(0, 7, 6) | /* VC_ID */ + FLD_VAL(data_type, 5, 0); + dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(0), header); + + dsi_vc_enable(dsidev, 0, 1); + dsi_if_enable(dsidev, 1); + + return 0; +} + static void dsi_proto_timings(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -3807,6 +4021,11 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", x, y, w, h); + if (dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_VIDEO_MODE) { + dss_start_update(dssdev); + return; + } + dsi_vc_config_vp(dsidev, channel); bytespp = dssdev->ctrl.pixel_size / 8; @@ -4017,23 +4236,30 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; - r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev, - irq); - if (r) { - DSSERR("can't get FRAMEDONE irq\n"); - return r; + if (dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) { + r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev, + irq); + if (r) { + DSSERR("can't get FRAMEDONE irq\n"); + return r; + } + + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_DSI); + dispc_enable_fifohandcheck(dssdev->manager->id, 1); + } else { + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_BYPASS); + dispc_enable_fifohandcheck(dssdev->manager->id, 0); } dispc_set_lcd_display_type(dssdev->manager->id, OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(dssdev->manager->id, - OMAP_DSS_PARALLELMODE_DSI); - dispc_enable_fifohandcheck(dssdev->manager->id, 1); dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); - { + if(dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) { struct omap_video_timings timings = { .hsw = 1, .hfp = 1, @@ -4044,6 +4270,9 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) }; dispc_set_lcd_timings(dssdev->manager->id, &timings); + } else { + dispc_set_lcd_timings(dssdev->manager->id, + &dssdev->panel.timings); } return 0; @@ -4056,8 +4285,9 @@ static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; - omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev, - irq); + if(dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) + omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev, + irq); } static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) @@ -4120,7 +4350,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) int dsi_module = dsi_get_dsidev_id(dsidev); int r; + /* The SCPClk is required for PLL and complexio registers on OMAP4 */ + if (cpu_is_omap44xx()) + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); + r = dsi_pll_init(dsidev, true, true); + if (r) goto err0; @@ -4151,7 +4386,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) if (1) _dsi_print_reset_status(dsidev); - r = dsi_proto_config(dssdev); + if(dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) + r = dsi_cmd_proto_config(dssdev); + else + r = dsi_video_proto_config(dssdev); + if (r) goto err3; @@ -4198,22 +4437,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dsi_pll_uninit(dsidev, disconnect_lanes); } -static int dsi_core_init(struct platform_device *dsidev) -{ - /* Autoidle */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0); - - /* ENWAKEUP */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2); - - /* SIDLEMODE smart-idle */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3); - - _dsi_initialize_irq(dsidev); - - return 0; -} - int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -4229,37 +4452,37 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err0; + goto err_start_dev; } - enable_clocks(1); - dsi_enable_pll_clock(dsidev, 1); - - r = _dsi_reset(dsidev); + r = dsi_runtime_get(dsidev); if (r) - goto err1; + goto err_get_dsi; + + dsi_enable_pll_clock(dsidev, 1); - dsi_core_init(dsidev); + _dsi_initialize_irq(dsidev); r = dsi_display_init_dispc(dssdev); if (r) - goto err1; + goto err_init_dispc; r = dsi_display_init_dsi(dssdev); if (r) - goto err2; + goto err_init_dsi; mutex_unlock(&dsi->lock); return 0; -err2: +err_init_dsi: dsi_display_uninit_dispc(dssdev); -err1: - enable_clocks(0); +err_init_dispc: dsi_enable_pll_clock(dsidev, 0); + dsi_runtime_put(dsidev); +err_get_dsi: omap_dss_stop_device(dssdev); -err0: +err_start_dev: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); return r; @@ -4282,7 +4505,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps); - enable_clocks(0); + dsi_runtime_put(dsidev); dsi_enable_pll_clock(dsidev, 0); omap_dss_stop_device(dssdev); @@ -4322,9 +4545,12 @@ int dsi_init_display(struct omap_dss_device *dssdev) DSSDBG("DSI init\n"); - /* XXX these should be figured out dynamically */ - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | + if(dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) { + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; + } else { + dssdev->caps = 0; + } if (dsi->vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; @@ -4437,7 +4663,44 @@ static void dsi_calc_clock_param_ranges(struct platform_device *dsidev) dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); } -static int dsi_init(struct platform_device *dsidev) +static int dsi_get_clocks(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct clk *clk; + + clk = clk_get(&dsidev->dev, "dss_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get dss_clk\n"); + return PTR_ERR(clk); + } + + dsi->dss_clk = clk; + + clk = clk_get(&dsidev->dev, "sys_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get sys_clk\n"); + clk_put(dsi->dss_clk); + dsi->dss_clk = NULL; + return PTR_ERR(clk); + } + + dsi->sys_clk = clk; + + return 0; +} + +static void dsi_put_clocks(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + if (dsi->dss_clk) + clk_put(dsi->dss_clk); + if (dsi->sys_clk) + clk_put(dsi->sys_clk); +} + +/* DSI1 HW IP initialisation */ +static int omap_dsi1hw_probe(struct platform_device *dsidev) { struct omap_display_platform_data *dss_plat_data; struct omap_dss_board_info *board_info; @@ -4449,7 +4712,7 @@ static int dsi_init(struct platform_device *dsidev) dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi) { r = -ENOMEM; - goto err0; + goto err_alloc; } dsi->pdev = dsidev; @@ -4472,6 +4735,14 @@ static int dsi_init(struct platform_device *dsidev) mutex_init(&dsi->lock); sema_init(&dsi->bus_lock, 1); + r = dsi_get_clocks(dsidev); + if (r) + goto err_get_clk; + + mutex_init(&dsi->runtime_lock); + + pm_runtime_enable(&dsidev->dev); + INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work, dsi_framedone_timeout_work_callback); @@ -4484,26 +4755,26 @@ static int dsi_init(struct platform_device *dsidev) if (!dsi_mem) { DSSERR("can't get IORESOURCE_MEM DSI\n"); r = -EINVAL; - goto err1; + goto err_ioremap; } dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem)); if (!dsi->base) { DSSERR("can't ioremap DSI\n"); r = -ENOMEM; - goto err1; + goto err_ioremap; } dsi->irq = platform_get_irq(dsi->pdev, 0); if (dsi->irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err2; + goto err_get_irq; } r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev); if (r < 0) { DSSERR("request_irq failed\n"); - goto err2; + goto err_get_irq; } /* DSI VCs initialization */ @@ -4515,7 +4786,9 @@ static int dsi_init(struct platform_device *dsidev) dsi_calc_clock_param_ranges(dsidev); - enable_clocks(1); + r = dsi_runtime_get(dsidev); + if (r) + goto err_get_dsi; rev = dsi_read_reg(dsidev, DSI_REVISION); dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", @@ -4523,21 +4796,32 @@ static int dsi_init(struct platform_device *dsidev) dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); - enable_clocks(0); + dsi_runtime_put(dsidev); return 0; -err2: + +err_get_dsi: + free_irq(dsi->irq, dsi->pdev); +err_get_irq: iounmap(dsi->base); -err1: +err_ioremap: + pm_runtime_disable(&dsidev->dev); +err_get_clk: kfree(dsi); -err0: +err_alloc: return r; } -static void dsi_exit(struct platform_device *dsidev) +static int omap_dsi1hw_remove(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + WARN_ON(dsi->scp_clk_refcount > 0); + + pm_runtime_disable(&dsidev->dev); + + dsi_put_clocks(dsidev); + if (dsi->vdds_dsi_reg != NULL) { if (dsi->vdds_dsi_enabled) { regulator_disable(dsi->vdds_dsi_reg); @@ -4553,29 +4837,6 @@ static void dsi_exit(struct platform_device *dsidev) kfree(dsi); - DSSDBG("omap_dsi_exit\n"); -} - -/* DSI1 HW IP initialisation */ -static int omap_dsi1hw_probe(struct platform_device *dsidev) -{ - int r; - - r = dsi_init(dsidev); - if (r) { - DSSERR("Failed to initialize DSI\n"); - goto err_dsi; - } -err_dsi: - return r; -} - -static int omap_dsi1hw_remove(struct platform_device *dsidev) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - dsi_exit(dsidev); - WARN_ON(dsi->scp_clk_refcount > 0); return 0; } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index d9489d5..964eb08 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -28,6 +28,8 @@ #include <linux/delay.h> #include <linux/seq_file.h> #include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <video/omapdss.h> #include <plat/clock.h> @@ -59,15 +61,12 @@ struct dss_reg { static struct { struct platform_device *pdev; void __iomem *base; - int ctx_id; + + struct mutex runtime_lock; + int runtime_count; struct clk *dpll4_m4_ck; - struct clk *dss_ick; - struct clk *dss_fck; - struct clk *dss_sys_clk; - struct clk *dss_tv_fck; - struct clk *dss_video_fck; - unsigned num_clks_enabled; + struct clk *dss_clk; unsigned long cache_req_pck; unsigned long cache_prate; @@ -78,6 +77,7 @@ static struct { enum omap_dss_clk_source dispc_clk_source; enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; + bool ctx_valid; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; @@ -87,13 +87,6 @@ static const char * const dss_generic_clk_source_names[] = { [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", }; -static void dss_clk_enable_all_no_ctx(void); -static void dss_clk_disable_all_no_ctx(void); -static void dss_clk_enable_no_ctx(enum dss_clock clks); -static void dss_clk_disable_no_ctx(enum dss_clock clks); - -static int _omap_dss_wait_reset(void); - static inline void dss_write_reg(const struct dss_reg idx, u32 val) { __raw_writel(val, dss.base + idx.idx); @@ -109,12 +102,10 @@ static inline u32 dss_read_reg(const struct dss_reg idx) #define RR(reg) \ dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)]) -void dss_save_context(void) +static void dss_save_context(void) { - if (cpu_is_omap24xx()) - return; + DSSDBG("dss_save_context\n"); - SR(SYSCONFIG); SR(CONTROL); if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & @@ -122,14 +113,19 @@ void dss_save_context(void) SR(SDI_CONTROL); SR(PLL_CONTROL); } + + dss.ctx_valid = true; + + DSSDBG("context saved\n"); } -void dss_restore_context(void) +static void dss_restore_context(void) { - if (_omap_dss_wait_reset()) - DSSERR("DSS not coming out of reset after sleep\n"); + DSSDBG("dss_restore_context\n"); + + if (!dss.ctx_valid) + return; - RR(SYSCONFIG); RR(CONTROL); if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & @@ -137,6 +133,8 @@ void dss_restore_context(void) RR(SDI_CONTROL); RR(PLL_CONTROL); } + + DSSDBG("context restored\n"); } #undef SR @@ -234,6 +232,7 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) return dss_generic_clk_source_names[clk_src]; } + void dss_dump_clocks(struct seq_file *s) { unsigned long dpll4_ck_rate; @@ -241,13 +240,14 @@ void dss_dump_clocks(struct seq_file *s) const char *fclk_name, *fclk_real_name; unsigned long fclk_rate; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + if (dss_runtime_get()) + return; seq_printf(s, "- DSS -\n"); fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK); fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK); - fclk_rate = dss_clk_get_rate(DSS_CLK_FCK); + fclk_rate = clk_get_rate(dss.dss_clk); if (dss.dpll4_m4_ck) { dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); @@ -273,14 +273,15 @@ void dss_dump_clocks(struct seq_file *s) fclk_rate); } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dss_runtime_put(); } void dss_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + if (dss_runtime_get()) + return; DUMPREG(DSS_REVISION); DUMPREG(DSS_SYSCONFIG); @@ -294,7 +295,7 @@ void dss_dump_regs(struct seq_file *s) DUMPREG(DSS_SDI_STATUS); } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dss_runtime_put(); #undef DUMPREG } @@ -437,7 +438,7 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) } else { if (cinfo->fck_div != 0) return -EINVAL; - cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); + cinfo->fck = clk_get_rate(dss.dss_clk); } return 0; @@ -467,7 +468,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) int dss_get_clock_div(struct dss_clock_info *cinfo) { - cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); + cinfo->fck = clk_get_rate(dss.dss_clk); if (dss.dpll4_m4_ck) { unsigned long prate; @@ -512,7 +513,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); - fck = dss_clk_get_rate(DSS_CLK_FCK); + fck = clk_get_rate(dss.dss_clk); if (req_pck == dss.cache_req_pck && ((cpu_is_omap34xx() && prate == dss.cache_prate) || dss.cache_dss_cinfo.fck == fck)) { @@ -539,7 +540,7 @@ retry: if (dss.dpll4_m4_ck == NULL) { struct dispc_clock_info cur_dispc; /* XXX can we change the clock on omap2? */ - fck = dss_clk_get_rate(DSS_CLK_FCK); + fck = clk_get_rate(dss.dss_clk); fck_div = 1; dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); @@ -616,28 +617,6 @@ found: return 0; } -static int _omap_dss_wait_reset(void) -{ - int t = 0; - - while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) { - if (++t > 1000) { - DSSERR("soft reset failed\n"); - return -ENODEV; - } - udelay(1); - } - - return 0; -} - -static int _omap_dss_reset(void) -{ - /* Soft reset */ - REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1); - return _omap_dss_wait_reset(); -} - void dss_set_venc_output(enum omap_dss_venc_type type) { int l = 0; @@ -663,424 +642,111 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ } -static int dss_init(void) +static int dss_get_clocks(void) { + struct clk *clk; int r; - u32 rev; - struct resource *dss_mem; - struct clk *dpll4_m4_ck; - dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); - if (!dss_mem) { - DSSERR("can't get IORESOURCE_MEM DSS\n"); - r = -EINVAL; - goto fail0; - } - dss.base = ioremap(dss_mem->start, resource_size(dss_mem)); - if (!dss.base) { - DSSERR("can't ioremap DSS\n"); - r = -ENOMEM; - goto fail0; + clk = clk_get(&dss.pdev->dev, "dss_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get clock dss_clk\n"); + r = PTR_ERR(clk); + goto err; } - /* disable LCD and DIGIT output. This seems to fix the synclost - * problem that we get, if the bootloader starts the DSS and - * the kernel resets it */ - omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440); - -#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET - /* We need to wait here a bit, otherwise we sometimes start to - * get synclost errors, and after that only power cycle will - * restore DSS functionality. I have no idea why this happens. - * And we have to wait _before_ resetting the DSS, but after - * enabling clocks. - * - * This bug was at least present on OMAP3430. It's unknown - * if it happens on OMAP2 or OMAP3630. - */ - msleep(50); -#endif - - _omap_dss_reset(); - - /* autoidle */ - REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0); + dss.dss_clk = clk; - /* Select DPLL */ - REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); - -#ifdef CONFIG_OMAP2_DSS_VENC - REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ - REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ - REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ -#endif if (cpu_is_omap34xx()) { - dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); - if (IS_ERR(dpll4_m4_ck)) { + clk = clk_get(NULL, "dpll4_m4_ck"); + if (IS_ERR(clk)) { DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(dpll4_m4_ck); - goto fail1; + r = PTR_ERR(clk); + goto err; } } else if (cpu_is_omap44xx()) { - dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck"); - if (IS_ERR(dpll4_m4_ck)) { - DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(dpll4_m4_ck); - goto fail1; + clk = clk_get(NULL, "dpll_per_m5x2_ck"); + if (IS_ERR(clk)) { + DSSERR("Failed to get dpll_per_m5x2_ck\n"); + r = PTR_ERR(clk); + goto err; } } else { /* omap24xx */ - dpll4_m4_ck = NULL; + clk = NULL; } - dss.dpll4_m4_ck = dpll4_m4_ck; - - dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; - dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; - dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK; - dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; - dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; - - dss_save_context(); - - rev = dss_read_reg(DSS_REVISION); - printk(KERN_INFO "OMAP DSS rev %d.%d\n", - FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); + dss.dpll4_m4_ck = clk; return 0; -fail1: - iounmap(dss.base); -fail0: - return r; -} - -static void dss_exit(void) -{ +err: + if (dss.dss_clk) + clk_put(dss.dss_clk); if (dss.dpll4_m4_ck) clk_put(dss.dpll4_m4_ck); - iounmap(dss.base); -} - -/* CONTEXT */ -static int dss_get_ctx_id(void) -{ - struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data; - int r; - - if (!pdata->board_data->get_last_off_on_transaction_id) - return 0; - r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev); - if (r < 0) { - dev_err(&dss.pdev->dev, "getting transaction ID failed, " - "will force context restore\n"); - r = -1; - } return r; } -int dss_need_ctx_restore(void) -{ - int id = dss_get_ctx_id(); - - if (id < 0 || id != dss.ctx_id) { - DSSDBG("ctx id %d -> id %d\n", - dss.ctx_id, id); - dss.ctx_id = id; - return 1; - } else { - return 0; - } -} - -static void save_all_ctx(void) -{ - DSSDBG("save context\n"); - - dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK); - - dss_save_context(); - dispc_save_context(); -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_save_context(); -#endif - - dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK); -} - -static void restore_all_ctx(void) -{ - DSSDBG("restore context\n"); - - dss_clk_enable_all_no_ctx(); - - dss_restore_context(); - dispc_restore_context(); -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_restore_context(); -#endif - - dss_clk_disable_all_no_ctx(); -} - -static int dss_get_clock(struct clk **clock, const char *clk_name) +static void dss_put_clocks(void) { - struct clk *clk; - - clk = clk_get(&dss.pdev->dev, clk_name); - - if (IS_ERR(clk)) { - DSSERR("can't get clock %s", clk_name); - return PTR_ERR(clk); - } - - *clock = clk; - - DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk)); - - return 0; + if (dss.dpll4_m4_ck) + clk_put(dss.dpll4_m4_ck); + clk_put(dss.dss_clk); } -static int dss_get_clocks(void) +int dss_runtime_get(void) { int r; - struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data; - dss.dss_ick = NULL; - dss.dss_fck = NULL; - dss.dss_sys_clk = NULL; - dss.dss_tv_fck = NULL; - dss.dss_video_fck = NULL; - - r = dss_get_clock(&dss.dss_ick, "ick"); - if (r) - goto err; + mutex_lock(&dss.runtime_lock); - r = dss_get_clock(&dss.dss_fck, "fck"); - if (r) - goto err; + if (dss.runtime_count++ == 0) { + DSSDBG("dss_runtime_get\n"); - if (!pdata->opt_clock_available) { - r = -ENODEV; - goto err; - } + clk_enable(dss.dss_clk); - if (pdata->opt_clock_available("sys_clk")) { - r = dss_get_clock(&dss.dss_sys_clk, "sys_clk"); - if (r) + r = pm_runtime_get_sync(&dss.pdev->dev); + WARN_ON(r); + if (r < 0) goto err; - } - if (pdata->opt_clock_available("tv_clk")) { - r = dss_get_clock(&dss.dss_tv_fck, "tv_clk"); - if (r) - goto err; + dss_restore_context(); } - if (pdata->opt_clock_available("video_clk")) { - r = dss_get_clock(&dss.dss_video_fck, "video_clk"); - if (r) - goto err; - } + mutex_unlock(&dss.runtime_lock); return 0; err: - if (dss.dss_ick) - clk_put(dss.dss_ick); - if (dss.dss_fck) - clk_put(dss.dss_fck); - if (dss.dss_sys_clk) - clk_put(dss.dss_sys_clk); - if (dss.dss_tv_fck) - clk_put(dss.dss_tv_fck); - if (dss.dss_video_fck) - clk_put(dss.dss_video_fck); - + clk_disable(dss.dss_clk); + mutex_unlock(&dss.runtime_lock); return r; } -static void dss_put_clocks(void) +void dss_runtime_put(void) { - if (dss.dss_video_fck) - clk_put(dss.dss_video_fck); - if (dss.dss_tv_fck) - clk_put(dss.dss_tv_fck); - if (dss.dss_sys_clk) - clk_put(dss.dss_sys_clk); - clk_put(dss.dss_fck); - clk_put(dss.dss_ick); -} - -unsigned long dss_clk_get_rate(enum dss_clock clk) -{ - switch (clk) { - case DSS_CLK_ICK: - return clk_get_rate(dss.dss_ick); - case DSS_CLK_FCK: - return clk_get_rate(dss.dss_fck); - case DSS_CLK_SYSCK: - return clk_get_rate(dss.dss_sys_clk); - case DSS_CLK_TVFCK: - return clk_get_rate(dss.dss_tv_fck); - case DSS_CLK_VIDFCK: - return clk_get_rate(dss.dss_video_fck); - } - - BUG(); - return 0; -} - -static unsigned count_clk_bits(enum dss_clock clks) -{ - unsigned num_clks = 0; - - if (clks & DSS_CLK_ICK) - ++num_clks; - if (clks & DSS_CLK_FCK) - ++num_clks; - if (clks & DSS_CLK_SYSCK) - ++num_clks; - if (clks & DSS_CLK_TVFCK) - ++num_clks; - if (clks & DSS_CLK_VIDFCK) - ++num_clks; - - return num_clks; -} - -static void dss_clk_enable_no_ctx(enum dss_clock clks) -{ - unsigned num_clks = count_clk_bits(clks); - - if (clks & DSS_CLK_ICK) - clk_enable(dss.dss_ick); - if (clks & DSS_CLK_FCK) - clk_enable(dss.dss_fck); - if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk) - clk_enable(dss.dss_sys_clk); - if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck) - clk_enable(dss.dss_tv_fck); - if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck) - clk_enable(dss.dss_video_fck); - - dss.num_clks_enabled += num_clks; -} + mutex_lock(&dss.runtime_lock); -void dss_clk_enable(enum dss_clock clks) -{ - bool check_ctx = dss.num_clks_enabled == 0; - - dss_clk_enable_no_ctx(clks); - - /* - * HACK: On omap4 the registers may not be accessible right after - * enabling the clocks. At some point this will be handled by - * pm_runtime, but for the time begin this should make things work. - */ - if (cpu_is_omap44xx() && check_ctx) - udelay(10); - - if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore()) - restore_all_ctx(); -} + if (--dss.runtime_count == 0) { + int r; -static void dss_clk_disable_no_ctx(enum dss_clock clks) -{ - unsigned num_clks = count_clk_bits(clks); - - if (clks & DSS_CLK_ICK) - clk_disable(dss.dss_ick); - if (clks & DSS_CLK_FCK) - clk_disable(dss.dss_fck); - if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk) - clk_disable(dss.dss_sys_clk); - if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck) - clk_disable(dss.dss_tv_fck); - if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck) - clk_disable(dss.dss_video_fck); - - dss.num_clks_enabled -= num_clks; -} + DSSDBG("dss_runtime_put\n"); -void dss_clk_disable(enum dss_clock clks) -{ - if (cpu_is_omap34xx()) { - unsigned num_clks = count_clk_bits(clks); + dss_save_context(); - BUG_ON(dss.num_clks_enabled < num_clks); + r = pm_runtime_put_sync(&dss.pdev->dev); + WARN_ON(r); - if (dss.num_clks_enabled == num_clks) - save_all_ctx(); + clk_disable(dss.dss_clk); } - dss_clk_disable_no_ctx(clks); -} - -static void dss_clk_enable_all_no_ctx(void) -{ - enum dss_clock clks; - - clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; - if (cpu_is_omap34xx()) - clks |= DSS_CLK_VIDFCK; - dss_clk_enable_no_ctx(clks); + mutex_unlock(&dss.runtime_lock); } -static void dss_clk_disable_all_no_ctx(void) -{ - enum dss_clock clks; - - clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; - if (cpu_is_omap34xx()) - clks |= DSS_CLK_VIDFCK; - dss_clk_disable_no_ctx(clks); -} - -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) -/* CLOCKS */ -static void core_dump_clocks(struct seq_file *s) -{ - int i; - struct clk *clocks[5] = { - dss.dss_ick, - dss.dss_fck, - dss.dss_sys_clk, - dss.dss_tv_fck, - dss.dss_video_fck - }; - - const char *names[5] = { - "ick", - "fck", - "sys_clk", - "tv_fck", - "video_fck" - }; - - seq_printf(s, "- CORE -\n"); - - seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled); - - for (i = 0; i < 5; i++) { - if (!clocks[i]) - continue; - seq_printf(s, "%s (%s)%*s\t%lu\t%d\n", - names[i], - clocks[i]->name, - 24 - strlen(names[i]) - strlen(clocks[i]->name), - "", - clk_get_rate(clocks[i]), - clocks[i]->usecount); - } -} -#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */ - /* DEBUGFS */ #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) void dss_debug_dump_clocks(struct seq_file *s) { - core_dump_clocks(s); dss_dump_clocks(s); dispc_dump_clocks(s); #ifdef CONFIG_OMAP2_DSS_DSI @@ -1089,28 +755,53 @@ void dss_debug_dump_clocks(struct seq_file *s) } #endif - /* DSS HW IP initialisation */ static int omap_dsshw_probe(struct platform_device *pdev) { + struct resource *dss_mem; + u32 rev; int r; dss.pdev = pdev; + dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); + if (!dss_mem) { + DSSERR("can't get IORESOURCE_MEM DSS\n"); + r = -EINVAL; + goto err_ioremap; + } + dss.base = ioremap(dss_mem->start, resource_size(dss_mem)); + if (!dss.base) { + DSSERR("can't ioremap DSS\n"); + r = -ENOMEM; + goto err_ioremap; + } + r = dss_get_clocks(); if (r) goto err_clocks; - dss_clk_enable_all_no_ctx(); + mutex_init(&dss.runtime_lock); - dss.ctx_id = dss_get_ctx_id(); - DSSDBG("initial ctx id %u\n", dss.ctx_id); + pm_runtime_enable(&pdev->dev); - r = dss_init(); - if (r) { - DSSERR("Failed to initialize DSS\n"); - goto err_dss; - } + r = dss_runtime_get(); + if (r) + goto err_runtime_get; + + /* Select DPLL */ + REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); + +#ifdef CONFIG_OMAP2_DSS_VENC + REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ + REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ + REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ +#endif + dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; + dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; + dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK; + dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; + dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; r = dpi_init(); if (r) { @@ -1124,33 +815,37 @@ static int omap_dsshw_probe(struct platform_device *pdev) goto err_sdi; } - dss_clk_disable_all_no_ctx(); + rev = dss_read_reg(DSS_REVISION); + printk(KERN_INFO "OMAP DSS rev %d.%d\n", + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); + + dss_runtime_put(); + return 0; err_sdi: dpi_exit(); err_dpi: - dss_exit(); -err_dss: - dss_clk_disable_all_no_ctx(); + dss_runtime_put(); +err_runtime_get: + pm_runtime_disable(&pdev->dev); dss_put_clocks(); err_clocks: + iounmap(dss.base); +err_ioremap: return r; } static int omap_dsshw_remove(struct platform_device *pdev) { + dpi_exit(); + sdi_exit(); - dss_exit(); + iounmap(dss.base); - /* - * As part of hwmod changes, DSS is not the only controller of dss - * clocks; hwmod framework itself will also enable clocks during hwmod - * init for dss, and autoidle is set in h/w for DSS. Hence, there's no - * need to disable clocks if their usecounts > 1. - */ - WARN_ON(dss.num_clks_enabled > 0); + pm_runtime_disable(&pdev->dev); dss_put_clocks(); + return 0; } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 8ab6d43..ce17a61 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -109,14 +109,6 @@ enum omap_parallel_interface_mode { OMAP_DSS_PARALLELMODE_DSI, }; -enum dss_clock { - DSS_CLK_ICK = 1 << 0, /* DSS_L3_ICLK and DSS_L4_ICLK */ - DSS_CLK_FCK = 1 << 1, /* DSS1_ALWON_FCLK */ - DSS_CLK_SYSCK = 1 << 2, /* DSS2_ALWON_FCLK */ - DSS_CLK_TVFCK = 1 << 3, /* DSS_TV_FCLK */ - DSS_CLK_VIDFCK = 1 << 4, /* DSS_96M_FCLK*/ -}; - enum dss_hdmi_venc_clk_source_select { DSS_VENC_TV_CLK = 0, DSS_HDMI_M_PCLK = 1, @@ -220,13 +212,10 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); int dss_init_platform_driver(void); void dss_uninit_platform_driver(void); +int dss_runtime_get(void); +void dss_runtime_put(void); + void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); -void dss_save_context(void); -void dss_restore_context(void); -void dss_clk_enable(enum dss_clock clks); -void dss_clk_disable(enum dss_clock clks); -unsigned long dss_clk_get_rate(enum dss_clock clk); -int dss_need_ctx_restore(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); void dss_dump_clocks(struct seq_file *s); @@ -283,15 +272,15 @@ struct file_operations; int dsi_init_platform_driver(void); void dsi_uninit_platform_driver(void); +int dsi_runtime_get(struct platform_device *dsidev); +void dsi_runtime_put(struct platform_device *dsidev); + void dsi_dump_clocks(struct seq_file *s); void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir, const struct file_operations *debug_fops); void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, const struct file_operations *debug_fops); -void dsi_save_context(void); -void dsi_restore_context(void); - int dsi_init_display(struct omap_dss_device *display); void dsi_irq_handler(void); unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); @@ -317,6 +306,13 @@ static inline int dsi_init_platform_driver(void) static inline void dsi_uninit_platform_driver(void) { } +static inline int dsi_runtime_get(struct platform_device *dsidev) +{ + return 0; +} +static inline void dsi_runtime_put(struct platform_device *dsidev) +{ +} static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) { WARN("%s: DSI not compiled in, returning rate as 0\n", __func__); @@ -384,8 +380,8 @@ void dispc_dump_regs(struct seq_file *s); void dispc_irq_handler(void); void dispc_fake_vsync_irq(void); -void dispc_save_context(void); -void dispc_restore_context(void); +int dispc_runtime_get(void); +void dispc_runtime_put(void); void dispc_enable_sidle(void); void dispc_disable_sidle(void); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 1c18888..bd420f9 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -286,7 +286,9 @@ static const struct omap_dss_features omap3430_dss_features = { FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | - FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC, + FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC | + FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD | + FEAT_FIR_COEF_V, .num_mgrs = 2, .num_ovls = 3, @@ -306,7 +308,8 @@ static const struct omap_dss_features omap3630_dss_features = { FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG | - FEAT_DSI_PLL_FREQSEL, + FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD | + FEAT_FIR_COEF_V, .num_mgrs = 2, .num_ovls = 3, @@ -327,7 +330,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | - FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2, + FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | + FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V, .num_mgrs = 3, .num_ovls = 3, @@ -348,7 +352,8 @@ static const struct omap_dss_features omap4_dss_features = { FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE | - FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2, + FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR | + FEAT_PRELOAD | FEAT_FIR_COEF_V, .num_mgrs = 3, .num_ovls = 3, diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 07b346f..5be8103 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -51,6 +51,10 @@ enum dss_feat_id { FEAT_HDMI_CTS_SWMODE = 1 << 19, FEAT_HANDLE_UV_SEPARATE = 1 << 20, FEAT_ATTR2 = 1 << 21, + FEAT_VENC_REQUIRES_TV_DAC_CLK = 1 << 22, + FEAT_CPR = 1 << 23, + FEAT_PRELOAD = 1 << 24, + FEAT_FIR_COEF_V = 1 << 25, }; /* DSS register field id */ diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index b0555f4..5e5b98b 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -29,6 +29,9 @@ #include <linux/mutex.h> #include <linux/delay.h> #include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/clk.h> #include <video/omapdss.h> #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) @@ -51,6 +54,9 @@ static struct { u8 edid_set; bool custom_set; struct hdmi_config cfg; + + struct clk *sys_clk; + struct clk *hdmi_clk; } hdmi; /* @@ -162,6 +168,56 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx, return val; } +static int hdmi_runtime_get(void) +{ + int r; + + DSSDBG("hdmi_runtime_get\n"); + + r = dss_runtime_get(); + if (r) + goto err_get_dss; + + r = dispc_runtime_get(); + if (r) + goto err_get_dispc; + + clk_enable(hdmi.sys_clk); + clk_enable(hdmi.hdmi_clk); + + r = pm_runtime_get_sync(&hdmi.pdev->dev); + WARN_ON(r); + if (r < 0) + goto err_runtime_get; + + return 0; + +err_runtime_get: + clk_disable(hdmi.sys_clk); + clk_disable(hdmi.hdmi_clk); + dispc_runtime_put(); +err_get_dispc: + dss_runtime_put(); +err_get_dss: + return r; +} + +static void hdmi_runtime_put(void) +{ + int r; + + DSSDBG("hdmi_runtime_put\n"); + + r = pm_runtime_put_sync(&hdmi.pdev->dev); + WARN_ON(r); + + clk_disable(hdmi.sys_clk); + clk_disable(hdmi.hdmi_clk); + + dispc_runtime_put(); + dss_runtime_put(); +} + int hdmi_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); @@ -311,30 +367,11 @@ static int hdmi_phy_init(void) return 0; } -static int hdmi_wait_softreset(void) -{ - /* reset W1 */ - REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0); - - /* wait till SOFTRESET == 0 */ - if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) { - DSSERR("sysconfig reset failed\n"); - return -ETIMEDOUT; - } - - return 0; -} - static int hdmi_pll_program(struct hdmi_pll_info *fmt) { u16 r = 0; enum hdmi_clk_refsel refsel; - /* wait for wrapper reset */ - r = hdmi_wait_softreset(); - if (r) - return r; - r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); if (r) return r; @@ -1064,7 +1101,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, unsigned long clkin, refclk; u32 mf; - clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000; + clkin = clk_get_rate(hdmi.sys_clk) / 10000; /* * Input clock is predivided by N + 1 * out put of which is reference clk @@ -1098,16 +1135,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); } -static void hdmi_enable_clocks(int enable) -{ - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | - DSS_CLK_SYSCK | DSS_CLK_VIDFCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | - DSS_CLK_SYSCK | DSS_CLK_VIDFCK); -} - static int hdmi_power_on(struct omap_dss_device *dssdev) { int r, code = 0; @@ -1115,7 +1142,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) struct omap_video_timings *p; unsigned long phy; - hdmi_enable_clocks(1); + r = hdmi_runtime_get(); + if (r) + return r; dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); @@ -1180,7 +1209,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) return 0; err: - hdmi_enable_clocks(0); + hdmi_runtime_put(); return -EIO; } @@ -1191,7 +1220,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) hdmi_wp_video_start(0); hdmi_phy_off(); hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); - hdmi_enable_clocks(0); + hdmi_runtime_put(); hdmi.edid_set = 0; } @@ -1686,14 +1715,43 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = { }; #endif +static int hdmi_get_clocks(struct platform_device *pdev) +{ + struct clk *clk; + + clk = clk_get(&pdev->dev, "sys_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get sys_clk\n"); + return PTR_ERR(clk); + } + + hdmi.sys_clk = clk; + + clk = clk_get(&pdev->dev, "hdmi_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get hdmi_clk\n"); + clk_put(hdmi.sys_clk); + return PTR_ERR(clk); + } + + hdmi.hdmi_clk = clk; + + return 0; +} + +static void hdmi_put_clocks(void) +{ + if (hdmi.sys_clk) + clk_put(hdmi.sys_clk); + if (hdmi.hdmi_clk) + clk_put(hdmi.hdmi_clk); +} + /* HDMI HW IP initialisation */ static int omapdss_hdmihw_probe(struct platform_device *pdev) { struct resource *hdmi_mem; -#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ - defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) - int ret; -#endif + int r; hdmi.pdata = pdev->dev.platform_data; hdmi.pdev = pdev; @@ -1713,17 +1771,25 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) return -ENOMEM; } + r = hdmi_get_clocks(pdev); + if (r) { + iounmap(hdmi.base_wp); + return r; + } + + pm_runtime_enable(&pdev->dev); + hdmi_panel_init(); #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) /* Register ASoC codec DAI */ - ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, + r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, &hdmi_codec_dai_drv, 1); - if (ret) { + if (r) { DSSERR("can't register ASoC HDMI audio codec\n"); - return ret; + return r; } #endif return 0; @@ -1738,6 +1804,10 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev) snd_soc_unregister_codec(&pdev->dev); #endif + pm_runtime_disable(&pdev->dev); + + hdmi_put_clocks(); + iounmap(hdmi.base_wp); return 0; diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 9aeea50..b1126b6 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -492,6 +492,12 @@ static int omap_dss_set_device(struct omap_overlay_manager *mgr, mgr->device = dssdev; mgr->device_changed = true; + if (dssdev->type == OMAP_DISPLAY_TYPE_DSI && + !(dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)) + omap_dispc_set_irq_type(mgr->id, OMAP_DISPC_IRQ_TYPE_VSYNC); + else + omap_dispc_set_irq_type(mgr->id, OMAP_DISPC_IRQ_TYPE_FRAMEDONE); + return 0; } @@ -1236,6 +1242,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); + r = dispc_runtime_get(); + if (r) + return r; + spin_lock_irqsave(&dss_cache.lock, flags); /* Configure overlays */ @@ -1409,7 +1419,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) } r = 0; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); if (!dss_cache.irq_enabled) { u32 mask; @@ -1422,10 +1431,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) dss_cache.irq_enabled = true; } configure_dispc(); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); spin_unlock_irqrestore(&dss_cache.lock, flags); + dispc_runtime_put(); + return r; } diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 0f08025..c84380c 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -84,32 +84,42 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, old_mgr = ovl->manager; + r = dispc_runtime_get(); + if (r) + return r; + /* detach old manager */ if (old_mgr) { r = ovl->unset_manager(ovl); if (r) { DSSERR("detach failed\n"); - return r; + goto err; } r = old_mgr->apply(old_mgr); if (r) - return r; + goto err; } if (mgr) { r = ovl->set_manager(ovl, mgr); if (r) { DSSERR("Failed to attach overlay\n"); - return r; + goto err; } r = mgr->apply(mgr); if (r) - return r; + goto err; } + dispc_runtime_put(); + return size; + +err: + dispc_runtime_put(); + return r; } static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) @@ -238,6 +248,9 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, u8 alpha; struct omap_overlay_info info; + if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) + return -ENODEV; + r = kstrtou8(buf, 0, &alpha); if (r) return r; @@ -504,7 +517,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, ovl->manager = mgr; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); /* XXX: When there is an overlay on a DSI manual update display, and * the overlay is first disabled, then moved to tv, and enabled, we * seem to get SYNC_LOST_DIGIT error. @@ -518,7 +530,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, * the overlay, but before moving the overlay to TV. */ dispc_set_channel_out(ovl->id, mgr->id); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); return 0; } @@ -719,6 +730,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) } if (mgr) { + dispc_runtime_get(); + for (i = 0; i < dss_feat_get_num_ovls(); i++) { struct omap_overlay *ovl; ovl = omap_dss_get_overlay(i); @@ -728,6 +741,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) omap_dss_set_manager(ovl, mgr); } } + + dispc_runtime_put(); } } diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index c06fbe0..3e2f5cd 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -33,6 +33,8 @@ #include <linux/hrtimer.h> #include <linux/seq_file.h> #include <linux/semaphore.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <video/omapdss.h> #include "dss.h" @@ -120,12 +122,46 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx) return __raw_readl(rfbi.base + idx.idx); } -static void rfbi_enable_clocks(bool enable) +static int rfbi_runtime_get(void) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + int r; + + DSSDBG("rfbi_runtime_get\n"); + + r = dss_runtime_get(); + if (r) + goto err_get_dss; + + r = dispc_runtime_get(); + if (r) + goto err_get_dispc; + + r = pm_runtime_get_sync(&rfbi.pdev->dev); + WARN_ON(r); + if (r < 0) + goto err_runtime_get; + + return 0; + +err_runtime_get: + dispc_runtime_put(); +err_get_dispc: + dss_runtime_put(); +err_get_dss: + return r; +} + +static void rfbi_runtime_put(void) +{ + int r; + + DSSDBG("rfbi_runtime_put\n"); + + r = pm_runtime_put_sync(&rfbi.pdev->dev); + WARN_ON(r); + + dispc_runtime_put(); + dss_runtime_put(); } void rfbi_bus_lock(void) @@ -805,7 +841,8 @@ void rfbi_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + if (rfbi_runtime_get()) + return; DUMPREG(RFBI_REVISION); DUMPREG(RFBI_SYSCONFIG); @@ -836,7 +873,7 @@ void rfbi_dump_regs(struct seq_file *s) DUMPREG(RFBI_VSYNC_WIDTH); DUMPREG(RFBI_HSYNC_WIDTH); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + rfbi_runtime_put(); #undef DUMPREG } @@ -844,7 +881,9 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { int r; - rfbi_enable_clocks(1); + r = rfbi_runtime_get(); + if (r) + return r; r = omap_dss_start_device(dssdev); if (r) { @@ -879,6 +918,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) err1: omap_dss_stop_device(dssdev); err0: + rfbi_runtime_put(); return r; } EXPORT_SYMBOL(omapdss_rfbi_display_enable); @@ -889,7 +929,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) DISPC_IRQ_FRAMEDONE); omap_dss_stop_device(dssdev); - rfbi_enable_clocks(0); + rfbi_runtime_put(); } EXPORT_SYMBOL(omapdss_rfbi_display_disable); @@ -904,8 +944,9 @@ int rfbi_init_display(struct omap_dss_device *dssdev) static int omap_rfbihw_probe(struct platform_device *pdev) { u32 rev; - u32 l; struct resource *rfbi_mem; + struct clk *clk; + int r; rfbi.pdev = pdev; @@ -914,36 +955,55 @@ static int omap_rfbihw_probe(struct platform_device *pdev) rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); if (!rfbi_mem) { DSSERR("can't get IORESOURCE_MEM RFBI\n"); - return -EINVAL; + r = -EINVAL; + goto err_ioremap; } rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem)); if (!rfbi.base) { DSSERR("can't ioremap RFBI\n"); - return -ENOMEM; + r = -ENOMEM; + goto err_ioremap; } - rfbi_enable_clocks(1); + pm_runtime_enable(&pdev->dev); + + r = rfbi_runtime_get(); + if (r) + goto err_get_rfbi; msleep(10); - rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000; + clk = clk_get(&pdev->dev, "rfbi_iclk"); + if (IS_ERR(clk)) { + DSSERR("can't get rfbi_iclk\n"); + r = PTR_ERR(clk); + goto err_get_ick; + } + + rfbi.l4_khz = clk_get_rate(clk) / 1000; - /* Enable autoidle and smart-idle */ - l = rfbi_read_reg(RFBI_SYSCONFIG); - l |= (1 << 0) | (2 << 3); - rfbi_write_reg(RFBI_SYSCONFIG, l); + clk_put(clk); rev = rfbi_read_reg(RFBI_REVISION); dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - rfbi_enable_clocks(0); + rfbi_runtime_put(); return 0; + +err_get_ick: + rfbi_runtime_put(); +err_get_rfbi: + pm_runtime_disable(&pdev->dev); + iounmap(rfbi.base); +err_ioremap: + return r; } static int omap_rfbihw_remove(struct platform_device *pdev) { + pm_runtime_disable(&pdev->dev); iounmap(rfbi.base); return 0; } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 0bd4b03..3a688c8 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -20,13 +20,11 @@ #define DSS_SUBSYS_NAME "SDI" #include <linux/kernel.h> -#include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/regulator/consumer.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" static struct { @@ -60,14 +58,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err0; + goto err_start_dev; } r = regulator_enable(sdi.vdds_sdi_reg); if (r) - goto err1; + goto err_reg_enable; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + r = dss_runtime_get(); + if (r) + goto err_get_dss; + + r = dispc_runtime_get(); + if (r) + goto err_get_dispc; sdi_basic_init(dssdev); @@ -80,7 +84,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) r = dss_calc_clock_div(1, t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); if (r) - goto err2; + goto err_calc_clock_div; fck = dss_cinfo.fck; lck_div = dispc_cinfo.lck_div; @@ -101,27 +105,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) r = dss_set_clock_div(&dss_cinfo); if (r) - goto err2; + goto err_set_dss_clock_div; r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) - goto err2; + goto err_set_dispc_clock_div; dss_sdi_init(dssdev->phy.sdi.datapairs); r = dss_sdi_enable(); if (r) - goto err1; + goto err_sdi_enable; mdelay(2); dssdev->manager->enable(dssdev->manager); return 0; -err2: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + +err_sdi_enable: +err_set_dispc_clock_div: +err_set_dss_clock_div: +err_calc_clock_div: + dispc_runtime_put(); +err_get_dispc: + dss_runtime_put(); +err_get_dss: regulator_disable(sdi.vdds_sdi_reg); -err1: +err_reg_enable: omap_dss_stop_device(dssdev); -err0: +err_start_dev: return r; } EXPORT_SYMBOL(omapdss_sdi_display_enable); @@ -132,7 +143,8 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) dss_sdi_disable(); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dispc_runtime_put(); + dss_runtime_put(); regulator_disable(sdi.vdds_sdi_reg); diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 980f919..4491983 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -33,11 +33,13 @@ #include <linux/seq_file.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/pm_runtime.h> #include <video/omapdss.h> #include <plat/cpu.h> #include "dss.h" +#include "dss_features.h" /* Venc registers */ #define VENC_REV_ID 0x00 @@ -292,6 +294,12 @@ static struct { struct mutex venc_lock; u32 wss_data; struct regulator *vdda_dac_reg; + + struct mutex runtime_lock; + int runtime_count; + + struct clk *tv_clk; + struct clk *tv_dac_clk; } venc; static inline void venc_write_reg(int idx, u32 val) @@ -380,14 +388,71 @@ static void venc_reset(void) #endif } -static void venc_enable_clocks(int enable) +static int venc_runtime_get(void) +{ + int r; + + mutex_lock(&venc.runtime_lock); + + if (venc.runtime_count++ == 0) { + DSSDBG("venc_runtime_get\n"); + + r = dss_runtime_get(); + if (r) + goto err_get_dss; + + r = dispc_runtime_get(); + if (r) + goto err_get_dispc; + + clk_enable(venc.tv_clk); + if (venc.tv_dac_clk) + clk_enable(venc.tv_dac_clk); + + r = pm_runtime_get_sync(&venc.pdev->dev); + WARN_ON(r); + if (r < 0) + goto err_runtime_get; + } + + mutex_unlock(&venc.runtime_lock); + + return 0; + +err_runtime_get: + clk_disable(venc.tv_clk); + if (venc.tv_dac_clk) + clk_disable(venc.tv_dac_clk); + dispc_runtime_put(); +err_get_dispc: + dss_runtime_put(); +err_get_dss: + mutex_unlock(&venc.runtime_lock); + + return r; +} + +static void venc_runtime_put(void) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | - DSS_CLK_VIDFCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | - DSS_CLK_VIDFCK); + mutex_lock(&venc.runtime_lock); + + if (--venc.runtime_count == 0) { + int r; + + DSSDBG("venc_runtime_put\n"); + + r = pm_runtime_put_sync(&venc.pdev->dev); + WARN_ON(r); + + clk_disable(venc.tv_clk); + if (venc.tv_dac_clk) + clk_disable(venc.tv_dac_clk); + + dispc_runtime_put(); + dss_runtime_put(); + } + + mutex_unlock(&venc.runtime_lock); } static const struct venc_config *venc_timings_to_config( @@ -406,8 +471,6 @@ static void venc_power_on(struct omap_dss_device *dssdev) { u32 l; - venc_enable_clocks(1); - venc_reset(); venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); @@ -448,8 +511,6 @@ static void venc_power_off(struct omap_dss_device *dssdev) dssdev->platform_disable(dssdev); regulator_disable(venc.vdda_dac_reg); - - venc_enable_clocks(0); } @@ -487,6 +548,10 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) goto err1; } + r = venc_runtime_get(); + if (r) + goto err1; + venc_power_on(dssdev); venc.wss_data = 0; @@ -520,6 +585,8 @@ static void venc_panel_disable(struct omap_dss_device *dssdev) venc_power_off(dssdev); + venc_runtime_put(); + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; omap_dss_stop_device(dssdev); @@ -598,6 +665,7 @@ static u32 venc_get_wss(struct omap_dss_device *dssdev) static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) { const struct venc_config *config; + int r; DSSDBG("venc_set_wss\n"); @@ -608,16 +676,19 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) /* Invert due to VENC_L21_WC_CTL:INV=1 */ venc.wss_data = (wss ^ 0xfffff) << 8; - venc_enable_clocks(1); + r = venc_runtime_get(); + if (r) + goto err; venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | venc.wss_data); - venc_enable_clocks(0); + venc_runtime_put(); +err: mutex_unlock(&venc.venc_lock); - return 0; + return r; } static struct omap_dss_driver venc_driver = { @@ -673,7 +744,8 @@ void venc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) - venc_enable_clocks(1); + if (venc_runtime_get()) + return; DUMPREG(VENC_F_CONTROL); DUMPREG(VENC_VIDOUT_CTRL); @@ -717,16 +789,53 @@ void venc_dump_regs(struct seq_file *s) DUMPREG(VENC_OUTPUT_CONTROL); DUMPREG(VENC_OUTPUT_TEST); - venc_enable_clocks(0); + venc_runtime_put(); #undef DUMPREG } +static int venc_get_clocks(struct platform_device *pdev) +{ + struct clk *clk; + + clk = clk_get(&pdev->dev, "tv_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get tv_clk\n"); + return PTR_ERR(clk); + } + + venc.tv_clk = clk; + + if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) { + clk = clk_get(&pdev->dev, "tv_dac_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get tv_dac_clk\n"); + clk_put(venc.tv_clk); + return PTR_ERR(clk); + } + } else { + clk = NULL; + } + + venc.tv_dac_clk = clk; + + return 0; +} + +static void venc_put_clocks(void) +{ + if (venc.tv_clk) + clk_put(venc.tv_clk); + if (venc.tv_dac_clk) + clk_put(venc.tv_dac_clk); +} + /* VENC HW IP initialisation */ static int omap_venchw_probe(struct platform_device *pdev) { u8 rev_id; struct resource *venc_mem; + int r; venc.pdev = pdev; @@ -737,22 +846,41 @@ static int omap_venchw_probe(struct platform_device *pdev) venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); if (!venc_mem) { DSSERR("can't get IORESOURCE_MEM VENC\n"); - return -EINVAL; + r = -EINVAL; + goto err_ioremap; } venc.base = ioremap(venc_mem->start, resource_size(venc_mem)); if (!venc.base) { DSSERR("can't ioremap VENC\n"); - return -ENOMEM; + r = -ENOMEM; + goto err_ioremap; } - venc_enable_clocks(1); + r = venc_get_clocks(pdev); + if (r) + goto err_get_clk; + + mutex_init(&venc.runtime_lock); + pm_runtime_enable(&pdev->dev); + + r = venc_runtime_get(); + if (r) + goto err_get_venc; rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); - venc_enable_clocks(0); + venc_runtime_put(); return omap_dss_register_driver(&venc_driver); + +err_get_venc: + pm_runtime_disable(&pdev->dev); + venc_put_clocks(); +err_get_clk: + iounmap(venc.base); +err_ioremap: + return r; } static int omap_venchw_remove(struct platform_device *pdev) @@ -763,6 +891,9 @@ static int omap_venchw_remove(struct platform_device *pdev) } omap_dss_unregister_driver(&venc_driver); + pm_runtime_disable(&pdev->dev); + venc_put_clocks(); + iounmap(venc.base); return 0; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 505bc12..0a3e400 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -622,8 +622,9 @@ void set_fb_fix(struct fb_info *fbi) fix->smem_len = var->yres_virtual * fix->line_length; } else { - fix->line_length = - (var->xres_virtual * var->bits_per_pixel) >> 3; + /* SGX requires stride to be a multiple of 32 pixels */ + int xres_align = ALIGN(var->xres_virtual, 32); + fix->line_length = (xres_align * var->bits_per_pixel) >> 3; fix->smem_len = rg->size; } diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 892b97f..25fc1f3 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -21,8 +21,6 @@ #include <linux/list.h> #include <linux/kobject.h> #include <linux/device.h> -#include <linux/platform_device.h> -#include <asm/atomic.h> #define DISPC_IRQ_FRAMEDONE (1 << 0) #define DISPC_IRQ_VSYNC (1 << 1) @@ -126,6 +124,11 @@ enum omap_panel_config { OMAP_DSS_LCD_TFT = 1<<20, }; +enum omap_dss_dsi_type { + OMAP_DSS_DSI_TYPE_CMD_MODE = 0, + OMAP_DSS_DSI_TYPE_VIDEO_MODE, +}; + enum omap_dss_venc_type { OMAP_DSS_VENC_TYPE_COMPOSITE, OMAP_DSS_VENC_TYPE_SVIDEO, @@ -148,6 +151,11 @@ enum omap_dss_display_state { OMAP_DSS_DISPLAY_SUSPENDED, }; +enum omap_dispc_irq_type { + OMAP_DISPC_IRQ_TYPE_FRAMEDONE, + OMAP_DISPC_IRQ_TYPE_VSYNC, +}; + /* XXX perhaps this should be removed */ enum omap_dss_overlay_managers { OMAP_DSS_OVL_MGR_LCD, @@ -244,9 +252,11 @@ int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel, int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel); +int dsi_video_mode_enable(struct omap_dss_device *dssdev, u8 data_type); + /* Board specific data */ struct omap_dss_board_info { - int (*get_last_off_on_transaction_id)(struct device *dev); + int (*get_context_loss_count)(struct device *dev); int num_devices; struct omap_dss_device **devices; struct omap_dss_device *default_device; @@ -266,8 +276,6 @@ static inline int omap_display_init(struct omap_dss_board_info *board_data) struct omap_display_platform_data { struct omap_dss_board_info *board_data; /* TODO: Additional members to be added when PM is considered */ - - bool (*opt_clock_available)(const char *clk_role); }; struct omap_video_timings { @@ -420,6 +428,7 @@ struct omap_dss_device { } sdi; struct { + enum omap_dss_dsi_type type; u8 clk_lane; u8 clk_pol; u8 data1_lane; @@ -430,7 +439,6 @@ struct omap_dss_device { u8 data3_pol; u8 data4_lane; u8 data4_pol; - int module; bool ext_te; @@ -596,6 +604,8 @@ int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout); int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, unsigned long timeout); +void omap_dispc_set_irq_type(int channel, enum omap_dispc_irq_type type); + #define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver) #define to_dss_device(x) container_of((x), struct omap_dss_device, dev) |