diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-03-08 20:21:04 +0000 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-03-08 20:21:04 +0000 |
commit | 988addf82e4c03739375279de73929580a2d4a6a (patch) | |
tree | 989ae1cd4e264bbad80c65f04480486246e7b9f3 /drivers/video/omap2/dss | |
parent | 004c1c7096659d352b83047a7593e91d8a30e3c5 (diff) | |
parent | 25cf84cf377c0aae5dbcf937ea89bc7893db5176 (diff) |
Merge branch 'origin' into devel-stable
Conflicts:
arch/arm/mach-mx2/devices.c
arch/arm/mach-mx2/devices.h
sound/soc/pxa/pxa-ssp.c
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r-- | drivers/video/omap2/dss/Kconfig | 26 | ||||
-rw-r--r-- | drivers/video/omap2/dss/core.c | 117 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 42 | ||||
-rw-r--r-- | drivers/video/omap2/dss/display.c | 119 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dpi.c | 144 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 1031 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.c | 42 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.h | 23 | ||||
-rw-r--r-- | drivers/video/omap2/dss/manager.c | 48 | ||||
-rw-r--r-- | drivers/video/omap2/dss/overlay.c | 2 | ||||
-rw-r--r-- | drivers/video/omap2/dss/rfbi.c | 321 | ||||
-rw-r--r-- | drivers/video/omap2/dss/sdi.c | 115 | ||||
-rw-r--r-- | drivers/video/omap2/dss/venc.c | 296 |
13 files changed, 729 insertions, 1597 deletions
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index c63ce767b27..87afb81b2c4 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -30,19 +30,29 @@ config OMAP2_DSS_COLLECT_IRQ_STATS depends on OMAP2_DSS_DEBUG_SUPPORT default n help - Collect DSS IRQ statistics, printable via debugfs + Collect DSS IRQ statistics, printable via debugfs. + + The statistics can be found from + <debugfs>/omapdss/dispc_irq for DISPC interrupts, and + <debugfs>/omapdss/dsi_irq for DSI interrupts. config OMAP2_DSS_RFBI bool "RFBI support" default n help - MIPI DBI, or RFBI (Remote Framebuffer Interface), support. + MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas + Instrument's terminology). + + DBI is a bus between the host processor and a peripheral, + such as a display or a framebuffer chip. + + See http://www.mipi.org/ for DBI spesifications. config OMAP2_DSS_VENC bool "VENC support" default y help - OMAP Video Encoder support. + OMAP Video Encoder support for S-Video and composite TV-out. config OMAP2_DSS_SDI bool "SDI support" @@ -51,12 +61,20 @@ config OMAP2_DSS_SDI help SDI (Serial Display Interface) support. + SDI is a high speed one-way display serial bus between the host + processor and a display. + config OMAP2_DSS_DSI bool "DSI support" depends on ARCH_OMAP3 default n help - MIPI DSI support. + MIPI DSI (Display Serial Interface) support. + + DSI is a high speed half-duplex serial interface between the host + processor and a peripheral, such as a display or a framebuffer chip. + + See http://www.mipi.org/ for DSI spesifications. config OMAP2_DSS_USE_DSI_PLL bool "Use DSI PLL for PCLK (EXPERIMENTAL)" diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 82918eec6d2..7ebe50b335e 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -31,6 +31,7 @@ #include <linux/debugfs.h> #include <linux/io.h> #include <linux/device.h> +#include <linux/regulator/consumer.h> #include <plat/display.h> #include <plat/clock.h> @@ -47,6 +48,10 @@ static struct { struct clk *dss_54m_fck; struct clk *dss_96m_fck; unsigned num_clks_enabled; + + struct regulator *vdds_dsi_reg; + struct regulator *vdds_sdi_reg; + struct regulator *vdda_dac_reg; } core; static void dss_clk_enable_all_no_ctx(void); @@ -284,9 +289,11 @@ static void dss_clk_enable_no_ctx(enum dss_clock clks) void dss_clk_enable(enum dss_clock clks) { + bool check_ctx = core.num_clks_enabled == 0; + dss_clk_enable_no_ctx(clks); - if (cpu_is_omap34xx() && dss_need_ctx_restore()) + if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore()) restore_all_ctx(); } @@ -352,6 +359,50 @@ static void dss_clk_disable_all(void) dss_clk_disable(clks); } +/* REGULATORS */ + +struct regulator *dss_get_vdds_dsi(void) +{ + struct regulator *reg; + + if (core.vdds_dsi_reg != NULL) + return core.vdds_dsi_reg; + + reg = regulator_get(&core.pdev->dev, "vdds_dsi"); + if (!IS_ERR(reg)) + core.vdds_dsi_reg = reg; + + return reg; +} + +struct regulator *dss_get_vdds_sdi(void) +{ + struct regulator *reg; + + if (core.vdds_sdi_reg != NULL) + return core.vdds_sdi_reg; + + reg = regulator_get(&core.pdev->dev, "vdds_sdi"); + if (!IS_ERR(reg)) + core.vdds_sdi_reg = reg; + + return reg; +} + +struct regulator *dss_get_vdda_dac(void) +{ + struct regulator *reg; + + if (core.vdda_dac_reg != NULL) + return core.vdda_dac_reg; + + reg = regulator_get(&core.pdev->dev, "vdda_dac"); + if (!IS_ERR(reg)) + core.vdda_dac_reg = reg; + + return reg; +} + /* DEBUGFS */ #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) static void dss_debug_dump_clocks(struct seq_file *s) @@ -397,10 +448,12 @@ static int dss_initialize_debugfs(void) debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, &dss_debug_dump_clocks, &dss_debug_fops); +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir, &dispc_dump_irqs, &dss_debug_fops); +#endif -#ifdef CONFIG_OMAP2_DSS_DSI +#if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS) debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir, &dsi_dump_irqs, &dss_debug_fops); #endif @@ -473,7 +526,7 @@ static int omap_dss_probe(struct platform_device *pdev) } #endif - r = dpi_init(); + r = dpi_init(pdev); if (r) { DSSERR("Failed to initialize dpi\n"); goto fail0; @@ -718,16 +771,14 @@ static int dss_driver_probe(struct device *dev) dss_init_device(core.pdev, dssdev); - /* skip this if the device is behind a ctrl */ - if (!dssdev->panel.ctrl) { - force = pdata->default_device == dssdev; - dss_recheck_connections(dssdev, force); - } + force = pdata->default_device == dssdev; + dss_recheck_connections(dssdev, force); r = dssdrv->probe(dssdev); if (r) { DSSERR("driver probe failed: %d\n", r); + dss_uninit_device(core.pdev, dssdev); return r; } @@ -760,6 +811,13 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver) dssdriver->driver.bus = &dss_bus_type; dssdriver->driver.probe = dss_driver_probe; dssdriver->driver.remove = dss_driver_remove; + + if (dssdriver->get_resolution == NULL) + dssdriver->get_resolution = omapdss_default_get_resolution; + if (dssdriver->get_recommended_bpp == NULL) + dssdriver->get_recommended_bpp = + omapdss_default_get_recommended_bpp; + return driver_register(&dssdriver->driver); } EXPORT_SYMBOL(omap_dss_register_driver); @@ -808,8 +866,6 @@ static void omap_dss_dev_release(struct device *dev) int omap_dss_register_device(struct omap_dss_device *dssdev) { static int dev_num; - static int panel_num; - int r; WARN_ON(!dssdev->driver_name); @@ -818,36 +874,12 @@ int omap_dss_register_device(struct omap_dss_device *dssdev) dssdev->dev.parent = &dss_bus; dssdev->dev.release = omap_dss_dev_release; dev_set_name(&dssdev->dev, "display%d", dev_num++); - r = device_register(&dssdev->dev); - if (r) - return r; - - if (dssdev->ctrl.panel) { - struct omap_dss_device *panel = dssdev->ctrl.panel; - - panel->panel.ctrl = dssdev; - - reset_device(&panel->dev, 1); - panel->dev.bus = &dss_bus_type; - panel->dev.parent = &dssdev->dev; - panel->dev.release = omap_dss_dev_release; - dev_set_name(&panel->dev, "panel%d", panel_num++); - r = device_register(&panel->dev); - if (r) - return r; - } - - return 0; + return device_register(&dssdev->dev); } void omap_dss_unregister_device(struct omap_dss_device *dssdev) { device_unregister(&dssdev->dev); - - if (dssdev->ctrl.panel) { - struct omap_dss_device *panel = dssdev->ctrl.panel; - device_unregister(&panel->dev); - } } /* BUS */ @@ -901,6 +933,21 @@ static int __init omap_dss_init(void) static void __exit omap_dss_exit(void) { + if (core.vdds_dsi_reg != NULL) { + regulator_put(core.vdds_dsi_reg); + core.vdds_dsi_reg = NULL; + } + + if (core.vdds_sdi_reg != NULL) { + regulator_put(core.vdds_sdi_reg); + core.vdds_sdi_reg = NULL; + } + + if (core.vdda_dac_reg != NULL) { + regulator_put(core.vdda_dac_reg); + core.vdda_dac_reg = NULL; + } + platform_driver_unregister(&omap_dss_driver); omap_dss_bus_unregister(); diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index de8bfbac9e2..e777e352dbc 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1725,7 +1725,7 @@ static void _enable_lcd_out(bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); } -void dispc_enable_lcd_out(bool enable) +static void dispc_enable_lcd_out(bool enable) { struct completion frame_done_completion; bool is_on; @@ -1772,7 +1772,7 @@ static void _enable_digit_out(bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); } -void dispc_enable_digit_out(bool enable) +static void dispc_enable_digit_out(bool enable) { struct completion frame_done_completion; int r; @@ -1836,6 +1836,26 @@ void dispc_enable_digit_out(bool enable) enable_clocks(0); } +bool dispc_is_channel_enabled(enum omap_channel channel) +{ + if (channel == OMAP_DSS_CHANNEL_LCD) + return !!REG_GET(DISPC_CONTROL, 0, 0); + else if (channel == OMAP_DSS_CHANNEL_DIGIT) + return !!REG_GET(DISPC_CONTROL, 1, 1); + else + BUG(); +} + +void dispc_enable_channel(enum omap_channel channel, bool enable) +{ + if (channel == OMAP_DSS_CHANNEL_LCD) + dispc_enable_lcd_out(enable); + else if (channel == OMAP_DSS_CHANNEL_DIGIT) + dispc_enable_digit_out(enable); + else + BUG(); +} + void dispc_lcd_enable_signal_polarity(bool act_high) { enable_clocks(1); @@ -2198,7 +2218,7 @@ unsigned long dispc_fclk_rate(void) { unsigned long r = 0; - if (dss_get_dispc_clk_source() == 0) + if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) r = dss_clk_get_rate(DSS_CLK_FCK1); else #ifdef CONFIG_OMAP2_DSS_DSI @@ -2251,7 +2271,7 @@ void dispc_dump_clocks(struct seq_file *s) seq_printf(s, "- DISPC -\n"); seq_printf(s, "dispc fclk source = %s\n", - dss_get_dispc_clk_source() == 0 ? + dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? "dss1_alwon_fclk" : "dsi1_pll_fclk"); seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); @@ -2301,8 +2321,6 @@ void dispc_dump_irqs(struct seq_file *s) PIS(WAKEUP); #undef PIS } -#else -void dispc_dump_irqs(struct seq_file *s) { } #endif void dispc_dump_regs(struct seq_file *s) @@ -2854,12 +2872,13 @@ static void dispc_error_worker(struct work_struct *work) manager = mgr; enable = mgr->device->state == OMAP_DSS_DISPLAY_ACTIVE; - mgr->device->disable(mgr->device); + mgr->device->driver->disable(mgr->device); break; } } if (manager) { + struct omap_dss_device *dssdev = manager->device; for (i = 0; i < omap_dss_get_num_overlays(); ++i) { struct omap_overlay *ovl; ovl = omap_dss_get_overlay(i); @@ -2874,7 +2893,7 @@ static void dispc_error_worker(struct work_struct *work) dispc_go(manager->id); mdelay(50); if (enable) - manager->device->enable(manager->device); + dssdev->driver->enable(dssdev); } } @@ -2892,12 +2911,13 @@ static void dispc_error_worker(struct work_struct *work) manager = mgr; enable = mgr->device->state == OMAP_DSS_DISPLAY_ACTIVE; - mgr->device->disable(mgr->device); + mgr->device->driver->disable(mgr->device); break; } } if (manager) { + struct omap_dss_device *dssdev = manager->device; for (i = 0; i < omap_dss_get_num_overlays(); ++i) { struct omap_overlay *ovl; ovl = omap_dss_get_overlay(i); @@ -2912,7 +2932,7 @@ static void dispc_error_worker(struct work_struct *work) dispc_go(manager->id); mdelay(50); if (enable) - manager->device->enable(manager->device); + dssdev->driver->enable(dssdev); } } @@ -2923,7 +2943,7 @@ static void dispc_error_worker(struct work_struct *work) mgr = omap_dss_get_overlay_manager(i); if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC) - mgr->device->disable(mgr->device); + mgr->device->driver->disable(mgr->device); } } diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 3b92b84b956..6a74ea116d2 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -53,11 +53,11 @@ static ssize_t display_enabled_store(struct device *dev, if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { if (enabled) { - r = dssdev->enable(dssdev); + r = dssdev->driver->enable(dssdev); if (r) return r; } else { - dssdev->disable(dssdev); + dssdev->driver->disable(dssdev); } } @@ -69,8 +69,8 @@ static ssize_t display_upd_mode_show(struct device *dev, { struct omap_dss_device *dssdev = to_dss_device(dev); enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO; - if (dssdev->get_update_mode) - mode = dssdev->get_update_mode(dssdev); + if (dssdev->driver->get_update_mode) + mode = dssdev->driver->get_update_mode(dssdev); return snprintf(buf, PAGE_SIZE, "%d\n", mode); } @@ -94,7 +94,7 @@ static ssize_t display_upd_mode_store(struct device *dev, return -EINVAL; } - r = dssdev->set_update_mode(dssdev, mode); + r = dssdev->driver->set_update_mode(dssdev, mode); if (r) return r; @@ -106,7 +106,8 @@ static ssize_t display_tear_show(struct device *dev, { struct omap_dss_device *dssdev = to_dss_device(dev); return snprintf(buf, PAGE_SIZE, "%d\n", - dssdev->get_te ? dssdev->get_te(dssdev) : 0); + dssdev->driver->get_te ? + dssdev->driver->get_te(dssdev) : 0); } static ssize_t display_tear_store(struct device *dev, @@ -116,12 +117,12 @@ static ssize_t display_tear_store(struct device *dev, unsigned long te; int r; - if (!dssdev->enable_te || !dssdev->get_te) + if (!dssdev->driver->enable_te || !dssdev->driver->get_te) return -ENOENT; te = simple_strtoul(buf, NULL, 0); - r = dssdev->enable_te(dssdev, te); + r = dssdev->driver->enable_te(dssdev, te); if (r) return r; @@ -134,10 +135,10 @@ static ssize_t display_timings_show(struct device *dev, struct omap_dss_device *dssdev = to_dss_device(dev); struct omap_video_timings t; - if (!dssdev->get_timings) + if (!dssdev->driver->get_timings) return -ENOENT; - dssdev->get_timings(dssdev, &t); + dssdev->driver->get_timings(dssdev, &t); return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", t.pixel_clock, @@ -152,7 +153,7 @@ static ssize_t display_timings_store(struct device *dev, struct omap_video_timings t; int r, found; - if (!dssdev->set_timings || !dssdev->check_timings) + if (!dssdev->driver->set_timings || !dssdev->driver->check_timings) return -ENOENT; found = 0; @@ -171,11 +172,11 @@ static ssize_t display_timings_store(struct device *dev, &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) return -EINVAL; - r = dssdev->check_timings(dssdev, &t); + r = dssdev->driver->check_timings(dssdev, &t); if (r) return r; - dssdev->set_timings(dssdev, &t); + dssdev->driver->set_timings(dssdev, &t); return size; } @@ -185,9 +186,9 @@ static ssize_t display_rotate_show(struct device *dev, { struct omap_dss_device *dssdev = to_dss_device(dev); int rotate; - if (!dssdev->get_rotate) + if (!dssdev->driver->get_rotate) return -ENOENT; - rotate = dssdev->get_rotate(dssdev); + rotate = dssdev->driver->get_rotate(dssdev); return snprintf(buf, PAGE_SIZE, "%u\n", rotate); } @@ -198,12 +199,12 @@ static ssize_t display_rotate_store(struct device *dev, unsigned long rot; int r; - if (!dssdev->set_rotate || !dssdev->get_rotate) + if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) return -ENOENT; rot = simple_strtoul(buf, NULL, 0); - r = dssdev->set_rotate(dssdev, rot); + r = dssdev->driver->set_rotate(dssdev, rot); if (r) return r; @@ -215,9 +216,9 @@ static ssize_t display_mirror_show(struct device *dev, { struct omap_dss_device *dssdev = to_dss_device(dev); int mirror; - if (!dssdev->get_mirror) + if (!dssdev->driver->get_mirror) return -ENOENT; - mirror = dssdev->get_mirror(dssdev); + mirror = dssdev->driver->get_mirror(dssdev); return snprintf(buf, PAGE_SIZE, "%u\n", mirror); } @@ -228,12 +229,12 @@ static ssize_t display_mirror_store(struct device *dev, unsigned long mirror; int r; - if (!dssdev->set_mirror || !dssdev->get_mirror) + if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) return -ENOENT; mirror = simple_strtoul(buf, NULL, 0); - r = dssdev->set_mirror(dssdev, mirror); + r = dssdev->driver->set_mirror(dssdev, mirror); if (r) return r; @@ -246,10 +247,10 @@ static ssize_t display_wss_show(struct device *dev, struct omap_dss_device *dssdev = to_dss_device(dev); unsigned int wss; - if (!dssdev->get_wss) + if (!dssdev->driver->get_wss) return -ENOENT; - wss = dssdev->get_wss(dssdev); + wss = dssdev->driver->get_wss(dssdev); return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss); } @@ -261,7 +262,7 @@ static ssize_t display_wss_store(struct device *dev, unsigned long wss; int r; - if (!dssdev->get_wss || !dssdev->set_wss) + if (!dssdev->driver->get_wss || !dssdev->driver->set_wss) return -ENOENT; if (strict_strtoul(buf, 0, &wss)) @@ -270,7 +271,7 @@ static ssize_t display_wss_store(struct device *dev, if (wss > 0xfffff) return -EINVAL; - r = dssdev->set_wss(dssdev, wss); + r = dssdev->driver->set_wss(dssdev, wss); if (r) return r; @@ -303,12 +304,13 @@ static struct device_attribute *display_sysfs_attrs[] = { NULL }; -static void default_get_resolution(struct omap_dss_device *dssdev, +void omapdss_default_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres) { *xres = dssdev->panel.timings.x_res; *yres = dssdev->panel.timings.y_res; } +EXPORT_SYMBOL(omapdss_default_get_resolution); void default_get_overlay_fifo_thresholds(enum omap_plane plane, u32 fifo_size, enum omap_burst_size *burst_size, @@ -323,24 +325,8 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane, *fifo_low = fifo_size - burst_size_bytes; } -static int default_wait_vsync(struct omap_dss_device *dssdev) +int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) { - unsigned long timeout = msecs_to_jiffies(500); - u32 irq; - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) - irq = DISPC_IRQ_EVSYNC_ODD; - else - irq = DISPC_IRQ_VSYNC; - - return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); -} - -static int default_get_recommended_bpp(struct omap_dss_device *dssdev) -{ - if (dssdev->panel.recommended_bpp) - return dssdev->panel.recommended_bpp; - switch (dssdev->type) { case OMAP_DISPLAY_TYPE_DPI: if (dssdev->phy.dpi.data_lines == 24) @@ -362,6 +348,7 @@ static int default_get_recommended_bpp(struct omap_dss_device *dssdev) BUG(); } } +EXPORT_SYMBOL(omapdss_default_get_recommended_bpp); /* Checks if replication logic should be used. Only use for active matrix, * when overlay is in RGB12U or RGB16 mode, and LCD interface is @@ -425,10 +412,6 @@ void dss_init_device(struct platform_device *pdev, return; } - dssdev->get_resolution = default_get_resolution; - dssdev->get_recommended_bpp = default_get_recommended_bpp; - dssdev->wait_vsync = default_wait_vsync; - switch (dssdev->type) { case OMAP_DISPLAY_TYPE_DPI: r = dpi_init_display(dssdev); @@ -502,13 +485,13 @@ static int dss_suspend_device(struct device *dev, void *data) return 0; } - if (!dssdev->suspend) { + if (!dssdev->driver->suspend) { DSSERR("display '%s' doesn't implement suspend\n", dssdev->name); return -ENOSYS; } - r = dssdev->suspend(dssdev); + r = dssdev->driver->suspend(dssdev); if (r) return r; @@ -537,8 +520,8 @@ static int dss_resume_device(struct device *dev, void *data) int r; struct omap_dss_device *dssdev = to_dss_device(dev); - if (dssdev->activate_after_resume && dssdev->resume) { - r = dssdev->resume(dssdev); + if (dssdev->activate_after_resume && dssdev->driver->resume) { + r = dssdev->driver->resume(dssdev); if (r) return r; } @@ -558,7 +541,7 @@ int dss_resume_all_devices(void) static int dss_disable_device(struct device *dev, void *data) { struct omap_dss_device *dssdev = to_dss_device(dev); - dssdev->disable(dssdev); + dssdev->driver->disable(dssdev); return 0; } @@ -591,10 +574,6 @@ struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from) int match(struct device *dev, void *data) { - /* skip panels connected to controllers */ - if (to_dss_device(dev)->panel.ctrl) - return 0; - return 1; } @@ -626,45 +605,21 @@ EXPORT_SYMBOL(omap_dss_find_device); int omap_dss_start_device(struct omap_dss_device *dssdev) { - int r; - if (!dssdev->driver) { DSSDBG("no driver\n"); - r = -ENODEV; - goto err0; - } - - if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) { - DSSDBG("no panel driver\n"); - r = -ENODEV; - goto err0; + return -ENODEV; } if (!try_module_get(dssdev->dev.driver->owner)) { - r = -ENODEV; - goto err0; - } - - if (dssdev->ctrl.panel) { - if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) { - r = -ENODEV; - goto err1; - } + return -ENODEV; } return 0; -err1: - module_put(dssdev->dev.driver->owner); -err0: - return r; } EXPORT_SYMBOL(omap_dss_start_device); void omap_dss_stop_device(struct omap_dss_device *dssdev) { - if (dssdev->ctrl.panel) - module_put(dssdev->ctrl.panel->dev.driver->owner); - module_put(dssdev->dev.driver->owner); } EXPORT_SYMBOL(omap_dss_stop_device); diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 2d71031baa2..960e977a8bf 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -25,7 +25,10 @@ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/err.h> #include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <plat/display.h> #include <plat/cpu.h> @@ -33,7 +36,7 @@ #include "dss.h" static struct { - int update_enabled; + struct regulator *vdds_dsi_reg; } dpi; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL @@ -53,7 +56,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, if (r) return r; - dss_select_clk_source(0, 1); + dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); r = dispc_set_clock_div(&dispc_cinfo); if (r) @@ -150,7 +153,7 @@ static int dpi_basic_init(struct omap_dss_device *dssdev) return 0; } -static int dpi_display_enable(struct omap_dss_device *dssdev) +int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) { int r; @@ -160,10 +163,10 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) goto err0; } - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { - DSSERR("display already enabled\n"); - r = -EINVAL; - goto err1; + if (cpu_is_omap34xx()) { + r = regulator_enable(dpi.vdds_dsi_reg); + if (r) + goto err1; } dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); @@ -184,18 +187,10 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - dispc_enable_lcd_out(1); - - r = dssdev->driver->enable(dssdev); - if (r) - goto err5; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + dssdev->manager->enable(dssdev->manager); return 0; -err5: - dispc_enable_lcd_out(0); err4: #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL dsi_pll_uninit(); @@ -204,78 +199,35 @@ err3: #endif err2: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + if (cpu_is_omap34xx()) + regulator_disable(dpi.vdds_dsi_reg); err1: omap_dss_stop_device(dssdev); err0: return r; } +EXPORT_SYMBOL(omapdss_dpi_display_enable); -static int dpi_display_resume(struct omap_dss_device *dssdev); - -static void dpi_display_disable(struct omap_dss_device *dssdev) +void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) { - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) - return; - - if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) - dpi_display_resume(dssdev); - - dssdev->driver->disable(dssdev); - - dispc_enable_lcd_out(0); + dssdev->manager->disable(dssdev->manager); #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL - dss_select_clk_source(0, 0); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dsi_pll_uninit(); dss_clk_disable(DSS_CLK_FCK2); #endif dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + if (cpu_is_omap34xx()) + regulator_disable(dpi.vdds_dsi_reg); omap_dss_stop_device(dssdev); } +EXPORT_SYMBOL(omapdss_dpi_display_disable); -static int dpi_display_suspend(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return -EINVAL; - - DSSDBG("dpi_display_suspend\n"); - - if (dssdev->driver->suspend) - dssdev->driver->suspend(dssdev); - - dispc_enable_lcd_out(0); - - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - return 0; -} - -static int dpi_display_resume(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) - return -EINVAL; - - DSSDBG("dpi_display_resume\n"); - - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - - dispc_enable_lcd_out(1); - - if (dssdev->driver->resume) - dssdev->driver->resume(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void dpi_set_timings(struct omap_dss_device *dssdev, +void dpi_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { DSSDBG("dpi_set_timings\n"); @@ -285,8 +237,9 @@ static void dpi_set_timings(struct omap_dss_device *dssdev, dispc_go(OMAP_DSS_CHANNEL_LCD); } } +EXPORT_SYMBOL(dpi_set_timings); -static int dpi_check_timings(struct omap_dss_device *dssdev, +int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { bool is_tft; @@ -340,56 +293,25 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, return 0; } - -static void dpi_get_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) -{ - *timings = dssdev->panel.timings; -} - -static int dpi_display_set_update_mode(struct omap_dss_device *dssdev, - enum omap_dss_update_mode mode) -{ - if (mode == OMAP_DSS_UPDATE_MANUAL) - return -EINVAL; - - if (mode == OMAP_DSS_UPDATE_DISABLED) { - dispc_enable_lcd_out(0); - dpi.update_enabled = 0; - } else { - dispc_enable_lcd_out(1); - dpi.update_enabled = 1; - } - - return 0; -} - -static enum omap_dss_update_mode dpi_display_get_update_mode( - struct omap_dss_device *dssdev) -{ - return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO : - OMAP_DSS_UPDATE_DISABLED; -} +EXPORT_SYMBOL(dpi_check_timings); int dpi_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); - dssdev->enable = dpi_display_enable; - dssdev->disable = dpi_display_disable; - dssdev->suspend = dpi_display_suspend; - dssdev->resume = dpi_display_resume; - dssdev->set_timings = dpi_set_timings; - dssdev->check_timings = dpi_check_timings; - dssdev->get_timings = dpi_get_timings; - dssdev->set_update_mode = dpi_display_set_update_mode; - dssdev->get_update_mode = dpi_display_get_update_mode; - return 0; } -int dpi_init(void) +int dpi_init(struct platform_device *pdev) { + if (cpu_is_omap34xx()) { + dpi.vdds_dsi_reg = dss_get_vdds_dsi(); + if (IS_ERR(dpi.vdds_dsi_reg)) { + DSSERR("can't get VDDS_DSI regulator\n"); + return PTR_ERR(dpi.vdds_dsi_reg); + } + } + return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 6122178f5f8..3af207b2bde 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -27,11 +27,12 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/semaphore.h> #include <linux/seq_file.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> -#include <linux/kthread.h> #include <linux/wait.h> +#include <linux/workqueue.h> #include <plat/display.h> #include <plat/clock.h> @@ -199,7 +200,6 @@ enum dsi_vc_mode { }; struct dsi_update_region { - bool dirty; u16 x, y, w, h; struct omap_dss_device *device; }; @@ -224,29 +224,25 @@ static struct enum dsi_vc_mode mode; struct omap_dss_device *dssdev; enum fifo_size fifo_size; - int dest_per; /* destination peripheral 0-3 */ } vc[4]; struct mutex lock; - struct mutex bus_lock; + struct semaphore bus_lock; unsigned pll_locked; struct completion bta_completion; - struct task_struct *thread; - wait_queue_head_t waitqueue; - - spinlock_t update_lock; - bool framedone_received; + int update_channel; struct dsi_update_region update_region; - struct dsi_update_region active_update_region; - struct completion update_completion; - enum omap_dss_update_mode user_update_mode; - enum omap_dss_update_mode update_mode; bool te_enabled; - bool use_ext_te; + + struct work_struct framedone_work; + void (*framedone_callback)(int, void *); + void *framedone_data; + + struct delayed_work framedone_timeout_work; #ifdef DSI_CATCH_MISSING_TE struct timer_list te_timer; @@ -261,8 +257,6 @@ static struct #ifdef DEBUG ktime_t perf_setup_time; ktime_t perf_start_time; - ktime_t perf_start_time_auto; - int perf_measure_frames; #endif int debug_read; int debug_write; @@ -299,16 +293,21 @@ void dsi_restore_context(void) void dsi_bus_lock(void) { - mutex_lock(&dsi.bus_lock); + down(&dsi.bus_lock); } EXPORT_SYMBOL(dsi_bus_lock); void dsi_bus_unlock(void) { - mutex_unlock(&dsi.bus_lock); + up(&dsi.bus_lock); } EXPORT_SYMBOL(dsi_bus_unlock); +static bool dsi_bus_is_locked(void) +{ + return dsi.bus_lock.count == 0; +} + static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum, int value) { @@ -333,12 +332,6 @@ static void dsi_perf_mark_start(void) dsi.perf_start_time = ktime_get(); } -static void dsi_perf_mark_start_auto(void) -{ - dsi.perf_measure_frames = 0; - dsi.perf_start_time_auto = ktime_get(); -} - static void dsi_perf_show(const char *name) { ktime_t t, setup_time, trans_time; @@ -348,9 +341,6 @@ static void dsi_perf_show(const char *name) if (!dsi_perf) return; - if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED) - return; - t = ktime_get(); setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time); @@ -365,76 +355,23 @@ static void dsi_perf_show(const char *name) total_us = setup_us + trans_us; - total_bytes = dsi.active_update_region.w * - dsi.active_update_region.h * - dsi.active_update_region.device->ctrl.pixel_size / 8; - - if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) { - static u32 s_total_trans_us, s_total_setup_us; - static u32 s_min_trans_us = 0xffffffff, s_min_setup_us; - static u32 s_max_trans_us, s_max_setup_us; - const int numframes = 100; - ktime_t total_time_auto; - u32 total_time_auto_us; - - dsi.perf_measure_frames++; - - if (setup_us < s_min_setup_us) - s_min_setup_us = setup_us; + total_bytes = dsi.update_region.w * + dsi.update_region.h * + dsi.update_region.device->ctrl.pixel_size / 8; - if (setup_us > s_max_setup_us) - s_max_setup_us = setup_us; - - s_total_setup_us += setup_us; - - if (trans_us < s_min_trans_us) - s_min_trans_us = trans_us; - - if (trans_us > s_max_trans_us) - s_max_trans_us = trans_us; - - s_total_trans_us += trans_us; - - if (dsi.perf_measure_frames < numframes) - return; - - total_time_auto = ktime_sub(t, dsi.perf_start_time_auto); - total_time_auto_us = (u32)ktime_to_us(total_time_auto); - - printk(KERN_INFO "DSI(%s): %u fps, setup %u/%u/%u, " - "trans %u/%u/%u\n", - name, - 1000 * 1000 * numframes / total_time_auto_us, - s_min_setup_us, - s_max_setup_us, - s_total_setup_us / numframes, - s_min_trans_us, - s_max_trans_us, - s_total_trans_us / numframes); - - s_total_setup_us = 0; - s_min_setup_us = 0xffffffff; - s_max_setup_us = 0; - s_total_trans_us = 0; - s_min_trans_us = 0xffffffff; - s_max_trans_us = 0; - dsi_perf_mark_start_auto(); - } else { - printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " - "%u bytes, %u kbytes/sec\n", - name, - setup_us, - trans_us, - total_us, - 1000*1000 / total_us, - total_bytes, - total_bytes * 1000 / total_us); - } + printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " + "%u bytes, %u kbytes/sec\n", + name, + setup_us, + trans_us, + total_us, + 1000*1000 / total_us, + total_bytes, + total_bytes * 1000 / total_us); } #else #define dsi_perf_mark_setup() #define dsi_perf_mark_start() -#define dsi_perf_mark_start_auto() #define dsi_perf_show(x) #endif @@ -774,7 +711,7 @@ static unsigned long dsi_fclk_rate(void) { unsigned long r; - if (dss_get_dsi_clk_source() == 0) { + if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) { /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */ r = dss_clk_get_rate(DSS_CLK_FCK1); } else { @@ -1227,17 +1164,19 @@ void dsi_dump_clocks(struct seq_file *s) seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n", cinfo->dsi1_pll_fclk, cinfo->regm3, - dss_get_dispc_clk_source() == 0 ? "off" : "on"); + dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? + "off" : "on"); seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n", cinfo->dsi2_pll_fclk, cinfo->regm4, - dss_get_dsi_clk_source() == 0 ? "off" : "on"); + dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? + "off" : "on"); seq_printf(s, "- DSI -\n"); seq_printf(s, "dsi fclk source = %s\n", - dss_get_dsi_clk_source() == 0 ? + dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? "dss1_alwon_fclk" : "dsi2_pll_fclk"); seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate()); @@ -1756,29 +1695,10 @@ static int dsi_force_tx_stop_mode_io(void) return 0; } -static void dsi_vc_print_status(int channel) -{ - u32 r; - - r = dsi_read_reg(DSI_VC_CTRL(channel)); - DSSDBG("vc %d: TX_FIFO_NOT_EMPTY %d, BTA_EN %d, VC_BUSY %d, " - "TX_FIFO_FULL %d, RX_FIFO_NOT_EMPTY %d, ", - channel, - FLD_GET(r, 5, 5), - FLD_GET(r, 6, 6), - FLD_GET(r, 15, 15), - FLD_GET(r, 16, 16), - FLD_GET(r, 20, 20)); - - r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS); - DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff); -} - static int dsi_vc_enable(int channel, bool enable) { - if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO) - DSSDBG("dsi_vc_enable channel %d, enable %d\n", - channel, enable); + DSSDBG("dsi_vc_enable channel %d, enable %d\n", + channel, enable); enable = enable ? 1 : 0; @@ -1859,10 +1779,12 @@ static void dsi_vc_config_vp(int channel) } -static void dsi_vc_enable_hs(int channel, bool enable) +void omapdss_dsi_vc_enable_hs(int channel, bool enable) { DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); + WARN_ON(!dsi_bus_is_locked()); + dsi_vc_enable(channel, 0); dsi_if_enable(0); @@ -1873,6 +1795,7 @@ static void dsi_vc_enable_hs(int channel, bool enable) dsi_force_tx_stop_mode_io(); } +EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); static void dsi_vc_flush_long_data(int channel) { @@ -1955,11 +1878,10 @@ static u16 dsi_vc_flush_receive_data(int channel) static int dsi_vc_send_bta(int channel) { - if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO && - (dsi.debug_write || dsi.debug_read)) + if (dsi.debug_write || dsi.debug_read) DSSDBG("dsi_vc_send_bta %d\n", channel); - WARN_ON(!mutex_is_locked(&dsi.bus_lock)); + WARN_ON(!dsi_bus_is_locked()); if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */ DSSERR("rx fifo not empty when sending BTA, dumping data:\n"); @@ -2010,10 +1932,9 @@ static inline void dsi_vc_write_long_header(int channel, u8 data_type, u32 val; u8 data_id; - WARN_ON(!mutex_is_locked(&dsi.bus_lock)); + WARN_ON(!dsi_bus_is_locked()); - /*data_id = data_type | channel << 6; */ - data_id = data_type | dsi.vc[channel].dest_per << 6; + data_id = data_type | channel << 6; val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) | FLD_VAL(ecc, 31, 24); @@ -2056,13 +1977,10 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len, dsi_vc_write_long_header(channel, data_type, len, ecc); - /*dsi_vc_print_status(0); */ - p = data; for (i = 0; i < len >> 2; i++) { if (dsi.debug_write) DSSDBG("\tsending full packet %d\n", i); - /*dsi_vc_print_status(0); */ b1 = *p++; b2 = *p++; @@ -2105,7 +2023,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc) u32 r; u8 data_id; - WARN_ON(!mutex_is_locked(&dsi.bus_lock)); + WARN_ON(!dsi_bus_is_locked()); if (dsi.debug_write) DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n", @@ -2119,7 +2037,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc) return -EINVAL; } - data_id = data_type | dsi.vc[channel].dest_per << 6; + data_id = data_type | channel << 6; r = (data_id << 0) | (data << 8) | (ecc << 24); @@ -2163,14 +2081,35 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len) r = dsi_vc_dcs_write_nosync(channel, data, len); if (r) - return r; + goto err; r = dsi_vc_send_bta_sync(channel); + if (r) + goto err; + return 0; +err: + DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n", + channel, data[0], len); return r; } EXPORT_SYMBOL(dsi_vc_dcs_write); +int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd) +{ + return dsi_vc_dcs_write(channel, &dcs_cmd, 1); +} +EXPORT_SYMBOL(dsi_vc_dcs_write_0); + +int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param) +{ + u8 buf[2]; + buf[0] = dcs_cmd; + buf[1] = param; + return dsi_vc_dcs_write(channel, buf, 2); +} +EXPORT_SYMBOL(dsi_vc_dcs_write_1); + int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) { u32 val; @@ -2182,16 +2121,17 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0); if (r) - return r; + goto err; r = dsi_vc_send_bta_sync(channel); if (r) - return r; + goto err; /* RX_FIFO_NOT_EMPTY */ if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) { DSSERR("RX fifo empty when trying to read.\n"); - return -EIO; + r = -EIO; + goto err; } val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); @@ -2201,15 +2141,18 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) if (dt == DSI_DT_RX_ACK_WITH_ERR) { u16 err = FLD_GET(val, 23, 8); dsi_show_rx_ack_with_err(err); - return -EIO; + r = -EIO; + goto err; } else if (dt == DSI_DT_RX_SHORT_READ_1) { u8 data = FLD_GET(val, 15, 8); if (dsi.debug_read) DSSDBG("\tDCS short response, 1 byte: %02x\n", data); - if (buflen < 1) - return -EIO; + if (buflen < 1) { + r = -EIO; + goto err; + } buf[0] = data; @@ -2219,8 +2162,10 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) if (dsi.debug_read) DSSDBG("\tDCS short response, 2 byte: %04x\n", data); - if (buflen < 2) - return -EIO; + if (buflen < 2) { + r = -EIO; + goto err; + } buf[0] = data & 0xff; buf[1] = (data >> 8) & 0xff; @@ -2232,8 +2177,10 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) if (dsi.debug_read) DSSDBG("\tDCS long response, len %d\n", len); - if (len > buflen) - return -EIO; + if (len > buflen) { + r = -EIO; + goto err; + } /* two byte checksum ends the packet, not included in len */ for (w = 0; w < len + 2;) { @@ -2255,14 +2202,52 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) } return len; - } else { DSSERR("\tunknown datatype 0x%02x\n", dt); - return -EIO; + r = -EIO; + goto err; } + + BUG(); +err: + DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", + channel, dcs_cmd); + return r; + } EXPORT_SYMBOL(dsi_vc_dcs_read); +int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data) +{ + int r; + + r = dsi_vc_dcs_read(channel, dcs_cmd, data, 1); + + if (r < 0) + return r; + + if (r != 1) + return -EIO; + + return 0; +} +EXPORT_SYMBOL(dsi_vc_dcs_read_1); + +int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) +{ + int r; + + r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2); + + if (r < 0) + return r; + + if (r != 2) + return -EIO; + + return 0; +} +EXPORT_SYMBOL(dsi_vc_dcs_read_2); int dsi_vc_set_max_rx_packet_size(int channel, u16 len) { @@ -2491,15 +2476,15 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) u32 r; int buswidth = 0; - dsi_config_tx_fifo(DSI_FIFO_SIZE_128, - DSI_FIFO_SIZE_0, - DSI_FIFO_SIZE_0, - DSI_FIFO_SIZE_0); + dsi_config_tx_fifo(DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32); - dsi_config_rx_fifo(DSI_FIFO_SIZE_128, - DSI_FIFO_SIZE_0, - DSI_FIFO_SIZE_0, - DSI_FIFO_SIZE_0); + dsi_config_rx_fifo(DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32); /* XXX what values for the timeouts? */ dsi_set_stop_state_counter(1000); @@ -2537,12 +2522,9 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_write_reg(DSI_CTRL, r); dsi_vc_initial_config(0); - - /* set all vc targets to peripheral 0 */ - dsi.vc[0].dest_per = 0; - dsi.vc[1].dest_per = 0; - dsi.vc[2].dest_per = 0; - dsi.vc[3].dest_per = 0; + dsi_vc_initial_config(1); + dsi_vc_initial_config(2); + dsi_vc_initial_config(3); return 0; } @@ -2777,18 +2759,16 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, unsigned packet_payload; unsigned packet_len; u32 l; - bool use_te_trigger; - const unsigned channel = 0; + const unsigned channel = dsi.update_channel; /* line buffer is 1024 x 24bits */ /* XXX: for some reason using full buffer size causes considerable TX * slowdown with update sizes that fill the whole buffer */ const unsigned line_buf_size = 1023 * 3; - use_te_trigger = dsi.te_enabled && !dsi.use_ext_te; + DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", + x, y, w, h); - if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO) - DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", - x, y, w, h); + dsi_vc_config_vp(channel); bytespp = dssdev->ctrl.pixel_size / 8; bytespl = w * bytespp; @@ -2808,15 +2788,12 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, if (bytespf % packet_payload) total_len += (bytespf % packet_payload) + 1; - if (0) - dsi_vc_print_status(1); - l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */ dsi_write_reg(DSI_VC_TE(channel), l); dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0); - if (use_te_trigger) + if (dsi.te_enabled) l = FLD_MOD(l, 1, 30, 30); /* TE_EN */ else l = FLD_MOD(l, 1, 31, 31); /* TE_START */ @@ -2830,9 +2807,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, */ dispc_disable_sidle(); + dsi_perf_mark_start(); + + schedule_delayed_work(&dsi.framedone_timeout_work, + msecs_to_jiffies(250)); + dss_start_update(dssdev); - if (use_te_trigger) { + if (dsi.te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait * for TE is longer than the timer allows */ REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */ @@ -2852,110 +2834,64 @@ static void dsi_te_timeout(unsigned long arg) } #endif -static void dsi_framedone_irq_callback(void *data, u32 mask) +static void dsi_framedone_timeout_work_callback(struct work_struct *work) { - /* Note: We get FRAMEDONE when DISPC has finished sending pixels and - * turns itself off. However, DSI still has the pixels in its buffers, - * and is sending the data. - */ + int r; + const int channel = dsi.update_channel; + + DSSERR("Framedone not received for 250ms!\n"); /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); - dsi.framedone_received = true; - wake_up(&dsi.waitqueue); -} - -static void dsi_set_update_region(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h) -{ - spin_lock(&dsi.update_lock); - if (dsi.update_region.dirty) { - dsi.update_region.x = min(x, dsi.update_region.x); - dsi.update_region.y = min(y, dsi.update_region.y); - dsi.update_region.w = max(w, dsi.update_region.w); - dsi.update_region.h = max(h, dsi.update_region.h); - } else { - dsi.update_region.x = x; - dsi.update_region.y = y; - dsi.update_region.w = w; - dsi.update_region.h = h; + if (dsi.te_enabled) { + /* enable LP_RX_TO again after the TE */ + REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ } - dsi.update_region.device = dssdev; - dsi.update_region.dirty = true; - - spin_unlock(&dsi.update_lock); - -} - -static int dsi_set_update_mode(struct omap_dss_device *dssdev, - enum omap_dss_update_mode mode) -{ - int r = 0; - int i; - - WARN_ON(!mutex_is_locked(&dsi.bus_lock)); - - if (dsi.update_mode != mode) { - dsi.update_mode = mode; - - /* Mark the overlays dirty, and do apply(), so that we get the - * overlays configured properly after update mode change. */ - for (i = 0; i < omap_dss_get_num_overlays(); ++i) { - struct omap_overlay *ovl; - ovl = omap_dss_get_overlay(i); - if (ovl->manager == dssdev->manager) - ovl->info_dirty = true; - } - - r = dssdev->manager->apply(dssdev->manager); - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE && - mode == OMAP_DSS_UPDATE_AUTO) { - u16 w, h; - - DSSDBG("starting auto update\n"); - - dssdev->get_resolution(dssdev, &w, &h); - - dsi_set_update_region(dssdev, 0, 0, w, h); - - dsi_perf_mark_start_auto(); + /* Send BTA after the frame. We need this for the TE to work, as TE + * trigger is only sent for BTAs without preceding packet. Thus we need + * to BTA after the pixel packets so that next BTA will cause TE + * trigger. + * + * This is not needed when TE is not in use, but we do it anyway to + * make sure that the transfer has been completed. It would be more + * optimal, but more complex, to wait only just before starting next + * transfer. */ + r = dsi_vc_send_bta_sync(channel); + if (r) + DSSERR("BTA after framedone failed\n"); - wake_up(&dsi.waitqueue); - } + /* RX_FIFO_NOT_EMPTY */ + if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { + DSSERR("Received error during frame transfer:\n"); + dsi_vc_flush_receive_data(channel); } - return r; + dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data); } -static int dsi_set_te(struct omap_dss_device *dssdev, bool enable) +static void dsi_framedone_irq_callback(void *data, u32 mask) { - int r = 0; + /* Note: We get FRAMEDONE when DISPC has finished sending pixels and + * turns itself off. However, DSI still has the pixels in its buffers, + * and is sending the data. + */ - if (dssdev->driver->enable_te) { - r = dssdev->driver->enable_te(dssdev, enable); - /* XXX for some reason, DSI TE breaks if we don't wait here. - * Panel bug? Needs more studying */ - msleep(100); - } + /* SIDLEMODE back to smart-idle */ + dispc_enable_sidle(); - return r; + schedule_work(&dsi.framedone_work); } static void dsi_handle_framedone(void) { int r; - const int channel = 0; - bool use_te_trigger; - - use_te_trigger = dsi.te_enabled && !dsi.use_ext_te; + const int channel = dsi.update_channel; - if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO) - DSSDBG("FRAMEDONE\n"); + DSSDBG("FRAMEDONE\n"); - if (use_te_trigger) { + if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ } @@ -2976,7 +2912,7 @@ static void dsi_handle_framedone(void) /* RX_FIFO_NOT_EMPTY */ if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { DSSERR("Received error during frame transfer:\n"); - dsi_vc_flush_receive_data(0); + dsi_vc_flush_receive_data(channel); } #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC @@ -2984,118 +2920,79 @@ static void dsi_handle_framedone(void) #endif } -static int dsi_update_thread(void *data) +static void dsi_framedone_work_callback(struct work_struct *work) { - unsigned long timeout; - struct omap_dss_device *device; - u16 x, y, w, h; - - while (1) { - bool sched; - - wait_event_interruptible(dsi.waitqueue, - dsi.update_mode == OMAP_DSS_UPDATE_AUTO || - (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL && - dsi.update_region.dirty == true) || - kthread_should_stop()); - - if (kthread_should_stop()) - break; - - dsi_bus_lock(); - - if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED || - kthread_should_stop()) { - dsi_bus_unlock(); - break; - } - - dsi_perf_mark_setup(); - - if (dsi.update_region.dirty) { - spin_lock(&dsi.update_lock); - dsi.active_update_region = dsi.update_region; - dsi.update_region.dirty = false; - spin_unlock(&dsi.update_lock); - } + DSSDBGF(); - device = dsi.active_update_region.device; - x = dsi.active_update_region.x; - y = dsi.active_update_region.y; - w = dsi.active_update_region.w; - h = dsi.active_update_region.h; + cancel_delayed_work_sync(&dsi.framedone_timeout_work); - if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { + dsi_handle_framedone(); - if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL) - dss_setup_partial_planes(device, - &x, &y, &w, &h); + dsi_perf_show("DISPC"); - dispc_set_lcd_size(w, h); - } + dsi.framedone_callback(0, dsi.framedone_data); +} - if (dsi.active_update_region.dirty) { - dsi.active_update_region.dirty = false; - /* XXX TODO we don't need to send the coords, if they - * are the same that are already programmed to the - * panel. That should speed up manual update a bit */ - device->driver->setup_update(device, x, y, w, h); - } +int omap_dsi_prepare_update(struct omap_dss_device *dssdev, + u16 *x, u16 *y, u16 *w, u16 *h) +{ + u16 dw, dh; - dsi_perf_mark_start(); + dssdev->driver->get_resolution(dssdev, &dw, &dh); - if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dsi_vc_config_vp(0); + if (*x > dw || *y > dh) + return -EINVAL; - if (dsi.te_enabled && dsi.use_ext_te) - device->driver->wait_for_te(device); + if (*x + *w > dw) + return -EINVAL; - dsi.framedone_received = false; + if (*y + *h > dh) + return -EINVAL; - dsi_update_screen_dispc(device, x, y, w, h); + if (*w == 1) + return -EINVAL; - /* wait for framedone */ - timeout = msecs_to_jiffies(1000); - wait_event_timeout(dsi.waitqueue, - dsi.framedone_received == true, - timeout); + if (*w == 0 || *h == 0) + return -EINVAL; - if (!dsi.framedone_received) { - DSSERR("framedone timeout\n"); - DSSERR("failed update %d,%d %dx%d\n", - x, y, w, h); + dsi_perf_mark_setup(); - dispc_enable_sidle(); - dispc_enable_lcd_out(0); + if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { + dss_setup_partial_planes(dssdev, x, y, w, h); + dispc_set_lcd_size(*w, *h); + } - dsi_reset_tx_fifo(0); - } else { - dsi_handle_framedone(); - dsi_perf_show("DISPC"); - } - } else { - dsi_update_screen_l4(device, x, y, w, h); - dsi_perf_show("L4"); - } + return 0; +} +EXPORT_SYMBOL(omap_dsi_prepare_update); - sched = atomic_read(&dsi.bus_lock.count) < 0; +int omap_dsi_update(struct omap_dss_device *dssdev, + int channel, + u16 x, u16 y, u16 w, u16 h, + void (*callback)(int, void *), void *data) +{ + dsi.update_channel = channel; - complete_all(&dsi.update_completion); + if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { + dsi.framedone_callback = callback; + dsi.framedone_data = data; - dsi_bus_unlock(); + dsi.update_region.x = x; + dsi.update_region.y = y; + dsi.update_region.w = w; + dsi.update_region.h = h; + dsi.update_region.device = dssdev; - /* XXX We need to give others chance to get the bus lock. Is - * there a better way for this? */ - if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO && sched) - schedule_timeout_interruptible(1); + dsi_update_screen_dispc(dssdev, x, y, w, h); + } else { + dsi_update_screen_l4(dssdev, x, y, w, h); + dsi_perf_show("L4"); + callback(0, data); } - DSSDBG("update thread exiting\n"); - return 0; } - - +EXPORT_SYMBOL(omap_dsi_update); /* Display funcs */ @@ -3203,7 +3100,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) if (r) goto err1; - dss_select_clk_source(true, true); + dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); + dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK); DSSDBG("PLL OK\n"); @@ -3229,25 +3127,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) /* enable interface */ dsi_vc_enable(0, 1); + dsi_vc_enable(1, 1); + dsi_vc_enable(2, 1); + dsi_vc_enable(3, 1); dsi_if_enable(1); dsi_force_tx_stop_mode_io(); - if (dssdev->driver->enable) { - r = dssdev->driver->enable(dssdev); - if (r) - goto err4; - } - - /* enable high-speed after initial config */ - dsi_vc_enable_hs(0, 1); - return 0; -err4: - dsi_if_enable(0); err3: dsi_complexio_uninit(); err2: - dss_select_clk_source(false, false); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); + dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); err1: dsi_pll_uninit(); err0: @@ -3256,10 +3147,8 @@ err0: static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) { - if (dssdev->driver->disable) - dssdev->driver->disable(dssdev); - - dss_select_clk_source(false, false); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); + dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dsi_complexio_uninit(); dsi_pll_uninit(); } @@ -3280,14 +3169,15 @@ static int dsi_core_init(void) return 0; } -static int dsi_display_enable(struct omap_dss_device *dssdev) +int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { int r = 0; DSSDBG("dsi_display_enable\n"); + WARN_ON(!dsi_bus_is_locked()); + mutex_lock(&dsi.lock); - dsi_bus_lock(); r = omap_dss_start_device(dssdev); if (r) { @@ -3295,100 +3185,47 @@ static int dsi_display_enable(struct omap_dss_device *dssdev) goto err0; } - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { - DSSERR("dssdev already enabled\n"); - r = -EINVAL; - goto err1; - } - enable_clocks(1); dsi_enable_pll_clock(1); r = _dsi_reset(); if (r) - goto err2; + goto err1; dsi_core_init(); r = dsi_display_init_dispc(dssdev); if (r) - goto err2; + goto err1; r = dsi_display_init_dsi(dssdev); if (r) - goto err3; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - dsi.use_ext_te = dssdev->phy.dsi.ext_te; - r = dsi_set_te(dssdev, dsi.te_enabled); - if (r) - goto err4; - - dsi_set_update_mode(dssdev, dsi.user_update_mode); + goto err2; - dsi_bus_unlock(); mutex_unlock(&dsi.lock); return 0; -err4: - - dsi_display_uninit_dsi(dssdev); -err3: - dsi_display_uninit_dispc(dssdev); err2: + dsi_display_uninit_dispc(dssdev); +err1: enable_clocks(0); dsi_enable_pll_clock(0); -err1: omap_dss_stop_device(dssdev); err0: - dsi_bus_unlock(); mutex_unlock(&dsi.lock); DSSDBG("dsi_display_enable FAILED\n"); return r; } +EXPORT_SYMBOL(omapdss_dsi_display_enable); -static void dsi_display_disable(struct omap_dss_device *dssdev) +void omapdss_dsi_display_disable(struct omap_dss_device *dssdev) { DSSDBG("dsi_display_disable\n"); - mutex_lock(&dsi.lock); - dsi_bus_lock(); - - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED || - dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) - goto end; - - dsi.update_mode = OMAP_DSS_UPDATE_DISABLED; - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - - dsi_display_uninit_dispc(dssdev); - - dsi_display_uninit_dsi(dssdev); - - enable_clocks(0); - dsi_enable_pll_clock(0); - - omap_dss_stop_device(dssdev); -end: - dsi_bus_unlock(); - mutex_unlock(&dsi.lock); -} - -static int dsi_display_suspend(struct omap_dss_device *dssdev) -{ - DSSDBG("dsi_display_suspend\n"); + WARN_ON(!dsi_bus_is_locked()); mutex_lock(&dsi.lock); - dsi_bus_lock(); - - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED || - dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) - goto end; - - dsi.update_mode = OMAP_DSS_UPDATE_DISABLED; - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; dsi_display_uninit_dispc(dssdev); @@ -3396,312 +3233,19 @@ static int dsi_display_suspend(struct omap_dss_device *dssdev) enable_clocks(0); dsi_enable_pll_clock(0); -end: - dsi_bus_unlock(); - mutex_unlock(&dsi.lock); - - return 0; -} - -static int dsi_display_resume(struct omap_dss_device *dssdev) -{ - int r; - - DSSDBG("dsi_display_resume\n"); - - mutex_lock(&dsi.lock); - dsi_bus_lock(); - - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { - DSSERR("dssdev not suspended\n"); - r = -EINVAL; - goto err0; - } - - enable_clocks(1); - dsi_enable_pll_clock(1); - - r = _dsi_reset(); - if (r) - goto err1; - - dsi_core_init(); - - r = dsi_display_init_dispc(dssdev); - if (r) - goto err1; - - r = dsi_display_init_dsi(dssdev); - if (r) - goto err2; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - r = dsi_set_te(dssdev, dsi.te_enabled); - if (r) - goto err2; - - dsi_set_update_mode(dssdev, dsi.user_update_mode); - - dsi_bus_unlock(); - mutex_unlock(&dsi.lock); - - return 0; - -err2: - dsi_display_uninit_dispc(dssdev); -err1: - enable_clocks(0); - dsi_enable_pll_clock(0); -err0: - dsi_bus_unlock(); - mutex_unlock(&dsi.lock); - DSSDBG("dsi_display_resume FAILED\n"); - return r; -} - -static int dsi_display_update(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h) -{ - int r = 0; - u16 dw, dh; - - DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h); - mutex_lock(&dsi.lock); - - if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL) - goto end; - - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - goto end; - - dssdev->get_resolution(dssdev, &dw, &dh); - - if (x > dw || y > dh) - goto end; - - if (x + w > dw) - w = dw - x; - - if (y + h > dh) - h = dh - y; - - if (w == 0 || h == 0) - goto end; - - if (w == 1) { - r = -EINVAL; - goto end; - } - - dsi_set_update_region(dssdev, x, y, w, h); - - wake_up(&dsi.waitqueue); - -end: - mutex_unlock(&dsi.lock); - - return r; -} - -static int dsi_display_sync(struct omap_dss_device *dssdev) -{ - bool wait; - - DSSDBG("dsi_display_sync()\n"); - - mutex_lock(&dsi.lock); - dsi_bus_lock(); - - if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL && - dsi.update_region.dirty) { - INIT_COMPLETION(dsi.update_completion); - wait = true; - } else { - wait = false; - } - - dsi_bus_unlock(); - mutex_unlock(&dsi.lock); - - if (wait) - wait_for_completion_interruptible(&dsi.update_completion); - - DSSDBG("dsi_display_sync() done\n"); - return 0; -} - -static int dsi_display_set_update_mode(struct omap_dss_device *dssdev, - enum omap_dss_update_mode mode) -{ - int r = 0; - - DSSDBGF("%d", mode); - - mutex_lock(&dsi.lock); - dsi_bus_lock(); - - dsi.user_update_mode = mode; - r = dsi_set_update_mode(dssdev, mode); + omap_dss_stop_device(dssdev); - dsi_bus_unlock(); mutex_unlock(&dsi.lock); - - return r; } +EXPORT_SYMBOL(omapdss_dsi_display_disable); -static enum omap_dss_update_mode dsi_display_get_update_mode( - struct omap_dss_device *dssdev) +int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) { - return dsi.update_mode; -} - - -static int dsi_display_enable_te(struct omap_dss_device *dssdev, bool enable) -{ - int r = 0; - - DSSDBGF("%d", enable); - - if (!dssdev->driver->enable_te) - return -ENOENT; - - dsi_bus_lock(); - dsi.te_enabled = enable; - - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - goto end; - - r = dsi_set_te(dssdev, enable); -end: - dsi_bus_unlock(); - - return r; -} - -static int dsi_display_get_te(struct omap_dss_device *dssdev) -{ - return dsi.te_enabled; -} - -static int dsi_display_set_rotate(struct omap_dss_device *dssdev, u8 rotate) -{ - - DSSDBGF("%d", rotate); - - if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) - return -EINVAL; - - dsi_bus_lock(); - dssdev->driver->set_rotate(dssdev, rotate); - if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) { - u16 w, h; - /* the display dimensions may have changed, so set a new - * update region */ - dssdev->get_resolution(dssdev, &w, &h); - dsi_set_update_region(dssdev, 0, 0, w, h); - } - dsi_bus_unlock(); - return 0; } - -static u8 dsi_display_get_rotate(struct omap_dss_device *dssdev) -{ - if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) - return 0; - - return dssdev->driver->get_rotate(dssdev); -} - -static int dsi_display_set_mirror(struct omap_dss_device *dssdev, bool mirror) -{ - DSSDBGF("%d", mirror); - - if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) - return -EINVAL; - - dsi_bus_lock(); - dssdev->driver->set_mirror(dssdev, mirror); - dsi_bus_unlock(); - - return 0; -} - -static bool dsi_display_get_mirror(struct omap_dss_device *dssdev) -{ - if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) - return 0; - - return dssdev->driver->get_mirror(dssdev); -} - -static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num) -{ - int r; - - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return -EIO; - - DSSDBGF("%d", test_num); - - dsi_bus_lock(); - - /* run test first in low speed mode */ - dsi_vc_enable_hs(0, 0); - - if (dssdev->driver->run_test) { - r = dssdev->driver->run_test(dssdev, test_num); - if (r) - goto end; - } - - /* then in high speed */ - dsi_vc_enable_hs(0, 1); - - if (dssdev->driver->run_test) { - r = dssdev->driver->run_test(dssdev, test_num); - if (r) - goto end; - } - -end: - dsi_vc_enable_hs(0, 1); - - dsi_bus_unlock(); - - return r; -} - -static int dsi_display_memory_read(struct omap_dss_device *dssdev, - void *buf, size_t size, - u16 x, u16 y, u16 w, u16 h) -{ - int r; - - DSSDBGF(""); - - if (!dssdev->driver->memory_read) - return -EINVAL; - - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return -EIO; - - dsi_bus_lock(); - - r = dssdev->driver->memory_read(dssdev, buf, size, - x, y, w, h); - - /* Memory read usually changes the update area. This will - * force the next update to re-set the update area */ - dsi.active_update_region.dirty = true; - - dsi_bus_unlock(); - - return r; -} +EXPORT_SYMBOL(omapdss_dsi_enable_te); void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, u32 fifo_size, enum omap_burst_size *burst_size, @@ -3720,26 +3264,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) { DSSDBG("DSI init\n"); - dssdev->enable = dsi_display_enable; - dssdev->disable = dsi_display_disable; - dssdev->suspend = dsi_display_suspend; - dssdev->resume = dsi_display_resume; - dssdev->update = dsi_display_update; - dssdev->sync = dsi_display_sync; - dssdev->set_update_mode = dsi_display_set_update_mode; - dssdev->get_update_mode = dsi_display_get_update_mode; - dssdev->enable_te = dsi_display_enable_te; - dssdev->get_te = dsi_display_get_te; - - dssdev->get_rotate = dsi_display_get_rotate; - dssdev->set_rotate = dsi_display_set_rotate; - - dssdev->get_mirror = dsi_display_get_mirror; - dssdev->set_mirror = dsi_display_set_mirror; - - dssdev->run_test = dsi_display_run_test; - dssdev->memory_read = dsi_display_memory_read; - /* XXX these should be figured out dynamically */ dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; @@ -3754,9 +3278,6 @@ int dsi_init(struct platform_device *pdev) { u32 rev; int r; - struct sched_param param = { - .sched_priority = MAX_USER_RT_PRIO-1 - }; spin_lock_init(&dsi.errors_lock); dsi.errors = 0; @@ -3767,31 +3288,19 @@ int dsi_init(struct platform_device *pdev) #endif init_completion(&dsi.bta_completion); - init_completion(&dsi.update_completion); - - dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi"); - if (IS_ERR(dsi.thread)) { - DSSERR("cannot create kthread\n"); - r = PTR_ERR(dsi.thread); - goto err0; - } - sched_setscheduler(dsi.thread, SCHED_FIFO, ¶m); - - init_waitqueue_head(&dsi.waitqueue); - spin_lock_init(&dsi.update_lock); mutex_init(&dsi.lock); - mutex_init(&dsi.bus_lock); + sema_init(&dsi.bus_lock, 1); + + INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); + INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, + dsi_framedone_timeout_work_callback); #ifdef DSI_CATCH_MISSING_TE init_timer(&dsi.te_timer); dsi.te_timer.function = dsi_te_timeout; dsi.te_timer.data = 0; #endif - - dsi.update_mode = OMAP_DSS_UPDATE_DISABLED; - dsi.user_update_mode = OMAP_DSS_UPDATE_DISABLED; - dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS); if (!dsi.base) { DSSERR("can't ioremap DSI\n"); @@ -3799,7 +3308,7 @@ int dsi_init(struct platform_device *pdev) goto err1; } - dsi.vdds_dsi_reg = regulator_get(&pdev->dev, "vdds_dsi"); + dsi.vdds_dsi_reg = dss_get_vdds_dsi(); if (IS_ERR(dsi.vdds_dsi_reg)) { iounmap(dsi.base); DSSERR("can't get VDDS_DSI regulator\n"); @@ -3815,23 +3324,15 @@ int dsi_init(struct platform_device *pdev) enable_clocks(0); - wake_up_process(dsi.thread); - return 0; err2: iounmap(dsi.base); err1: - kthread_stop(dsi.thread); -err0: return r; } void dsi_exit(void) { - kthread_stop(dsi.thread); - - regulator_put(dsi.vdds_dsi_reg); - iounmap(dsi.base); DSSDBG("omap_dsi_exit\n"); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 0a26b7d84d4..8254a4232a5 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -68,6 +68,9 @@ static struct { struct dss_clock_info cache_dss_cinfo; struct dispc_clock_info cache_dispc_cinfo; + enum dss_clk_source dsi_clk_source; + enum dss_clk_source dispc_clk_source; + u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; @@ -247,23 +250,42 @@ void dss_dump_regs(struct seq_file *s) #undef DUMPREG } -void dss_select_clk_source(bool dsi, bool dispc) +void dss_select_dispc_clk_source(enum dss_clk_source clk_src) +{ + int b; + + BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK && + clk_src != DSS_SRC_DSS1_ALWON_FCLK); + + b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + + REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ + + dss.dispc_clk_source = clk_src; +} + +void dss_select_dsi_clk_source(enum dss_clk_source clk_src) { - u32 r; - r = dss_read_reg(DSS_CONTROL); - r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */ - r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */ - dss_write_reg(DSS_CONTROL, r); + int b; + + BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK && + clk_src != DSS_SRC_DSS1_ALWON_FCLK); + + b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + + REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ + + dss.dsi_clk_source = clk_src; } -int dss_get_dsi_clk_source(void) +enum dss_clk_source dss_get_dispc_clk_source(void) { - return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1); + return dss.dispc_clk_source; } -int dss_get_dispc_clk_source(void) +enum dss_clk_source dss_get_dsi_clk_source(void) { - return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0); + return dss.dsi_clk_source; } /* calculate clock rates using dividers in cinfo */ diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 2bcb1245d6c..24326a5fd29 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -119,6 +119,12 @@ enum dss_clock { DSS_CLK_96M = 1 << 4, }; +enum dss_clk_source { + DSS_SRC_DSI1_PLL_FCLK, + DSS_SRC_DSI2_PLL_FCLK, + DSS_SRC_DSS1_ALWON_FCLK, +}; + struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; @@ -169,6 +175,9 @@ unsigned long dss_clk_get_rate(enum dss_clock clk); int dss_need_ctx_restore(void); void dss_dump_clocks(struct seq_file *s); struct bus_type *dss_get_bus(void); +struct regulator *dss_get_vdds_dsi(void); +struct regulator *dss_get_vdds_sdi(void); +struct regulator *dss_get_vdda_dac(void); /* display */ int dss_suspend_all_devices(void); @@ -216,9 +225,11 @@ void dss_sdi_init(u8 datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); -void dss_select_clk_source(bool dsi, bool dispc); -int dss_get_dsi_clk_source(void); -int dss_get_dispc_clk_source(void); +void dss_select_dispc_clk_source(enum dss_clk_source clk_src); +void dss_select_dsi_clk_source(enum dss_clk_source clk_src); +enum dss_clk_source dss_get_dispc_clk_source(void); +enum dss_clk_source dss_get_dsi_clk_source(void); + void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); @@ -261,7 +272,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, u32 *fifo_low, u32 *fifo_high); /* DPI */ -int dpi_init(void); +int dpi_init(struct platform_device *pdev); void dpi_exit(void); int dpi_init_display(struct omap_dss_device *dssdev); @@ -313,8 +324,8 @@ int dispc_setup_plane(enum omap_plane plane, bool dispc_go_busy(enum omap_channel channel); void dispc_go(enum omap_channel channel); -void dispc_enable_lcd_out(bool enable); -void dispc_enable_digit_out(bool enable); +void dispc_enable_channel(enum omap_channel channel, bool enable); +bool dispc_is_channel_enabled(enum omap_channel channel); int dispc_enable_plane(enum omap_plane plane, bool enable); void dispc_enable_replication(enum omap_plane plane, bool enable); diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 27d9c465c85..913142d4cab 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -501,6 +501,19 @@ static int omap_dss_unset_device(struct omap_overlay_manager *mgr) return 0; } +static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) +{ + unsigned long timeout = msecs_to_jiffies(500); + u32 irq; + + if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) + irq = DISPC_IRQ_EVSYNC_ODD; + else + irq = DISPC_IRQ_VSYNC; + + return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); +} + static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); @@ -509,17 +522,18 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) u32 irq; int r; int i; + struct omap_dss_device *dssdev = mgr->device; - if (!mgr->device) + if (!dssdev) return 0; - if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; channel = OMAP_DSS_CHANNEL_DIGIT; } else { - if (mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { + if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { enum omap_dss_update_mode mode; - mode = mgr->device->get_update_mode(mgr->device); + mode = dssdev->driver->get_update_mode(dssdev); if (mode != OMAP_DSS_UPDATE_AUTO) return 0; @@ -592,7 +606,7 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { enum omap_dss_update_mode mode; - mode = dssdev->get_update_mode(dssdev); + mode = dssdev->driver->get_update_mode(dssdev); if (mode != OMAP_DSS_UPDATE_AUTO) return 0; @@ -1064,7 +1078,7 @@ void dss_start_update(struct omap_dss_device *dssdev) mc->shadow_dirty = false; } - dispc_enable_lcd_out(1); + dssdev->manager->enable(dssdev->manager); } static void dss_apply_irq_handler(void *data, u32 mask) @@ -1196,7 +1210,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) oc->manual_update = dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE && - dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO; + dssdev->driver->get_update_mode(dssdev) != + OMAP_DSS_UPDATE_AUTO; ++num_planes_enabled; } @@ -1237,7 +1252,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) mc->manual_update = dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE && - dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO; + dssdev->driver->get_update_mode(dssdev) != + OMAP_DSS_UPDATE_AUTO; } /* XXX TODO: Try to get fifomerge working. The problem is that it @@ -1351,6 +1367,18 @@ static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, *info = mgr->info; } +static int dss_mgr_enable(struct omap_overlay_manager *mgr) +{ + dispc_enable_channel(mgr->id, 1); + return 0; +} + +static int dss_mgr_disable(struct omap_overlay_manager *mgr) +{ + dispc_enable_channel(mgr->id, 0); + return 0; +} + static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager) { ++num_managers; @@ -1394,6 +1422,10 @@ int dss_init_overlay_managers(struct platform_device *pdev) mgr->set_manager_info = &omap_dss_mgr_set_info; mgr->get_manager_info = &omap_dss_mgr_get_info; mgr->wait_for_go = &dss_mgr_wait_for_go; + mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; + + mgr->enable = &dss_mgr_enable; + mgr->disable = &dss_mgr_disable; mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC; diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index b7f9a733984..0c5bea263ac 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -350,7 +350,7 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) return -EINVAL; } - dssdev->get_resolution(dssdev, &dw, &dh); + dssdev->driver->get_resolution(dssdev, &dw, &dh); DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n", ovl->id, diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index b936495c065..cc23f53cc62 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -36,8 +36,6 @@ #include <plat/display.h> #include "dss.h" -/*#define MEASURE_PERF*/ - #define RFBI_BASE 0x48050800 struct rfbi_reg { u16 idx; }; @@ -66,8 +64,6 @@ struct rfbi_reg { u16 idx; }; #define RFBI_VSYNC_WIDTH RFBI_REG(0x0090) #define RFBI_HSYNC_WIDTH RFBI_REG(0x0094) -#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param)) - #define REG_FLD_MOD(idx, val, start, end) \ rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end)) @@ -102,7 +98,6 @@ enum update_cmd { static int rfbi_convert_timings(struct rfbi_timings *t); static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div); -static void process_cmd_fifo(void); static struct { void __iomem *base; @@ -125,11 +120,6 @@ static struct { struct completion cmd_done; atomic_t cmd_fifo_full; atomic_t cmd_pending; -#ifdef MEASURE_PERF - unsigned perf_bytes; - ktime_t perf_setup_time; - ktime_t perf_start_time; -#endif } rfbi; struct update_region { @@ -139,16 +129,6 @@ struct update_region { u16 h; }; -struct update_param { - u8 rfbi_module; - u8 cmd; - - union { - struct update_region r; - struct completion *sync; - } par; -}; - static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) { __raw_writel(val, rfbi.base + idx.idx); @@ -321,55 +301,6 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, } EXPORT_SYMBOL(omap_rfbi_write_pixels); -#ifdef MEASURE_PERF -static void perf_mark_setup(void) -{ - rfbi.perf_setup_time = ktime_get(); -} - -static void perf_mark_start(void) -{ - rfbi.perf_start_time = ktime_get(); -} - -static void perf_show(const char *name) -{ - ktime_t t, setup_time, trans_time; - u32 total_bytes; - u32 setup_us, trans_us, total_us; - - t = ktime_get(); - - setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time); - setup_us = (u32)ktime_to_us(setup_time); - if (setup_us == 0) - setup_us = 1; - - trans_time = ktime_sub(t, rfbi.perf_start_time); - trans_us = (u32)ktime_to_us(trans_time); - if (trans_us == 0) - trans_us = 1; - - total_us = setup_us + trans_us; - - total_bytes = rfbi.perf_bytes; - - DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, " - "%u kbytes/sec\n", - name, - setup_us, - trans_us, - total_us, - 1000*1000 / total_us, - total_bytes, - total_bytes * 1000 / total_us); -} -#else -#define perf_mark_setup() -#define perf_mark_start() -#define perf_show(x) -#endif - void rfbi_transfer_area(u16 width, u16 height, void (callback)(void *data), void *data) { @@ -382,7 +313,7 @@ void rfbi_transfer_area(u16 width, u16 height, dispc_set_lcd_size(width, height); - dispc_enable_lcd_out(1); + dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true); rfbi.framedone_callback = callback; rfbi.framedone_callback_data = data; @@ -396,8 +327,6 @@ void rfbi_transfer_area(u16 width, u16 height, if (!rfbi.te_enabled) l = FLD_MOD(l, 1, 4, 4); /* ITE */ - perf_mark_start(); - rfbi_write_reg(RFBI_CONTROL, l); } @@ -407,8 +336,6 @@ static void framedone_callback(void *data, u32 mask) DSSDBG("FRAMEDONE\n"); - perf_show("DISPC"); - REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0); rfbi_enable_clocks(0); @@ -416,11 +343,10 @@ static void framedone_callback(void *data, u32 mask) callback = rfbi.framedone_callback; rfbi.framedone_callback = NULL; - /*callback(rfbi.framedone_callback_data);*/ + if (callback != NULL) + callback(rfbi.framedone_callback_data); atomic_set(&rfbi.cmd_pending, 0); - - process_cmd_fifo(); } #if 1 /* VERBOSE */ @@ -937,52 +863,43 @@ int rfbi_configure(int rfbi_module, int bpp, int lines) } EXPORT_SYMBOL(rfbi_configure); -static int rfbi_find_display(struct omap_dss_device *dssdev) +int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, + u16 *x, u16 *y, u16 *w, u16 *h) { - if (dssdev == rfbi.dssdev[0]) - return 0; + u16 dw, dh; - if (dssdev == rfbi.dssdev[1]) - return 1; + dssdev->driver->get_resolution(dssdev, &dw, &dh); - BUG(); - return -1; -} + if (*x > dw || *y > dh) + return -EINVAL; + if (*x + *w > dw) + return -EINVAL; -static void signal_fifo_waiters(void) -{ - if (atomic_read(&rfbi.cmd_fifo_full) > 0) { - /* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */ - complete(&rfbi.cmd_done); - atomic_dec(&rfbi.cmd_fifo_full); - } -} + if (*y + *h > dh) + return -EINVAL; -/* returns 1 for async op, and 0 for sync op */ -static int do_update(struct omap_dss_device *dssdev, struct update_region *upd) -{ - u16 x = upd->x; - u16 y = upd->y; - u16 w = upd->w; - u16 h = upd->h; + if (*w == 1) + return -EINVAL; - perf_mark_setup(); + if (*w == 0 || *h == 0) + return -EINVAL; if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - /*dssdev->driver->enable_te(dssdev, 1); */ - dss_setup_partial_planes(dssdev, &x, &y, &w, &h); + dss_setup_partial_planes(dssdev, x, y, w, h); + dispc_set_lcd_size(*w, *h); } -#ifdef MEASURE_PERF - rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */ -#endif - - dssdev->driver->setup_update(dssdev, x, y, w, h); + return 0; +} +EXPORT_SYMBOL(omap_rfbi_prepare_update); +int omap_rfbi_update(struct omap_dss_device *dssdev, + u16 x, u16 y, u16 w, u16 h, + void (*callback)(void *), void *data) +{ if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - rfbi_transfer_area(w, h, NULL, NULL); - return 1; + rfbi_transfer_area(w, h, callback, data); } else { struct omap_overlay *ovl; void __iomem *addr; @@ -994,123 +911,12 @@ static int do_update(struct omap_dss_device *dssdev, struct update_region *upd) omap_rfbi_write_pixels(addr, scr_width, x, y, w, h); - perf_show("L4"); - - return 0; + callback(data); } -} - -static void process_cmd_fifo(void) -{ - int len; - struct update_param p; - struct omap_dss_device *dssdev; - unsigned long flags; - - if (atomic_inc_return(&rfbi.cmd_pending) != 1) - return; - - while (true) { - spin_lock_irqsave(&rfbi.cmd_lock, flags); - - len = kfifo_out(&rfbi.cmd_fifo, (unsigned char *)&p, - sizeof(struct update_param)); - if (len == 0) { - DSSDBG("nothing more in fifo\n"); - atomic_set(&rfbi.cmd_pending, 0); - spin_unlock_irqrestore(&rfbi.cmd_lock, flags); - break; - } - - /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/ - - spin_unlock_irqrestore(&rfbi.cmd_lock, flags); - - BUG_ON(len != sizeof(struct update_param)); - BUG_ON(p.rfbi_module > 1); - - dssdev = rfbi.dssdev[p.rfbi_module]; - - if (p.cmd == RFBI_CMD_UPDATE) { - if (do_update(dssdev, &p.par.r)) - break; /* async op */ - } else if (p.cmd == RFBI_CMD_SYNC) { - DSSDBG("Signaling SYNC done!\n"); - complete(p.par.sync); - } else - BUG(); - } - - signal_fifo_waiters(); -} -static void rfbi_push_cmd(struct update_param *p) -{ - int ret; - - while (1) { - unsigned long flags; - int available; - - spin_lock_irqsave(&rfbi.cmd_lock, flags); - available = RFBI_CMD_FIFO_LEN_BYTES - - kfifo_len(&rfbi.cmd_fifo); - -/* DSSDBG("%d bytes left in fifo\n", available); */ - if (available < sizeof(struct update_param)) { - DSSDBG("Going to wait because FIFO FULL..\n"); - spin_unlock_irqrestore(&rfbi.cmd_lock, flags); - atomic_inc(&rfbi.cmd_fifo_full); - wait_for_completion(&rfbi.cmd_done); - /*DSSDBG("Woke up because fifo not full anymore\n");*/ - continue; - } - - ret = kfifo_in(&rfbi.cmd_fifo, (unsigned char *)p, - sizeof(struct update_param)); -/* DSSDBG("pushed %d bytes\n", ret);*/ - - spin_unlock_irqrestore(&rfbi.cmd_lock, flags); - - BUG_ON(ret != sizeof(struct update_param)); - - break; - } -} - -static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h) -{ - struct update_param p; - - p.rfbi_module = rfbi_module; - p.cmd = RFBI_CMD_UPDATE; - - p.par.r.x = x; - p.par.r.y = y; - p.par.r.w = w; - p.par.r.h = h; - - DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h); - - rfbi_push_cmd(&p); - - process_cmd_fifo(); -} - -static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp) -{ - struct update_param p; - - p.rfbi_module = rfbi_module; - p.cmd = RFBI_CMD_SYNC; - p.par.sync = sync_comp; - - rfbi_push_cmd(&p); - - DSSDBG("RFBI sync pushed to cmd fifo\n"); - - process_cmd_fifo(); + return 0; } +EXPORT_SYMBOL(omap_rfbi_update); void rfbi_dump_regs(struct seq_file *s) { @@ -1155,12 +961,8 @@ int rfbi_init(void) { u32 rev; u32 l; - int r; spin_lock_init(&rfbi.cmd_lock); - r = kfifo_alloc(&rfbi.cmd_fifo, RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL); - if (r) - return r; init_completion(&rfbi.cmd_done); atomic_set(&rfbi.cmd_fifo_full, 0); @@ -1196,49 +998,10 @@ void rfbi_exit(void) { DSSDBG("rfbi_exit\n"); - kfifo_free(&rfbi.cmd_fifo); - iounmap(rfbi.base); } -/* struct omap_display support */ -static int rfbi_display_update(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h) -{ - int rfbi_module; - - if (w == 0 || h == 0) - return 0; - - rfbi_module = rfbi_find_display(dssdev); - - rfbi_push_update(rfbi_module, x, y, w, h); - - return 0; -} - -static int rfbi_display_sync(struct omap_dss_device *dssdev) -{ - struct completion sync_comp; - int rfbi_module; - - rfbi_module = rfbi_find_display(dssdev); - - init_completion(&sync_comp); - rfbi_push_sync(rfbi_module, &sync_comp); - DSSDBG("Waiting for SYNC to happen...\n"); - wait_for_completion(&sync_comp); - DSSDBG("Released from SYNC\n"); - return 0; -} - -static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable) -{ - dssdev->driver->enable_te(dssdev, enable); - return 0; -} - -static int rfbi_display_enable(struct omap_dss_device *dssdev) +int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { int r; @@ -1269,41 +1032,25 @@ static int rfbi_display_enable(struct omap_dss_device *dssdev) &dssdev->ctrl.rfbi_timings); - if (dssdev->driver->enable) { - r = dssdev->driver->enable(dssdev); - if (r) - goto err2; - } - return 0; -err2: - omap_dispc_unregister_isr(framedone_callback, NULL, - DISPC_IRQ_FRAMEDONE); err1: omap_dss_stop_device(dssdev); err0: return r; } +EXPORT_SYMBOL(omapdss_rfbi_display_enable); -static void rfbi_display_disable(struct omap_dss_device *dssdev) +void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) { - dssdev->driver->disable(dssdev); omap_dispc_unregister_isr(framedone_callback, NULL, DISPC_IRQ_FRAMEDONE); omap_dss_stop_device(dssdev); } +EXPORT_SYMBOL(omapdss_rfbi_display_disable); int rfbi_init_display(struct omap_dss_device *dssdev) { - dssdev->enable = rfbi_display_enable; - dssdev->disable = rfbi_display_disable; - dssdev->update = rfbi_display_update; - dssdev->sync = rfbi_display_sync; - dssdev->enable_te = rfbi_display_enable_te; - rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; - return 0; } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index c24f307d3da..12eb4042dd8 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -41,7 +41,7 @@ static void sdi_basic_init(void) dispc_lcd_enable_signal_polarity(1); } -static int sdi_display_enable(struct omap_dss_device *dssdev) +int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) { struct omap_video_timings *t = &dssdev->panel.timings; struct dss_clock_info dss_cinfo; @@ -57,12 +57,6 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) goto err0; } - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { - DSSERR("dssdev already enabled\n"); - r = -EINVAL; - goto err1; - } - /* In case of skip_init sdi_init has already enabled the clocks */ if (!sdi.skip_init) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); @@ -119,7 +113,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) mdelay(2); } - dispc_enable_lcd_out(1); + dssdev->manager->enable(dssdev->manager); if (dssdev->driver->enable) { r = dssdev->driver->enable(dssdev); @@ -127,13 +121,11 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) goto err3; } - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - sdi.skip_init = 0; return 0; err3: - dispc_enable_lcd_out(0); + dssdev->manager->disable(dssdev->manager); err2: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); err1: @@ -141,120 +133,27 @@ err1: err0: return r; } +EXPORT_SYMBOL(omapdss_sdi_display_enable); -static int sdi_display_resume(struct omap_dss_device *dssdev); - -static void sdi_display_disable(struct omap_dss_device *dssdev) +void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) - return; - - if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) - if (sdi_display_resume(dssdev)) - return; - if (dssdev->driver->disable) dssdev->driver->disable(dssdev); - dispc_enable_lcd_out(0); + dssdev->manager->disable(dssdev->manager); dss_sdi_disable(); dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - omap_dss_stop_device(dssdev); } - -static int sdi_display_suspend(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return -EINVAL; - - if (dssdev->driver->suspend) - dssdev->driver->suspend(dssdev); - - dispc_enable_lcd_out(0); - - dss_sdi_disable(); - - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - return 0; -} - -static int sdi_display_resume(struct omap_dss_device *dssdev) -{ - int r; - - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) - return -EINVAL; - - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - - r = dss_sdi_enable(); - if (r) - goto err; - mdelay(2); - - dispc_enable_lcd_out(1); - - if (dssdev->driver->resume) - dssdev->driver->resume(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -err: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); - return r; -} - -static int sdi_display_set_update_mode(struct omap_dss_device *dssdev, - enum omap_dss_update_mode mode) -{ - if (mode == OMAP_DSS_UPDATE_MANUAL) - return -EINVAL; - - if (mode == OMAP_DSS_UPDATE_DISABLED) { - dispc_enable_lcd_out(0); - sdi.update_enabled = 0; - } else { - dispc_enable_lcd_out(1); - sdi.update_enabled = 1; - } - - return 0; -} - -static enum omap_dss_update_mode sdi_display_get_update_mode( - struct omap_dss_device *dssdev) -{ - return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO : - OMAP_DSS_UPDATE_DISABLED; -} - -static void sdi_get_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) -{ - *timings = dssdev->panel.timings; -} +EXPORT_SYMBOL(omapdss_sdi_display_disable); int sdi_init_display(struct omap_dss_device *dssdev) { DSSDBG("SDI init\n"); - dssdev->enable = sdi_display_enable; - dssdev->disable = sdi_display_disable; - dssdev->suspend = sdi_display_suspend; - dssdev->resume = sdi_display_resume; - dssdev->set_update_mode = sdi_display_set_update_mode; - dssdev->get_update_mode = sdi_display_get_update_mode; - dssdev->get_timings = sdi_get_timings; - return 0; } diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 749a5a0f5be..f0ba5732d84 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -400,114 +400,6 @@ static const struct venc_config *venc_timings_to_config( BUG(); } - - - - -/* driver */ -static int venc_panel_probe(struct omap_dss_device *dssdev) -{ - dssdev->panel.timings = omap_dss_pal_timings; - - return 0; -} - -static void venc_panel_remove(struct omap_dss_device *dssdev) -{ -} - -static int venc_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - /* wait couple of vsyncs until enabling the LCD */ - msleep(50); - - if (dssdev->platform_enable) - r = dssdev->platform_enable(dssdev); - - return r; -} - -static void venc_panel_disable(struct omap_dss_device *dssdev) -{ - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - /* wait at least 5 vsyncs after disabling the LCD */ - - msleep(100); -} - -static int venc_panel_suspend(struct omap_dss_device *dssdev) -{ - venc_panel_disable(dssdev); - return 0; -} - -static int venc_panel_resume(struct omap_dss_device *dssdev) -{ - return venc_panel_enable(dssdev); -} - -static struct omap_dss_driver venc_driver = { - .probe = venc_panel_probe, - .remove = venc_panel_remove, - - .enable = venc_panel_enable, - .disable = venc_panel_disable, - .suspend = venc_panel_suspend, - .resume = venc_panel_resume, - - .driver = { - .name = "venc", - .owner = THIS_MODULE, - }, -}; -/* driver end */ - - - -int venc_init(struct platform_device *pdev) -{ - u8 rev_id; - - mutex_init(&venc.venc_lock); - - venc.wss_data = 0; - - venc.base = ioremap(VENC_BASE, SZ_1K); - if (!venc.base) { - DSSERR("can't ioremap VENC\n"); - return -ENOMEM; - } - - venc.vdda_dac_reg = regulator_get(&pdev->dev, "vdda_dac"); - if (IS_ERR(venc.vdda_dac_reg)) { - iounmap(venc.base); - DSSERR("can't get VDDA_DAC regulator\n"); - return PTR_ERR(venc.vdda_dac_reg); - } - - venc_enable_clocks(1); - - rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); - printk(KERN_INFO "OMAP VENC rev %d\n", rev_id); - - venc_enable_clocks(0); - - return omap_dss_register_driver(&venc_driver); -} - -void venc_exit(void) -{ - omap_dss_unregister_driver(&venc_driver); - - regulator_put(venc.vdda_dac_reg); - - iounmap(venc.base); -} - static void venc_power_on(struct omap_dss_device *dssdev) { u32 l; @@ -540,7 +432,7 @@ static void venc_power_on(struct omap_dss_device *dssdev) if (dssdev->platform_enable) dssdev->platform_enable(dssdev); - dispc_enable_digit_out(1); + dssdev->manager->enable(dssdev->manager); } static void venc_power_off(struct omap_dss_device *dssdev) @@ -548,7 +440,7 @@ static void venc_power_off(struct omap_dss_device *dssdev) venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - dispc_enable_digit_out(0); + dssdev->manager->disable(dssdev->manager); if (dssdev->platform_disable) dssdev->platform_disable(dssdev); @@ -558,7 +450,23 @@ static void venc_power_off(struct omap_dss_device *dssdev) venc_enable_clocks(0); } -static int venc_enable_display(struct omap_dss_device *dssdev) + + + + +/* driver */ +static int venc_panel_probe(struct omap_dss_device *dssdev) +{ + dssdev->panel.timings = omap_dss_pal_timings; + + return 0; +} + +static void venc_panel_remove(struct omap_dss_device *dssdev) +{ +} + +static int venc_panel_enable(struct omap_dss_device *dssdev) { int r = 0; @@ -568,7 +476,13 @@ static int venc_enable_display(struct omap_dss_device *dssdev) if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { r = -EINVAL; - goto err; + goto err1; + } + + if (dssdev->platform_enable) { + r = dssdev->platform_enable(dssdev); + if (r) + goto err2; } venc_power_on(dssdev); @@ -576,13 +490,21 @@ static int venc_enable_display(struct omap_dss_device *dssdev) venc.wss_data = 0; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; -err: + + /* wait couple of vsyncs until enabling the LCD */ + msleep(50); + mutex_unlock(&venc.venc_lock); return r; +err2: + venc_power_off(dssdev); +err1: + mutex_unlock(&venc.venc_lock); + return r; } -static void venc_disable_display(struct omap_dss_device *dssdev) +static void venc_panel_disable(struct omap_dss_device *dssdev) { DSSDBG("venc_disable_display\n"); @@ -599,53 +521,40 @@ static void venc_disable_display(struct omap_dss_device *dssdev) venc_power_off(dssdev); + /* wait at least 5 vsyncs after disabling the LCD */ + msleep(100); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; end: mutex_unlock(&venc.venc_lock); } -static int venc_display_suspend(struct omap_dss_device *dssdev) +static int venc_panel_suspend(struct omap_dss_device *dssdev) { - int r = 0; - - DSSDBG("venc_display_suspend\n"); - - mutex_lock(&venc.venc_lock); - - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { - r = -EINVAL; - goto err; - } - - venc_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; -err: - mutex_unlock(&venc.venc_lock); - - return r; + venc_panel_disable(dssdev); + return 0; } -static int venc_display_resume(struct omap_dss_device *dssdev) +static int venc_panel_resume(struct omap_dss_device *dssdev) { - int r = 0; - - DSSDBG("venc_display_resume\n"); - - mutex_lock(&venc.venc_lock); - - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { - r = -EINVAL; - goto err; - } - - venc_power_on(dssdev); + return venc_panel_enable(dssdev); +} - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; -err: - mutex_unlock(&venc.venc_lock); +static enum omap_dss_update_mode venc_get_update_mode( + struct omap_dss_device *dssdev) +{ + return OMAP_DSS_UPDATE_AUTO; +} - return r; +static int venc_set_update_mode(struct omap_dss_device *dssdev, + enum omap_dss_update_mode mode) +{ + if (mode != OMAP_DSS_UPDATE_AUTO) + return -EINVAL; + return 0; } static void venc_get_timings(struct omap_dss_device *dssdev, @@ -666,8 +575,8 @@ static void venc_set_timings(struct omap_dss_device *dssdev, dssdev->panel.timings = *timings; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { /* turn the venc off and on to get new timings to use */ - venc_disable_display(dssdev); - venc_enable_display(dssdev); + venc_panel_disable(dssdev); + venc_panel_enable(dssdev); } } @@ -716,30 +625,79 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) return 0; } -static enum omap_dss_update_mode venc_display_get_update_mode( - struct omap_dss_device *dssdev) +static struct omap_dss_driver venc_driver = { + .probe = venc_panel_probe, + .remove = venc_panel_remove, + + .enable = venc_panel_enable, + .disable = venc_panel_disable, + .suspend = venc_panel_suspend, + .resume = venc_panel_resume, + + .get_resolution = omapdss_default_get_resolution, + .get_recommended_bpp = omapdss_default_get_recommended_bpp, + + .set_update_mode = venc_set_update_mode, + .get_update_mode = venc_get_update_mode, + + .get_timings = venc_get_timings, + .set_timings = venc_set_timings, + .check_timings = venc_check_timings, + + .get_wss = venc_get_wss, + .set_wss = venc_set_wss, + + .driver = { + .name = "venc", + .owner = THIS_MODULE, + }, +}; +/* driver end */ + + + +int venc_init(struct platform_device *pdev) { - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - return OMAP_DSS_UPDATE_AUTO; - else - return OMAP_DSS_UPDATE_DISABLED; + u8 rev_id; + + mutex_init(&venc.venc_lock); + + venc.wss_data = 0; + + venc.base = ioremap(VENC_BASE, SZ_1K); + if (!venc.base) { + DSSERR("can't ioremap VENC\n"); + return -ENOMEM; + } + + venc.vdda_dac_reg = dss_get_vdda_dac(); + if (IS_ERR(venc.vdda_dac_reg)) { + iounmap(venc.base); + DSSERR("can't get VDDA_DAC regulator\n"); + return PTR_ERR(venc.vdda_dac_reg); + } + + venc_enable_clocks(1); + + rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); + printk(KERN_INFO "OMAP VENC rev %d\n", rev_id); + + venc_enable_clocks(0); + + return omap_dss_register_driver(&venc_driver); +} + +void venc_exit(void) +{ + omap_dss_unregister_driver(&venc_driver); + + iounmap(venc.base); } int venc_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); - dssdev->enable = venc_enable_display; - dssdev->disable = venc_disable_display; - dssdev->suspend = venc_display_suspend; - dssdev->resume = venc_display_resume; - dssdev->get_timings = venc_get_timings; - dssdev->set_timings = venc_set_timings; - dssdev->check_timings = venc_check_timings; - dssdev->get_wss = venc_get_wss; - dssdev->set_wss = venc_set_wss; - dssdev->get_update_mode = venc_display_get_update_mode; - return 0; } |