diff options
Diffstat (limited to 'drivers/video')
45 files changed, 2587 insertions, 2894 deletions
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig index d877c361abd..346d67d6cf4 100644 --- a/drivers/video/omap2/Kconfig +++ b/drivers/video/omap2/Kconfig @@ -1,6 +1,3 @@ -config OMAP2_VRAM - bool - config OMAP2_VRFB bool diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile index 5ddef129f79..5ea7cb9aed1 100644 --- a/drivers/video/omap2/Makefile +++ b/drivers/video/omap2/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_OMAP2_VRAM) += vram.o obj-$(CONFIG_OMAP2_VRFB) += vrfb.o obj-$(CONFIG_OMAP2_DSS) += dss/ diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index c835aa70f96..65eb76c840a 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -710,27 +710,6 @@ static void acx_panel_disable(struct omap_dss_device *dssdev) dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } -static int acx_panel_suspend(struct omap_dss_device *dssdev) -{ - dev_dbg(&dssdev->dev, "%s\n", __func__); - acx_panel_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - return 0; -} - -static int acx_panel_resume(struct omap_dss_device *dssdev) -{ - int r; - - dev_dbg(&dssdev->dev, "%s\n", __func__); - r = acx_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - return 0; -} - static void acx_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { @@ -752,8 +731,6 @@ static struct omap_dss_driver acx_panel_driver = { .enable = acx_panel_enable, .disable = acx_panel_disable, - .suspend = acx_panel_suspend, - .resume = acx_panel_resume, .set_timings = acx_panel_set_timings, .check_timings = acx_panel_check_timings, diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 88295c52681..54ca8ae2107 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -688,40 +688,6 @@ static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) mutex_unlock(&drv_data->lock); } -static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); - - mutex_lock(&drv_data->lock); - - generic_dpi_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - mutex_unlock(&drv_data->lock); - - return 0; -} - -static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); - int r; - - mutex_lock(&drv_data->lock); - - r = generic_dpi_panel_power_on(dssdev); - if (r) - goto err; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - -err: - mutex_unlock(&drv_data->lock); - - return r; -} - static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { @@ -769,8 +735,6 @@ static struct omap_dss_driver dpi_driver = { .enable = generic_dpi_panel_enable, .disable = generic_dpi_panel_disable, - .suspend = generic_dpi_panel_suspend, - .resume = generic_dpi_panel_resume, .set_timings = generic_dpi_panel_set_timings, .get_timings = generic_dpi_panel_get_timings, diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 90c1cabf244..ace419b801e 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c @@ -143,46 +143,12 @@ static void lb035q02_panel_disable(struct omap_dss_device *dssdev) mutex_unlock(&ld->lock); } -static int lb035q02_panel_suspend(struct omap_dss_device *dssdev) -{ - struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); - - mutex_lock(&ld->lock); - - lb035q02_panel_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - mutex_unlock(&ld->lock); - return 0; -} - -static int lb035q02_panel_resume(struct omap_dss_device *dssdev) -{ - struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); - int r; - - mutex_lock(&ld->lock); - - r = lb035q02_panel_power_on(dssdev); - if (r) - goto err; - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - mutex_unlock(&ld->lock); - return 0; -err: - mutex_unlock(&ld->lock); - return r; -} - static struct omap_dss_driver lb035q02_driver = { .probe = lb035q02_panel_probe, .remove = lb035q02_panel_remove, .enable = lb035q02_panel_enable, .disable = lb035q02_panel_disable, - .suspend = lb035q02_panel_suspend, - .resume = lb035q02_panel_resume, .driver = { .name = "lgphilips_lb035q02_panel", diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index 3fc5ad081a2..d1cb722fcdb 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -574,54 +574,6 @@ static void n8x0_panel_disable(struct omap_dss_device *dssdev) mutex_unlock(&ddata->lock); } -static int n8x0_panel_suspend(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = get_drv_data(dssdev); - - dev_dbg(&dssdev->dev, "suspend\n"); - - mutex_lock(&ddata->lock); - - rfbi_bus_lock(); - - n8x0_panel_power_off(dssdev); - - rfbi_bus_unlock(); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - mutex_unlock(&ddata->lock); - - return 0; -} - -static int n8x0_panel_resume(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = get_drv_data(dssdev); - int r; - - dev_dbg(&dssdev->dev, "resume\n"); - - mutex_lock(&ddata->lock); - - rfbi_bus_lock(); - - r = n8x0_panel_power_on(dssdev); - - rfbi_bus_unlock(); - - if (r) { - mutex_unlock(&ddata->lock); - return r; - } - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - mutex_unlock(&ddata->lock); - - return 0; -} - static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres) { @@ -683,8 +635,6 @@ static struct omap_dss_driver n8x0_panel_driver = { .enable = n8x0_panel_enable, .disable = n8x0_panel_disable, - .suspend = n8x0_panel_suspend, - .resume = n8x0_panel_resume, .update = n8x0_panel_update, .sync = n8x0_panel_sync, @@ -702,18 +652,25 @@ static struct omap_dss_driver n8x0_panel_driver = { static int mipid_spi_probe(struct spi_device *spi) { + int r; + dev_dbg(&spi->dev, "mipid_spi_probe\n"); spi->mode = SPI_MODE_0; s_drv_data.spidev = spi; - return 0; + r = omap_dss_register_driver(&n8x0_panel_driver); + if (r) + pr_err("n8x0_panel: dss driver registration failed\n"); + + return r; } static int mipid_spi_remove(struct spi_device *spi) { dev_dbg(&spi->dev, "mipid_spi_remove\n"); + omap_dss_unregister_driver(&n8x0_panel_driver); return 0; } @@ -725,34 +682,6 @@ static struct spi_driver mipid_spi_driver = { .probe = mipid_spi_probe, .remove = __devexit_p(mipid_spi_remove), }; +module_spi_driver(mipid_spi_driver); -static int __init n8x0_panel_drv_init(void) -{ - int r; - - r = spi_register_driver(&mipid_spi_driver); - if (r) { - pr_err("n8x0_panel: spi driver registration failed\n"); - return r; - } - - r = omap_dss_register_driver(&n8x0_panel_driver); - if (r) { - pr_err("n8x0_panel: dss driver registration failed\n"); - spi_unregister_driver(&mipid_spi_driver); - return r; - } - - return 0; -} - -static void __exit n8x0_panel_drv_exit(void) -{ - spi_unregister_driver(&mipid_spi_driver); - - omap_dss_unregister_driver(&n8x0_panel_driver); -} - -module_init(n8x0_panel_drv_init); -module_exit(n8x0_panel_drv_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 908fd268f3d..2a79c283beb 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -236,28 +236,6 @@ static void nec_8048_panel_disable(struct omap_dss_device *dssdev) dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } -static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) -{ - nec_8048_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - return 0; -} - -static int nec_8048_panel_resume(struct omap_dss_device *dssdev) -{ - int r; - - r = nec_8048_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) { return 16; @@ -268,8 +246,6 @@ static struct omap_dss_driver nec_8048_driver = { .remove = nec_8048_panel_remove, .enable = nec_8048_panel_enable, .disable = nec_8048_panel_disable, - .suspend = nec_8048_panel_suspend, - .resume = nec_8048_panel_resume, .get_recommended_bpp = nec_8048_recommended_bpp, .driver = { diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 9df87640ddd..1b94018aac3 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c @@ -50,6 +50,7 @@ struct picodlp_i2c_data { static struct i2c_device_id picodlp_i2c_id[] = { { "picodlp_i2c_driver", 0 }, + { } }; struct picodlp_i2c_command { @@ -503,47 +504,6 @@ static void picodlp_panel_disable(struct omap_dss_device *dssdev) dev_dbg(&dssdev->dev, "disabling picodlp panel\n"); } -static int picodlp_panel_suspend(struct omap_dss_device *dssdev) -{ - struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); - - mutex_lock(&picod->lock); - /* Turn off DLP Power */ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { - mutex_unlock(&picod->lock); - dev_err(&dssdev->dev, "unable to suspend picodlp panel," - " panel is not ACTIVE\n"); - return -EINVAL; - } - - picodlp_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - mutex_unlock(&picod->lock); - - dev_dbg(&dssdev->dev, "suspending picodlp panel\n"); - return 0; -} - -static int picodlp_panel_resume(struct omap_dss_device *dssdev) -{ - struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); - int r; - - mutex_lock(&picod->lock); - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { - mutex_unlock(&picod->lock); - dev_err(&dssdev->dev, "unable to resume picodlp panel," - " panel is not ACTIVE\n"); - return -EINVAL; - } - - r = picodlp_panel_power_on(dssdev); - mutex_unlock(&picod->lock); - dev_dbg(&dssdev->dev, "resuming picodlp panel\n"); - return r; -} - static void picodlp_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres) { @@ -560,9 +520,6 @@ static struct omap_dss_driver picodlp_driver = { .get_resolution = picodlp_get_resolution, - .suspend = picodlp_panel_suspend, - .resume = picodlp_panel_resume, - .driver = { .name = "picodlp_panel", .owner = THIS_MODULE, diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index 1ec3b277ff1..cada8c621e0 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -194,29 +194,12 @@ static void sharp_ls_panel_disable(struct omap_dss_device *dssdev) dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } -static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev) -{ - sharp_ls_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - return 0; -} - -static int sharp_ls_panel_resume(struct omap_dss_device *dssdev) -{ - int r; - r = sharp_ls_power_on(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - return r; -} - static struct omap_dss_driver sharp_ls_driver = { .probe = sharp_ls_panel_probe, .remove = __exit_p(sharp_ls_panel_remove), .enable = sharp_ls_panel_enable, .disable = sharp_ls_panel_disable, - .suspend = sharp_ls_panel_suspend, - .resume = sharp_ls_panel_resume, .driver = { .name = "sharp_ls_panel", diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index f2f644680ca..a32407a5735 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -1245,76 +1245,6 @@ static void taal_disable(struct omap_dss_device *dssdev) mutex_unlock(&td->lock); } -static int taal_suspend(struct omap_dss_device *dssdev) -{ - struct taal_data *td = dev_get_drvdata(&dssdev->dev); - int r; - - dev_dbg(&dssdev->dev, "suspend\n"); - - mutex_lock(&td->lock); - - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { - r = -EINVAL; - goto err; - } - - taal_cancel_ulps_work(dssdev); - taal_cancel_esd_work(dssdev); - - dsi_bus_lock(dssdev); - - r = taal_wake_up(dssdev); - if (!r) - taal_power_off(dssdev); - - dsi_bus_unlock(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - mutex_unlock(&td->lock); - - return 0; -err: - mutex_unlock(&td->lock); - return r; -} - -static int taal_resume(struct omap_dss_device *dssdev) -{ - struct taal_data *td = dev_get_drvdata(&dssdev->dev); - int r; - - dev_dbg(&dssdev->dev, "resume\n"); - - mutex_lock(&td->lock); - - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { - r = -EINVAL; - goto err; - } - - dsi_bus_lock(dssdev); - - r = taal_power_on(dssdev); - - dsi_bus_unlock(dssdev); - - if (r) { - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - } else { - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - taal_queue_esd_work(dssdev); - } - - mutex_unlock(&td->lock); - - return r; -err: - mutex_unlock(&td->lock); - return r; -} - static void taal_framedone_cb(int err, void *data) { struct omap_dss_device *dssdev = data; @@ -1818,8 +1748,6 @@ static struct omap_dss_driver taal_driver = { .enable = taal_enable, .disable = taal_disable, - .suspend = taal_suspend, - .resume = taal_resume, .update = taal_update, .sync = taal_sync, diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 383811cf864..8281baafe1e 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c @@ -189,37 +189,6 @@ static void tfp410_disable(struct omap_dss_device *dssdev) mutex_unlock(&ddata->lock); } -static int tfp410_suspend(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); - - mutex_lock(&ddata->lock); - - tfp410_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - mutex_unlock(&ddata->lock); - - return 0; -} - -static int tfp410_resume(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); - int r; - - mutex_lock(&ddata->lock); - - r = tfp410_power_on(dssdev); - if (r == 0) - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - mutex_unlock(&ddata->lock); - - return r; -} - static void tfp410_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { @@ -355,8 +324,6 @@ static struct omap_dss_driver tfp410_driver = { .enable = tfp410_enable, .disable = tfp410_disable, - .suspend = tfp410_suspend, - .resume = tfp410_resume, .set_timings = tfp410_set_timings, .get_timings = tfp410_get_timings, diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index b5e6dbc59f0..316b3da6d2c 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -401,24 +401,6 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev) dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } -static int tpo_td043_suspend(struct omap_dss_device *dssdev) -{ - dev_dbg(&dssdev->dev, "suspend\n"); - - tpo_td043_disable_dss(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - - return 0; -} - -static int tpo_td043_resume(struct omap_dss_device *dssdev) -{ - dev_dbg(&dssdev->dev, "resume\n"); - - return tpo_td043_enable_dss(dssdev); -} - static int tpo_td043_probe(struct omap_dss_device *dssdev) { struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); @@ -500,8 +482,6 @@ static struct omap_dss_driver tpo_td043_driver = { .enable = tpo_td043_enable, .disable = tpo_td043_disable, - .suspend = tpo_td043_suspend, - .resume = tpo_td043_resume, .set_mirror = tpo_td043_set_hmirror, .get_mirror = tpo_td043_get_hmirror, diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 80f5390aa13..cb0f145c707 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -1,33 +1,30 @@ menuconfig OMAP2_DSS tristate "OMAP2+ Display Subsystem support" - depends on ARCH_OMAP2PLUS help OMAP2+ Display Subsystem support. if OMAP2_DSS -config OMAP2_VRAM_SIZE - int "VRAM size (MB)" - range 0 32 - default 0 +config OMAP2_DSS_DEBUG + bool "Debug support" + default n help - The amount of SDRAM to reserve at boot time for video RAM use. - This VRAM will be used by omapfb and other drivers that need - large continuous RAM area for video use. + This enables printing of debug messages. Alternatively, debug messages + can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting + appropriate flags in <debugfs>/dynamic_debug/control. - You can also set this with "vram=<bytes>" kernel argument, or - in the board file. - -config OMAP2_DSS_DEBUG_SUPPORT - bool "Debug support" - default y +config OMAP2_DSS_DEBUGFS + bool "Debugfs filesystem support" + depends on DEBUG_FS + default n help - This enables debug messages. You need to enable printing - with 'debug' module parameter. + This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables + querying about clock configuration and register configuration of dss, + dispc, dsi, hdmi and rfbi. config OMAP2_DSS_COLLECT_IRQ_STATS bool "Collect DSS IRQ statistics" - depends on OMAP2_DSS_DEBUG_SUPPORT + depends on OMAP2_DSS_DEBUGFS default n help Collect DSS IRQ statistics, printable via debugfs. @@ -62,7 +59,6 @@ config OMAP2_DSS_VENC config OMAP4_DSS_HDMI bool "HDMI support" - depends on ARCH_OMAP4 default y help HDMI Interface. This adds the High Definition Multimedia Interface. @@ -70,11 +66,9 @@ config OMAP4_DSS_HDMI config OMAP4_DSS_HDMI_AUDIO bool - depends on OMAP4_DSS_HDMI config OMAP2_DSS_SDI bool "SDI support" - depends on ARCH_OMAP3 default n help SDI (Serial Display Interface) support. @@ -84,7 +78,6 @@ config OMAP2_DSS_SDI config OMAP2_DSS_DSI bool "DSI support" - depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5 default n help MIPI DSI (Display Serial Interface) support. diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 4549869bfe1..61949ff7940 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,6 +1,10 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o +# Core DSS files omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o + output.o +# DSS compat layer files +omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ + dispc-compat.o display-sysfs.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o @@ -8,3 +12,4 @@ omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ hdmi_panel.o ti_hdmi_4xxx_ip.o +ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 19d66f471b4..d446bdfc4c8 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -18,6 +18,7 @@ #define DSS_SUBSYS_NAME "APPLY" #include <linux/kernel.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/jiffies.h> @@ -26,6 +27,7 @@ #include "dss.h" #include "dss_features.h" +#include "dispc-compat.h" /* * We have 4 levels of cache for the dispc settings. First two are in SW and @@ -70,7 +72,6 @@ struct ovl_priv_data { bool shadow_extra_info_dirty; bool enabled; - enum omap_channel channel; u32 fifo_low, fifo_high; /* @@ -105,6 +106,9 @@ struct mgr_priv_data { struct omap_video_timings timings; struct dss_lcd_mgr_config lcd_config; + + void (*framedone_handler)(void *); + void *framedone_handler_data; }; static struct { @@ -132,7 +136,7 @@ static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) return &dss_data.mgr_priv_data_array[mgr->id]; } -void dss_apply_init(void) +static void apply_init_priv(void) { const int num_ovls = dss_feat_get_num_ovls(); struct mgr_priv_data *mp; @@ -414,11 +418,46 @@ static void wait_pending_extra_info_updates(void) r = wait_for_completion_timeout(&extra_updated_completion, t); if (r == 0) DSSWARN("timeout in wait_pending_extra_info_updates\n"); - else if (r < 0) - DSSERR("wait_pending_extra_info_updates failed: %d\n", r); } -int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) +static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) +{ + return ovl->manager ? + (ovl->manager->output ? ovl->manager->output->device : NULL) : + NULL; +} + +static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) +{ + return mgr->output ? mgr->output->device : NULL; +} + +static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) +{ + unsigned long timeout = msecs_to_jiffies(500); + struct omap_dss_device *dssdev = mgr->get_device(mgr); + u32 irq; + int r; + + r = dispc_runtime_get(); + if (r) + return r; + + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) + irq = DISPC_IRQ_EVSYNC_ODD; + else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) + irq = DISPC_IRQ_EVSYNC_EVEN; + else + irq = dispc_mgr_get_vsync_irq(mgr->id); + + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); + + dispc_runtime_put(); + + return r; +} + +static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); struct mgr_priv_data *mp = get_mgr_priv(mgr); @@ -488,7 +527,7 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) return r; } -int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) +static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) { unsigned long timeout = msecs_to_jiffies(500); struct ovl_priv_data *op; @@ -573,7 +612,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) struct mgr_priv_data *mp; int r; - DSSDBGF("%d", ovl->id); + DSSDBG("writing ovl %d regs", ovl->id); if (!op->enabled || !op->info_dirty) return; @@ -608,7 +647,7 @@ static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) struct ovl_priv_data *op = get_ovl_priv(ovl); struct mgr_priv_data *mp; - DSSDBGF("%d", ovl->id); + DSSDBG("writing ovl %d regs extra", ovl->id); if (!op->extra_info_dirty) return; @@ -617,7 +656,6 @@ static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) * disabled */ dispc_ovl_enable(ovl->id, op->enabled); - dispc_ovl_set_channel_out(ovl->id, op->channel); dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); mp = get_mgr_priv(ovl->manager); @@ -632,7 +670,7 @@ static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) struct mgr_priv_data *mp = get_mgr_priv(mgr); struct omap_overlay *ovl; - DSSDBGF("%d", mgr->id); + DSSDBG("writing mgr %d regs", mgr->id); if (!mp->enabled) return; @@ -658,7 +696,7 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) { struct mgr_priv_data *mp = get_mgr_priv(mgr); - DSSDBGF("%d", mgr->id); + DSSDBG("writing mgr %d regs extra", mgr->id); if (!mp->extra_info_dirty) return; @@ -666,22 +704,8 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) dispc_mgr_set_timings(mgr->id, &mp->timings); /* lcd_config parameters */ - if (dss_mgr_is_lcd(mgr->id)) { - dispc_mgr_set_io_pad_mode(mp->lcd_config.io_pad_mode); - - dispc_mgr_enable_stallmode(mgr->id, mp->lcd_config.stallmode); - dispc_mgr_enable_fifohandcheck(mgr->id, - mp->lcd_config.fifohandcheck); - - dispc_mgr_set_clock_div(mgr->id, &mp->lcd_config.clock_info); - - dispc_mgr_set_tft_data_lines(mgr->id, - mp->lcd_config.video_port_width); - - dispc_lcd_enable_signal_polarity(mp->lcd_config.lcden_sig_polarity); - - dispc_mgr_set_lcd_type_tft(mgr->id); - } + if (dss_mgr_is_lcd(mgr->id)) + dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config); mp->extra_info_dirty = false; if (mp->updating) @@ -761,7 +785,7 @@ static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) } } -void dss_mgr_start_update(struct omap_overlay_manager *mgr) +static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr) { struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; @@ -786,9 +810,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) if (!dss_data.irq_enabled && need_isr()) dss_register_vsync_isr(); - dispc_mgr_enable(mgr->id, true); - - mgr_clear_shadow_dirty(mgr); + dispc_mgr_enable_sync(mgr->id); spin_unlock_irqrestore(&data_lock, flags); } @@ -845,7 +867,6 @@ static void dss_apply_irq_handler(void *data, u32 mask) for (i = 0; i < num_mgrs; i++) { struct omap_overlay_manager *mgr; struct mgr_priv_data *mp; - bool was_updating; mgr = omap_dss_get_overlay_manager(i); mp = get_mgr_priv(mgr); @@ -853,7 +874,6 @@ static void dss_apply_irq_handler(void *data, u32 mask) if (!mp->enabled) continue; - was_updating = mp->updating; mp->updating = dispc_mgr_is_enabled(i); if (!mgr_manual_update(mgr)) { @@ -872,6 +892,21 @@ static void dss_apply_irq_handler(void *data, u32 mask) if (!extra_updating) complete_all(&extra_updated_completion); + /* call framedone handlers for manual update displays */ + for (i = 0; i < num_mgrs; i++) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mgr_manual_update(mgr) || !mp->framedone_handler) + continue; + + if (mask & dispc_mgr_get_framedone_irq(i)) + mp->framedone_handler(mp->framedone_handler_data); + } + if (!need_isr()) dss_unregister_vsync_isr(); @@ -906,7 +941,7 @@ static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) mp->info = mp->user_info; } -int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) +static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) { unsigned long flags; struct omap_overlay *ovl; @@ -1005,7 +1040,7 @@ static void dss_setup_fifos(void) } } -int dss_mgr_enable(struct omap_overlay_manager *mgr) +static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr) { struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; @@ -1035,10 +1070,13 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) if (!mgr_manual_update(mgr)) mp->updating = true; + if (!dss_data.irq_enabled && need_isr()) + dss_register_vsync_isr(); + spin_unlock_irqrestore(&data_lock, flags); if (!mgr_manual_update(mgr)) - dispc_mgr_enable(mgr->id, true); + dispc_mgr_enable_sync(mgr->id); out: mutex_unlock(&apply_lock); @@ -1052,7 +1090,7 @@ err: return r; } -void dss_mgr_disable(struct omap_overlay_manager *mgr) +static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr) { struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; @@ -1063,7 +1101,7 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) goto out; if (!mgr_manual_update(mgr)) - dispc_mgr_enable(mgr->id, false); + dispc_mgr_disable_sync(mgr->id); spin_lock_irqsave(&data_lock, flags); @@ -1076,7 +1114,7 @@ out: mutex_unlock(&apply_lock); } -int dss_mgr_set_info(struct omap_overlay_manager *mgr, +static int dss_mgr_set_info(struct omap_overlay_manager *mgr, struct omap_overlay_manager_info *info) { struct mgr_priv_data *mp = get_mgr_priv(mgr); @@ -1097,7 +1135,7 @@ int dss_mgr_set_info(struct omap_overlay_manager *mgr, return 0; } -void dss_mgr_get_info(struct omap_overlay_manager *mgr, +static void dss_mgr_get_info(struct omap_overlay_manager *mgr, struct omap_overlay_manager_info *info) { struct mgr_priv_data *mp = get_mgr_priv(mgr); @@ -1110,7 +1148,7 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, spin_unlock_irqrestore(&data_lock, flags); } -int dss_mgr_set_output(struct omap_overlay_manager *mgr, +static int dss_mgr_set_output(struct omap_overlay_manager *mgr, struct omap_dss_output *output) { int r; @@ -1142,7 +1180,7 @@ err: return r; } -int dss_mgr_unset_output(struct omap_overlay_manager *mgr) +static int dss_mgr_unset_output(struct omap_overlay_manager *mgr) { int r; struct mgr_priv_data *mp = get_mgr_priv(mgr); @@ -1189,7 +1227,7 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, mp->extra_info_dirty = true; } -void dss_mgr_set_timings(struct omap_overlay_manager *mgr, +static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr, const struct omap_video_timings *timings) { unsigned long flags; @@ -1217,7 +1255,7 @@ static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, mp->extra_info_dirty = true; } -void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, +static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr, const struct dss_lcd_mgr_config *config) { unsigned long flags; @@ -1236,7 +1274,7 @@ out: spin_unlock_irqrestore(&data_lock, flags); } -int dss_ovl_set_info(struct omap_overlay *ovl, +static int dss_ovl_set_info(struct omap_overlay *ovl, struct omap_overlay_info *info) { struct ovl_priv_data *op = get_ovl_priv(ovl); @@ -1257,7 +1295,7 @@ int dss_ovl_set_info(struct omap_overlay *ovl, return 0; } -void dss_ovl_get_info(struct omap_overlay *ovl, +static void dss_ovl_get_info(struct omap_overlay *ovl, struct omap_overlay_info *info) { struct ovl_priv_data *op = get_ovl_priv(ovl); @@ -1270,7 +1308,7 @@ void dss_ovl_get_info(struct omap_overlay *ovl, spin_unlock_irqrestore(&data_lock, flags); } -int dss_ovl_set_manager(struct omap_overlay *ovl, +static int dss_ovl_set_manager(struct omap_overlay *ovl, struct omap_overlay_manager *mgr) { struct ovl_priv_data *op = get_ovl_priv(ovl); @@ -1289,45 +1327,40 @@ int dss_ovl_set_manager(struct omap_overlay *ovl, goto err; } + r = dispc_runtime_get(); + if (r) + goto err; + spin_lock_irqsave(&data_lock, flags); if (op->enabled) { spin_unlock_irqrestore(&data_lock, flags); DSSERR("overlay has to be disabled to change the manager\n"); r = -EINVAL; - goto err; + goto err1; } - op->channel = mgr->id; - op->extra_info_dirty = true; + dispc_ovl_set_channel_out(ovl->id, mgr->id); ovl->manager = mgr; list_add_tail(&ovl->list, &mgr->overlays); spin_unlock_irqrestore(&data_lock, flags); - /* XXX: When there is an overlay on a DSI manual update display, and - * the overlay is first disabled, then moved to tv, and enabled, we - * seem to get SYNC_LOST_DIGIT error. - * - * Waiting doesn't seem to help, but updating the manual update display - * after disabling the overlay seems to fix this. This hints that the - * overlay is perhaps somehow tied to the LCD output until the output - * is updated. - * - * Userspace workaround for this is to update the LCD after disabling - * the overlay, but before moving the overlay to TV. - */ + dispc_runtime_put(); mutex_unlock(&apply_lock); return 0; + +err1: + dispc_runtime_put(); err: mutex_unlock(&apply_lock); return r; } -int dss_ovl_unset_manager(struct omap_overlay *ovl) +static int dss_ovl_unset_manager(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; @@ -1355,9 +1388,24 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl) /* wait for pending extra_info updates to ensure the ovl is disabled */ wait_pending_extra_info_updates(); + /* + * For a manual update display, there is no guarantee that the overlay + * is really disabled in HW, we may need an extra update from this + * manager before the configurations can go in. Return an error if the + * overlay needed an update from the manager. + * + * TODO: Instead of returning an error, try to do a dummy manager update + * here to disable the overlay in hardware. Use the *GATED fields in + * the DISPC_CONFIG registers to do a dummy update. + */ spin_lock_irqsave(&data_lock, flags); - op->channel = -1; + if (ovl_manual_update(ovl) && op->extra_info_dirty) { + spin_unlock_irqrestore(&data_lock, flags); + DSSERR("need an update to change the manager\n"); + r = -EINVAL; + goto err; + } ovl->manager = NULL; list_del(&ovl->list); @@ -1372,7 +1420,7 @@ err: return r; } -bool dss_ovl_is_enabled(struct omap_overlay *ovl) +static bool dss_ovl_is_enabled(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; @@ -1387,7 +1435,7 @@ bool dss_ovl_is_enabled(struct omap_overlay *ovl) return e; } -int dss_ovl_enable(struct omap_overlay *ovl) +static int dss_ovl_enable(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; @@ -1437,7 +1485,7 @@ err1: return r; } -int dss_ovl_disable(struct omap_overlay *ovl) +static int dss_ovl_disable(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; @@ -1472,3 +1520,152 @@ err: return r; } +static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr, + void (*handler)(void *), void *data) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + + if (mp->framedone_handler) + return -EBUSY; + + mp->framedone_handler = handler; + mp->framedone_handler_data = data; + + return 0; +} + +static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr, + void (*handler)(void *), void *data) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + + WARN_ON(mp->framedone_handler != handler || + mp->framedone_handler_data != data); + + mp->framedone_handler = NULL; + mp->framedone_handler_data = NULL; +} + +static const struct dss_mgr_ops apply_mgr_ops = { + .start_update = dss_mgr_start_update_compat, + .enable = dss_mgr_enable_compat, + .disable = dss_mgr_disable_compat, + .set_timings = dss_mgr_set_timings_compat, + .set_lcd_config = dss_mgr_set_lcd_config_compat, + .register_framedone_handler = dss_mgr_register_framedone_handler_compat, + .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat, +}; + +static int compat_refcnt; +static DEFINE_MUTEX(compat_init_lock); + +int omapdss_compat_init(void) +{ + struct platform_device *pdev = dss_get_core_pdev(); + struct omap_dss_device *dssdev = NULL; + int i, r; + + mutex_lock(&compat_init_lock); + + if (compat_refcnt++ > 0) + goto out; + + apply_init_priv(); + + dss_init_overlay_managers(pdev); + dss_init_overlays(pdev); + + for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { + struct omap_overlay_manager *mgr; + + mgr = omap_dss_get_overlay_manager(i); + + mgr->set_output = &dss_mgr_set_output; + mgr->unset_output = &dss_mgr_unset_output; + mgr->apply = &omap_dss_mgr_apply; + mgr->set_manager_info = &dss_mgr_set_info; + mgr->get_manager_info = &dss_mgr_get_info; + mgr->wait_for_go = &dss_mgr_wait_for_go; + mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; + mgr->get_device = &dss_mgr_get_device; + } + + for (i = 0; i < omap_dss_get_num_overlays(); i++) { + struct omap_overlay *ovl = omap_dss_get_overlay(i); + + ovl->is_enabled = &dss_ovl_is_enabled; + ovl->enable = &dss_ovl_enable; + ovl->disable = &dss_ovl_disable; + ovl->set_manager = &dss_ovl_set_manager; + ovl->unset_manager = &dss_ovl_unset_manager; + ovl->set_overlay_info = &dss_ovl_set_info; + ovl->get_overlay_info = &dss_ovl_get_info; + ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; + ovl->get_device = &dss_ovl_get_device; + } + + r = dss_install_mgr_ops(&apply_mgr_ops); + if (r) + goto err_mgr_ops; + + for_each_dss_dev(dssdev) { + r = display_init_sysfs(pdev, dssdev); + /* XXX uninit sysfs files on error */ + if (r) + goto err_disp_sysfs; + } + + dispc_runtime_get(); + + r = dss_dispc_initialize_irq(); + if (r) + goto err_init_irq; + + dispc_runtime_put(); + +out: + mutex_unlock(&compat_init_lock); + + return 0; + +err_init_irq: + dispc_runtime_put(); + +err_disp_sysfs: + dss_uninstall_mgr_ops(); + +err_mgr_ops: + dss_uninit_overlay_managers(pdev); + dss_uninit_overlays(pdev); + + compat_refcnt--; + + mutex_unlock(&compat_init_lock); + + return r; +} +EXPORT_SYMBOL(omapdss_compat_init); + +void omapdss_compat_uninit(void) +{ + struct platform_device *pdev = dss_get_core_pdev(); + struct omap_dss_device *dssdev = NULL; + + mutex_lock(&compat_init_lock); + + if (--compat_refcnt > 0) + goto out; + + dss_dispc_uninitialize_irq(); + + for_each_dss_dev(dssdev) + display_uninit_sysfs(pdev, dssdev); + + dss_uninstall_mgr_ops(); + + dss_uninit_overlay_managers(pdev); + dss_uninit_overlays(pdev); +out: + mutex_unlock(&compat_init_lock); +} +EXPORT_SYMBOL(omapdss_compat_uninit); diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index b2af72dc20b..f8779d4750b 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -53,15 +53,23 @@ static char *def_disp_name; module_param_named(def_disp, def_disp_name, charp, 0); MODULE_PARM_DESC(def_disp, "default display name"); -#ifdef DEBUG -bool dss_debug; -module_param_named(debug, dss_debug, bool, 0644); -#endif - -const char *dss_get_default_display_name(void) +const char *omapdss_get_default_display_name(void) { return core.default_display_name; } +EXPORT_SYMBOL(omapdss_get_default_display_name); + +enum omapdss_version omapdss_get_version(void) +{ + struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; + return pdata->version; +} +EXPORT_SYMBOL(omapdss_get_version); + +struct platform_device *dss_get_core_pdev(void) +{ + return core.pdev; +} /* REGULATORS */ @@ -93,21 +101,6 @@ struct regulator *dss_get_vdds_sdi(void) return reg; } -int dss_get_ctx_loss_count(struct device *dev) -{ - struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; - int cnt; - - if (!board_data->get_context_loss_count) - return -ENOENT; - - cnt = board_data->get_context_loss_count(dev); - - WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); - - return cnt; -} - int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) { struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; @@ -122,7 +115,7 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask) { struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; - if (!board_data->dsi_enable_pads) + if (!board_data->dsi_disable_pads) return; return board_data->dsi_disable_pads(dsi_id, lane_mask); @@ -138,7 +131,7 @@ int dss_set_min_bus_tput(struct device *dev, unsigned long tput) return 0; } -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +#if defined(CONFIG_OMAP2_DSS_DEBUGFS) static int dss_debug_show(struct seq_file *s, void *unused) { void (*func)(struct seq_file *) = s->private; @@ -193,7 +186,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) return 0; } -#else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ +#else /* CONFIG_OMAP2_DSS_DEBUGFS */ static inline int dss_initialize_debugfs(void) { return 0; @@ -205,7 +198,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) { return 0; } -#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ +#endif /* CONFIG_OMAP2_DSS_DEBUGFS */ /* PLATFORM DEVICE */ static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) @@ -237,12 +230,7 @@ static int __init omap_dss_probe(struct platform_device *pdev) core.pdev = pdev; - dss_features_init(); - - dss_apply_init(); - - dss_init_overlay_managers(pdev); - dss_init_overlays(pdev); + dss_features_init(omapdss_get_version()); r = dss_initialize_debugfs(); if (r) @@ -268,9 +256,6 @@ static int omap_dss_remove(struct platform_device *pdev) dss_uninitialize_debugfs(); - dss_uninit_overlays(pdev); - dss_uninit_overlay_managers(pdev); - return 0; } @@ -358,15 +343,10 @@ static int dss_driver_probe(struct device *dev) dev_name(dev), dssdev->driver_name, dssdrv->driver.name); - r = dss_init_device(core.pdev, dssdev); - if (r) - return r; - r = dssdrv->probe(dssdev); if (r) { DSSERR("driver probe failed: %d\n", r); - dss_uninit_device(core.pdev, dssdev); return r; } @@ -387,8 +367,6 @@ static int dss_driver_remove(struct device *dev) dssdrv->remove(dssdev); - dss_uninit_device(core.pdev, dssdev); - dssdev->driver = NULL; return 0; @@ -507,6 +485,9 @@ static int __init omap_dss_bus_register(void) /* INIT */ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_init_platform_driver, +#endif #ifdef CONFIG_OMAP2_DSS_DPI dpi_init_platform_driver, #endif @@ -519,15 +500,15 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { #ifdef CONFIG_OMAP2_DSS_VENC venc_init_platform_driver, #endif -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_init_platform_driver, -#endif #ifdef CONFIG_OMAP4_DSS_HDMI hdmi_init_platform_driver, #endif }; static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_uninit_platform_driver, +#endif #ifdef CONFIG_OMAP2_DSS_DPI dpi_uninit_platform_driver, #endif @@ -540,9 +521,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { #ifdef CONFIG_OMAP2_DSS_VENC venc_uninit_platform_driver, #endif -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_uninit_platform_driver, -#endif #ifdef CONFIG_OMAP4_DSS_HDMI hdmi_uninit_platform_driver, #endif diff --git a/drivers/video/omap2/dss/dispc-compat.c b/drivers/video/omap2/dss/dispc-compat.c new file mode 100644 index 00000000000..928884c9a0a --- /dev/null +++ b/drivers/video/omap2/dss/dispc-compat.c @@ -0,0 +1,667 @@ +/* + * Copyright (C) 2012 Texas Instruments + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "APPLY" + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/jiffies.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/seq_file.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" +#include "dispc-compat.h" + +#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ + DISPC_IRQ_OCP_ERR | \ + DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ + DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ + DISPC_IRQ_SYNC_LOST | \ + DISPC_IRQ_SYNC_LOST_DIGIT) + +#define DISPC_MAX_NR_ISRS 8 + +struct omap_dispc_isr_data { + omap_dispc_isr_t isr; + void *arg; + u32 mask; +}; + +struct dispc_irq_stats { + unsigned long last_reset; + unsigned irq_count; + unsigned irqs[32]; +}; + +static struct { + spinlock_t irq_lock; + u32 irq_error_mask; + struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; + u32 error_irqs; + struct work_struct error_work; + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spinlock_t irq_stats_lock; + struct dispc_irq_stats irq_stats; +#endif +} dispc_compat; + + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS +static void dispc_dump_irqs(struct seq_file *s) +{ + unsigned long flags; + struct dispc_irq_stats stats; + + spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags); + + stats = dispc_compat.irq_stats; + memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats)); + dispc_compat.irq_stats.last_reset = jiffies; + + spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags); + + seq_printf(s, "period %u ms\n", + jiffies_to_msecs(jiffies - stats.last_reset)); + + seq_printf(s, "irqs %d\n", stats.irq_count); +#define PIS(x) \ + seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); + + PIS(FRAMEDONE); + PIS(VSYNC); + PIS(EVSYNC_EVEN); + PIS(EVSYNC_ODD); + PIS(ACBIAS_COUNT_STAT); + PIS(PROG_LINE_NUM); + PIS(GFX_FIFO_UNDERFLOW); + PIS(GFX_END_WIN); + PIS(PAL_GAMMA_MASK); + PIS(OCP_ERR); + PIS(VID1_FIFO_UNDERFLOW); + PIS(VID1_END_WIN); + PIS(VID2_FIFO_UNDERFLOW); + PIS(VID2_END_WIN); + if (dss_feat_get_num_ovls() > 3) { + PIS(VID3_FIFO_UNDERFLOW); + PIS(VID3_END_WIN); + } + PIS(SYNC_LOST); + PIS(SYNC_LOST_DIGIT); + PIS(WAKEUP); + if (dss_has_feature(FEAT_MGR_LCD2)) { + PIS(FRAMEDONE2); + PIS(VSYNC2); + PIS(ACBIAS_COUNT_STAT2); + PIS(SYNC_LOST2); + } + if (dss_has_feature(FEAT_MGR_LCD3)) { + PIS(FRAMEDONE3); + PIS(VSYNC3); + PIS(ACBIAS_COUNT_STAT3); + PIS(SYNC_LOST3); + } +#undef PIS +} +#endif + +/* dispc.irq_lock has to be locked by the caller */ +static void _omap_dispc_set_irqs(void) +{ + u32 mask; + int i; + struct omap_dispc_isr_data *isr_data; + + mask = dispc_compat.irq_error_mask; + + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { + isr_data = &dispc_compat.registered_isr[i]; + + if (isr_data->isr == NULL) + continue; + + mask |= isr_data->mask; + } + + dispc_write_irqenable(mask); +} + +int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) +{ + int i; + int ret; + unsigned long flags; + struct omap_dispc_isr_data *isr_data; + + if (isr == NULL) + return -EINVAL; + + spin_lock_irqsave(&dispc_compat.irq_lock, flags); + + /* check for duplicate entry */ + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { + isr_data = &dispc_compat.registered_isr[i]; + if (isr_data->isr == isr && isr_data->arg == arg && + isr_data->mask == mask) { + ret = -EINVAL; + goto err; + } + } + + isr_data = NULL; + ret = -EBUSY; + + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { + isr_data = &dispc_compat.registered_isr[i]; + + if (isr_data->isr != NULL) + continue; + + isr_data->isr = isr; + isr_data->arg = arg; + isr_data->mask = mask; + ret = 0; + + break; + } + + if (ret) + goto err; + + _omap_dispc_set_irqs(); + + spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); + + return 0; +err: + spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); + + return ret; +} +EXPORT_SYMBOL(omap_dispc_register_isr); + +int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) +{ + int i; + unsigned long flags; + int ret = -EINVAL; + struct omap_dispc_isr_data *isr_data; + + spin_lock_irqsave(&dispc_compat.irq_lock, flags); + + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { + isr_data = &dispc_compat.registered_isr[i]; + if (isr_data->isr != isr || isr_data->arg != arg || + isr_data->mask != mask) + continue; + + /* found the correct isr */ + + isr_data->isr = NULL; + isr_data->arg = NULL; + isr_data->mask = 0; + + ret = 0; + break; + } + + if (ret == 0) + _omap_dispc_set_irqs(); + + spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); + + return ret; +} +EXPORT_SYMBOL(omap_dispc_unregister_isr); + +static void print_irq_status(u32 status) +{ + if ((status & dispc_compat.irq_error_mask) == 0) + return; + +#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : "" + + pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n", + status, + PIS(OCP_ERR), + PIS(GFX_FIFO_UNDERFLOW), + PIS(VID1_FIFO_UNDERFLOW), + PIS(VID2_FIFO_UNDERFLOW), + dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "", + PIS(SYNC_LOST), + PIS(SYNC_LOST_DIGIT), + dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "", + dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : ""); +#undef PIS +} + +/* Called from dss.c. Note that we don't touch clocks here, + * but we presume they are on because we got an IRQ. However, + * an irq handler may turn the clocks off, so we may not have + * clock later in the function. */ +static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) +{ + int i; + u32 irqstatus, irqenable; + u32 handledirqs = 0; + u32 unhandled_errors; + struct omap_dispc_isr_data *isr_data; + struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; + + spin_lock(&dispc_compat.irq_lock); + + irqstatus = dispc_read_irqstatus(); + irqenable = dispc_read_irqenable(); + + /* IRQ is not for us */ + if (!(irqstatus & irqenable)) { + spin_unlock(&dispc_compat.irq_lock); + return IRQ_NONE; + } + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_lock(&dispc_compat.irq_stats_lock); + dispc_compat.irq_stats.irq_count++; + dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs); + spin_unlock(&dispc_compat.irq_stats_lock); +#endif + + print_irq_status(irqstatus); + + /* Ack the interrupt. Do it here before clocks are possibly turned + * off */ + dispc_clear_irqstatus(irqstatus); + /* flush posted write */ + dispc_read_irqstatus(); + + /* make a copy and unlock, so that isrs can unregister + * themselves */ + memcpy(registered_isr, dispc_compat.registered_isr, + sizeof(registered_isr)); + + spin_unlock(&dispc_compat.irq_lock); + + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { + isr_data = ®istered_isr[i]; + + if (!isr_data->isr) + continue; + + if (isr_data->mask & irqstatus) { + isr_data->isr(isr_data->arg, irqstatus); + handledirqs |= isr_data->mask; + } + } + + spin_lock(&dispc_compat.irq_lock); + + unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask; + + if (unhandled_errors) { + dispc_compat.error_irqs |= unhandled_errors; + + dispc_compat.irq_error_mask &= ~unhandled_errors; + _omap_dispc_set_irqs(); + + schedule_work(&dispc_compat.error_work); + } + + spin_unlock(&dispc_compat.irq_lock); + + return IRQ_HANDLED; +} + +static void dispc_error_worker(struct work_struct *work) +{ + int i; + u32 errors; + unsigned long flags; + static const unsigned fifo_underflow_bits[] = { + DISPC_IRQ_GFX_FIFO_UNDERFLOW, + DISPC_IRQ_VID1_FIFO_UNDERFLOW, + DISPC_IRQ_VID2_FIFO_UNDERFLOW, + DISPC_IRQ_VID3_FIFO_UNDERFLOW, + }; + + spin_lock_irqsave(&dispc_compat.irq_lock, flags); + errors = dispc_compat.error_irqs; + dispc_compat.error_irqs = 0; + spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); + + dispc_runtime_get(); + + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + struct omap_overlay *ovl; + unsigned bit; + + ovl = omap_dss_get_overlay(i); + bit = fifo_underflow_bits[i]; + + if (bit & errors) { + DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", + ovl->name); + dispc_ovl_enable(ovl->id, false); + dispc_mgr_go(ovl->manager->id); + msleep(50); + } + } + + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + struct omap_overlay_manager *mgr; + unsigned bit; + + mgr = omap_dss_get_overlay_manager(i); + bit = dispc_mgr_get_sync_lost_irq(i); + + if (bit & errors) { + int j; + + DSSERR("SYNC_LOST on channel %s, restarting the output " + "with video overlays disabled\n", + mgr->name); + + dss_mgr_disable(mgr); + + for (j = 0; j < omap_dss_get_num_overlays(); ++j) { + struct omap_overlay *ovl; + ovl = omap_dss_get_overlay(j); + + if (ovl->id != OMAP_DSS_GFX && + ovl->manager == mgr) + ovl->disable(ovl); + } + + dss_mgr_enable(mgr); + } + } + + if (errors & DISPC_IRQ_OCP_ERR) { + DSSERR("OCP_ERR\n"); + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + struct omap_overlay_manager *mgr; + + mgr = omap_dss_get_overlay_manager(i); + dss_mgr_disable(mgr); + } + } + + spin_lock_irqsave(&dispc_compat.irq_lock, flags); + dispc_compat.irq_error_mask |= errors; + _omap_dispc_set_irqs(); + spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); + + dispc_runtime_put(); +} + +int dss_dispc_initialize_irq(void) +{ + int r; + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_lock_init(&dispc_compat.irq_stats_lock); + dispc_compat.irq_stats.last_reset = jiffies; + dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); +#endif + + spin_lock_init(&dispc_compat.irq_lock); + + memset(dispc_compat.registered_isr, 0, + sizeof(dispc_compat.registered_isr)); + + dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR; + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; + if (dss_has_feature(FEAT_MGR_LCD3)) + dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3; + if (dss_feat_get_num_ovls() > 3) + dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; + + /* + * there's SYNC_LOST_DIGIT waiting after enabling the DSS, + * so clear it + */ + dispc_clear_irqstatus(dispc_read_irqstatus()); + + INIT_WORK(&dispc_compat.error_work, dispc_error_worker); + + _omap_dispc_set_irqs(); + + r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat); + if (r) { + DSSERR("dispc_request_irq failed\n"); + return r; + } + + return 0; +} + +void dss_dispc_uninitialize_irq(void) +{ + dispc_free_irq(&dispc_compat); +} + +static void dispc_mgr_disable_isr(void *data, u32 mask) +{ + struct completion *compl = data; + complete(compl); +} + +static void dispc_mgr_enable_lcd_out(enum omap_channel channel) +{ + dispc_mgr_enable(channel, true); +} + +static void dispc_mgr_disable_lcd_out(enum omap_channel channel) +{ + DECLARE_COMPLETION_ONSTACK(framedone_compl); + int r; + u32 irq; + + if (dispc_mgr_is_enabled(channel) == false) + return; + + /* + * When we disable LCD output, we need to wait for FRAMEDONE to know + * that DISPC has finished with the LCD output. + */ + + irq = dispc_mgr_get_framedone_irq(channel); + + r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, + irq); + if (r) + DSSERR("failed to register FRAMEDONE isr\n"); + + dispc_mgr_enable(channel, false); + + /* if we couldn't register for framedone, just sleep and exit */ + if (r) { + msleep(100); + return; + } + + if (!wait_for_completion_timeout(&framedone_compl, + msecs_to_jiffies(100))) + DSSERR("timeout waiting for FRAME DONE\n"); + + r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, + irq); + if (r) + DSSERR("failed to unregister FRAMEDONE isr\n"); +} + +static void dispc_digit_out_enable_isr(void *data, u32 mask) +{ + struct completion *compl = data; + + /* ignore any sync lost interrupts */ + if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD)) + complete(compl); +} + +static void dispc_mgr_enable_digit_out(void) +{ + DECLARE_COMPLETION_ONSTACK(vsync_compl); + int r; + u32 irq_mask; + + if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true) + return; + + /* + * Digit output produces some sync lost interrupts during the first + * frame when enabling. Those need to be ignored, so we register for the + * sync lost irq to prevent the error handler from triggering. + */ + + irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) | + dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT); + + r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl, + irq_mask); + if (r) { + DSSERR("failed to register %x isr\n", irq_mask); + return; + } + + dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true); + + /* wait for the first evsync */ + if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100))) + DSSERR("timeout waiting for digit out to start\n"); + + r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl, + irq_mask); + if (r) + DSSERR("failed to unregister %x isr\n", irq_mask); +} + +static void dispc_mgr_disable_digit_out(void) +{ + DECLARE_COMPLETION_ONSTACK(framedone_compl); + int r, i; + u32 irq_mask; + int num_irqs; + + if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false) + return; + + /* + * When we disable the digit output, we need to wait for FRAMEDONE to + * know that DISPC has finished with the output. + */ + + irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT); + num_irqs = 1; + + if (!irq_mask) { + /* + * omap 2/3 don't have framedone irq for TV, so we need to use + * vsyncs for this. + */ + + irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT); + /* + * We need to wait for both even and odd vsyncs. Note that this + * is not totally reliable, as we could get a vsync interrupt + * before we disable the output, which leads to timeout in the + * wait_for_completion. + */ + num_irqs = 2; + } + + r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, + irq_mask); + if (r) + DSSERR("failed to register %x isr\n", irq_mask); + + dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false); + + /* if we couldn't register the irq, just sleep and exit */ + if (r) { + msleep(100); + return; + } + + for (i = 0; i < num_irqs; ++i) { + if (!wait_for_completion_timeout(&framedone_compl, + msecs_to_jiffies(100))) + DSSERR("timeout waiting for digit out to stop\n"); + } + + r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, + irq_mask); + if (r) + DSSERR("failed to unregister %x isr\n", irq_mask); +} + +void dispc_mgr_enable_sync(enum omap_channel channel) +{ + if (dss_mgr_is_lcd(channel)) + dispc_mgr_enable_lcd_out(channel); + else if (channel == OMAP_DSS_CHANNEL_DIGIT) + dispc_mgr_enable_digit_out(); + else + WARN_ON(1); +} + +void dispc_mgr_disable_sync(enum omap_channel channel) +{ + if (dss_mgr_is_lcd(channel)) + dispc_mgr_disable_lcd_out(channel); + else if (channel == OMAP_DSS_CHANNEL_DIGIT) + dispc_mgr_disable_digit_out(); + else + WARN_ON(1); +} + +int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, + unsigned long timeout) +{ + void dispc_irq_wait_handler(void *data, u32 mask) + { + complete((struct completion *)data); + } + + int r; + DECLARE_COMPLETION_ONSTACK(completion); + + r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, + irqmask); + + if (r) + return r; + + timeout = wait_for_completion_interruptible_timeout(&completion, + timeout); + + omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); + + if (timeout == 0) + return -ETIMEDOUT; + + if (timeout == -ERESTARTSYS) + return -ERESTARTSYS; + + return 0; +} diff --git a/drivers/video/omap2/dss/dispc-compat.h b/drivers/video/omap2/dss/dispc-compat.h new file mode 100644 index 00000000000..14a69b3d4fb --- /dev/null +++ b/drivers/video/omap2/dss/dispc-compat.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 Texas Instruments + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __OMAP2_DSS_DISPC_COMPAT_H +#define __OMAP2_DSS_DISPC_COMPAT_H + +void dispc_mgr_enable_sync(enum omap_channel channel); +void dispc_mgr_disable_sync(enum omap_channel channel); + +int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, + unsigned long timeout); + +int dss_dispc_initialize_irq(void); +void dss_dispc_uninitialize_irq(void); + +#endif diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b43477a5fae..05ff2b91d9e 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -33,11 +33,9 @@ #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/hardirq.h> -#include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> - -#include <plat/cpu.h> +#include <linux/sizes.h> #include <video/omapdss.h> @@ -48,21 +46,6 @@ /* DISPC */ #define DISPC_SZ_REGS SZ_4K -#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ - DISPC_IRQ_OCP_ERR | \ - DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ - DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ - DISPC_IRQ_SYNC_LOST | \ - DISPC_IRQ_SYNC_LOST_DIGIT) - -#define DISPC_MAX_NR_ISRS 8 - -struct omap_dispc_isr_data { - omap_dispc_isr_t isr; - void *arg; - u32 mask; -}; - enum omap_burst_size { BURST_SIZE_X2 = 0, BURST_SIZE_X4 = 1, @@ -75,12 +58,6 @@ enum omap_burst_size { #define REG_FLD_MOD(idx, val, start, end) \ dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) -struct dispc_irq_stats { - unsigned long last_reset; - unsigned irq_count; - unsigned irqs[32]; -}; - struct dispc_features { u8 sw_start; u8 fp_start; @@ -88,19 +65,26 @@ struct dispc_features { u16 sw_max; u16 vp_max; u16 hp_max; - int (*calc_scaling) (enum omap_plane plane, + u8 mgr_width_start; + u8 mgr_height_start; + u16 mgr_width_max; + u16 mgr_height_max; + int (*calc_scaling) (unsigned long pclk, unsigned long lclk, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode, bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, u16 pos_x, unsigned long *core_clk, bool mem_to_mem); - unsigned long (*calc_core_clk) (enum omap_plane plane, + unsigned long (*calc_core_clk) (unsigned long pclk, u16 width, u16 height, u16 out_width, u16 out_height, bool mem_to_mem); u8 num_fifos; /* swap GFX & WB fifos */ bool gfx_fifo_workaround:1; + + /* no DISPC_IRQ_FRAMEDONETV on this SoC */ + bool no_framedone_tv:1; }; #define DISPC_MAX_NR_FIFOS 5 @@ -112,27 +96,15 @@ static struct { int ctx_loss_cnt; int irq; - struct clk *dss_clk; u32 fifo_size[DISPC_MAX_NR_FIFOS]; /* maps which plane is using a fifo. fifo-id -> plane-id */ int fifo_assignment[DISPC_MAX_NR_FIFOS]; - spinlock_t irq_lock; - u32 irq_error_mask; - struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; - u32 error_irqs; - struct work_struct error_work; - bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; const struct dispc_features *feat; - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS - spinlock_t irq_stats_lock; - struct dispc_irq_stats irq_stats; -#endif } dispc; enum omap_color_component { @@ -188,7 +160,7 @@ static const struct { [OMAP_DSS_CHANNEL_DIGIT] = { .name = "DIGIT", .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, - .framedone_irq = 0, + .framedone_irq = DISPC_IRQ_FRAMEDONETV, .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 }, @@ -243,7 +215,6 @@ struct color_conv_coef { int full_range; }; -static void _omap_dispc_set_irqs(void); static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); @@ -376,7 +347,7 @@ static void dispc_save_context(void) if (dss_has_feature(FEAT_CORE_CLK_DIV)) SR(DIVISOR); - dispc.ctx_loss_cnt = dss_get_ctx_loss_count(&dispc.pdev->dev); + dispc.ctx_loss_cnt = dss_get_ctx_loss_count(); dispc.ctx_valid = true; DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); @@ -391,7 +362,7 @@ static void dispc_restore_context(void) if (!dispc.ctx_valid) return; - ctx = dss_get_ctx_loss_count(&dispc.pdev->dev); + ctx = dss_get_ctx_loss_count(); if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) return; @@ -498,7 +469,7 @@ static void dispc_restore_context(void) if (dss_has_feature(FEAT_MGR_LCD3)) RR(CONTROL3); /* clear spurious SYNC_LOST_DIGIT interrupts */ - dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); + dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT); /* * enable last so IRQs won't trigger before @@ -522,6 +493,7 @@ int dispc_runtime_get(void) WARN_ON(r < 0); return r < 0 ? r : 0; } +EXPORT_SYMBOL(dispc_runtime_get); void dispc_runtime_put(void) { @@ -532,16 +504,28 @@ void dispc_runtime_put(void) r = pm_runtime_put_sync(&dispc.pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } +EXPORT_SYMBOL(dispc_runtime_put); u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) { return mgr_desc[channel].vsync_irq; } +EXPORT_SYMBOL(dispc_mgr_get_vsync_irq); u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) { + if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv) + return 0; + return mgr_desc[channel].framedone_irq; } +EXPORT_SYMBOL(dispc_mgr_get_framedone_irq); + +u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel) +{ + return mgr_desc[channel].sync_lost_irq; +} +EXPORT_SYMBOL(dispc_mgr_get_sync_lost_irq); u32 dispc_wb_get_framedone_irq(void) { @@ -552,28 +536,18 @@ bool dispc_mgr_go_busy(enum omap_channel channel) { return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; } +EXPORT_SYMBOL(dispc_mgr_go_busy); void dispc_mgr_go(enum omap_channel channel) { - bool enable_bit, go_bit; - - /* if the channel is not enabled, we don't need GO */ - enable_bit = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE) == 1; - - if (!enable_bit) - return; - - go_bit = mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; - - if (go_bit) { - DSSERR("GO bit not down for channel %d\n", channel); - return; - } + WARN_ON(dispc_mgr_is_enabled(channel) == false); + WARN_ON(dispc_mgr_go_busy(channel)); DSSDBG("GO %s\n", mgr_desc[channel].name); mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); } +EXPORT_SYMBOL(dispc_mgr_go); bool dispc_wb_go_busy(void) { @@ -977,6 +951,7 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) } dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } +EXPORT_SYMBOL(dispc_ovl_set_channel_out); static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) { @@ -1042,7 +1017,7 @@ static void dispc_configure_burst_sizes(void) const int burst_size = BURST_SIZE_X8; /* Configure burst size always to maximum size */ - for (i = 0; i < omap_dss_get_num_overlays(); ++i) + for (i = 0; i < dss_feat_get_num_ovls(); ++i) dispc_ovl_set_burst_size(i, burst_size); } @@ -1076,7 +1051,7 @@ static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) } static void dispc_mgr_set_cpr_coef(enum omap_channel channel, - struct omap_dss_cpr_coefs *coefs) + const struct omap_dss_cpr_coefs *coefs) { u32 coef_r, coef_g, coef_b; @@ -1124,7 +1099,9 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width, { u32 val; - val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); + val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) | + FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0); + dispc_write_reg(DISPC_SIZE_MGR(channel), val); } @@ -1246,7 +1223,7 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, if (use_fifomerge) { total_fifo_size = 0; - for (i = 0; i < omap_dss_get_num_overlays(); ++i) + for (i = 0; i < dss_feat_get_num_ovls(); ++i) total_fifo_size += dispc_ovl_get_fifo_size(i); } else { total_fifo_size = ovl_fifo_size; @@ -1991,16 +1968,14 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width, * This function is used to avoid synclosts in OMAP3, because of some * undocumented horizontal position and timing related limitations. */ -static int check_horiz_timing_omap3(enum omap_plane plane, +static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk, const struct omap_video_timings *t, u16 pos_x, u16 width, u16 height, u16 out_width, u16 out_height) { - int DS = DIV_ROUND_UP(height, out_height); + const int ds = DIV_ROUND_UP(height, out_height); unsigned long nonactive; static const u8 limits[3] = { 8, 10, 20 }; u64 val, blank; - unsigned long pclk = dispc_plane_pclk_rate(plane); - unsigned long lclk = dispc_plane_lclk_rate(plane); int i; nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; @@ -2022,8 +1997,8 @@ static int check_horiz_timing_omap3(enum omap_plane plane, */ val = div_u64((u64)(nonactive - pos_x) * lclk, pclk); DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n", - val, max(0, DS - 2) * width); - if (val < max(0, DS - 2) * width) + val, max(0, ds - 2) * width); + if (val < max(0, ds - 2) * width) return -EINVAL; /* @@ -2033,21 +2008,20 @@ static int check_horiz_timing_omap3(enum omap_plane plane, */ val = div_u64((u64)nonactive * lclk, pclk); DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n", - val, max(0, DS - 1) * width); - if (val < max(0, DS - 1) * width) + val, max(0, ds - 1) * width); + if (val < max(0, ds - 1) * width) return -EINVAL; return 0; } -static unsigned long calc_core_clk_five_taps(enum omap_plane plane, +static unsigned long calc_core_clk_five_taps(unsigned long pclk, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode) { u32 core_clk = 0; u64 tmp; - unsigned long pclk = dispc_plane_pclk_rate(plane); if (height <= out_height && width <= out_width) return (unsigned long) pclk; @@ -2081,22 +2055,19 @@ static unsigned long calc_core_clk_five_taps(enum omap_plane plane, return core_clk; } -static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width, +static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width, u16 height, u16 out_width, u16 out_height, bool mem_to_mem) { - unsigned long pclk = dispc_plane_pclk_rate(plane); - if (height > out_height && width > out_width) return pclk * 4; else return pclk * 2; } -static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, +static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width, u16 height, u16 out_width, u16 out_height, bool mem_to_mem) { unsigned int hf, vf; - unsigned long pclk = dispc_plane_pclk_rate(plane); /* * FIXME how to determine the 'A' factor @@ -2119,11 +2090,9 @@ static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, return pclk * vf * hf; } -static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, +static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width, u16 height, u16 out_width, u16 out_height, bool mem_to_mem) { - unsigned long pclk; - /* * If the overlay/writeback is in mem to mem mode, there are no * downscaling limitations with respect to pixel clock, return 1 as @@ -2133,15 +2102,13 @@ static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, if (mem_to_mem) return 1; - pclk = dispc_plane_pclk_rate(plane); - if (width > out_width) return DIV_ROUND_UP(pclk, out_width) * width; else return pclk; } -static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, +static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode, bool *five_taps, @@ -2159,7 +2126,7 @@ static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, do { in_height = DIV_ROUND_UP(height, *decim_y); in_width = DIV_ROUND_UP(width, *decim_x); - *core_clk = dispc.feat->calc_core_clk(plane, in_width, + *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); error = (in_width > maxsinglelinewidth || !*core_clk || *core_clk > dispc_core_clk_rate()); @@ -2182,7 +2149,7 @@ static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, return 0; } -static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, +static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode, bool *five_taps, @@ -2198,10 +2165,10 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, do { in_height = DIV_ROUND_UP(height, *decim_y); in_width = DIV_ROUND_UP(width, *decim_x); - *core_clk = calc_core_clk_five_taps(plane, mgr_timings, + *core_clk = calc_core_clk_five_taps(pclk, mgr_timings, in_width, in_height, out_width, out_height, color_mode); - error = check_horiz_timing_omap3(plane, mgr_timings, + error = check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, in_width, in_height, out_width, out_height); @@ -2210,7 +2177,7 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, in_height < out_height * 2) *five_taps = false; if (!*five_taps) - *core_clk = dispc.feat->calc_core_clk(plane, in_width, + *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); @@ -2229,8 +2196,8 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, } } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); - if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height, - out_width, out_height)){ + if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width, + height, out_width, out_height)){ DSSERR("horizontal timing too tight\n"); return -EINVAL; } @@ -2248,7 +2215,7 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, return 0; } -static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, +static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode, bool *five_taps, @@ -2260,14 +2227,14 @@ static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, u16 in_height = DIV_ROUND_UP(height, *decim_y); const int maxsinglelinewidth = dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); - unsigned long pclk = dispc_plane_pclk_rate(plane); const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); - if (mem_to_mem) - in_width_max = DIV_ROUND_UP(out_width, maxdownscale); - else + if (mem_to_mem) { + in_width_max = out_width * maxdownscale; + } else { in_width_max = dispc_core_clk_rate() / DIV_ROUND_UP(pclk, out_width); + } *decim_x = DIV_ROUND_UP(width, in_width_max); @@ -2285,12 +2252,12 @@ static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, return -EINVAL; } - *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height, + *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); return 0; } -static int dispc_ovl_calc_scaling(enum omap_plane plane, +static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, enum omap_overlay_caps caps, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, @@ -2309,9 +2276,14 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) return -EINVAL; - *x_predecim = max_decim_limit; - *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && - dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit; + if (mem_to_mem) { + *x_predecim = *y_predecim = 1; + } else { + *x_predecim = max_decim_limit; + *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && + dss_has_feature(FEAT_BURST_2D)) ? + 2 : max_decim_limit; + } if (color_mode == OMAP_DSS_COLOR_CLUT1 || color_mode == OMAP_DSS_COLOR_CLUT2 || @@ -2332,7 +2304,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, if (decim_y > *y_predecim || out_height > height * 8) return -EINVAL; - ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height, + ret = dispc.feat->calc_scaling(pclk, lclk, mgr_timings, width, height, out_width, out_height, color_mode, five_taps, x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, mem_to_mem); @@ -2355,6 +2327,47 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, return 0; } +int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel, + const struct omap_overlay_info *oi, + const struct omap_video_timings *timings, + int *x_predecim, int *y_predecim) +{ + enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane); + bool five_taps = true; + bool fieldmode = 0; + u16 in_height = oi->height; + u16 in_width = oi->width; + bool ilace = timings->interlace; + u16 out_width, out_height; + int pos_x = oi->pos_x; + unsigned long pclk = dispc_mgr_pclk_rate(channel); + unsigned long lclk = dispc_mgr_lclk_rate(channel); + + out_width = oi->out_width == 0 ? oi->width : oi->out_width; + out_height = oi->out_height == 0 ? oi->height : oi->out_height; + + if (ilace && oi->height == out_height) + fieldmode = 1; + + if (ilace) { + if (fieldmode) + in_height /= 2; + out_height /= 2; + + DSSDBG("adjusting for ilace: height %d, out_height %d\n", + in_height, out_height); + } + + if (!dss_feat_color_mode_supported(plane, oi->color_mode)) + return -EINVAL; + + return dispc_ovl_calc_scaling(pclk, lclk, caps, timings, in_width, + in_height, out_width, out_height, oi->color_mode, + &five_taps, x_predecim, y_predecim, pos_x, + oi->rotation_type, false); +} +EXPORT_SYMBOL(dispc_ovl_check); + static int dispc_ovl_setup_common(enum omap_plane plane, enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, @@ -2370,12 +2383,14 @@ static int dispc_ovl_setup_common(enum omap_plane plane, unsigned offset0, offset1; s32 row_inc; s32 pix_inc; - u16 frame_height = height; + u16 frame_width, frame_height; unsigned int field_offset = 0; u16 in_height = height; u16 in_width = width; int x_predecim = 1, y_predecim = 1; bool ilace = mgr_timings->interlace; + unsigned long pclk = dispc_plane_pclk_rate(plane); + unsigned long lclk = dispc_plane_lclk_rate(plane); if (paddr == 0) return -EINVAL; @@ -2400,7 +2415,7 @@ static int dispc_ovl_setup_common(enum omap_plane plane, if (!dss_feat_color_mode_supported(plane, color_mode)) return -EINVAL; - r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width, + r = dispc_ovl_calc_scaling(pclk, lclk, caps, mgr_timings, in_width, in_height, out_width, out_height, color_mode, &five_taps, &x_predecim, &y_predecim, pos_x, rotation_type, mem_to_mem); @@ -2438,20 +2453,28 @@ static int dispc_ovl_setup_common(enum omap_plane plane, row_inc = 0; pix_inc = 0; + if (plane == OMAP_DSS_WB) { + frame_width = out_width; + frame_height = out_height; + } else { + frame_width = in_width; + frame_height = height; + } + if (rotation_type == OMAP_DSS_ROT_TILER) - calc_tiler_rotation_offset(screen_width, in_width, + calc_tiler_rotation_offset(screen_width, frame_width, color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); else if (rotation_type == OMAP_DSS_ROT_DMA) - calc_dma_rotation_offset(rotation, mirror, - screen_width, in_width, frame_height, + calc_dma_rotation_offset(rotation, mirror, screen_width, + frame_width, frame_height, color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); else calc_vrfb_rotation_offset(rotation, mirror, - screen_width, in_width, frame_height, + screen_width, frame_width, frame_height, color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); @@ -2505,7 +2528,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, bool mem_to_mem) { int r; - struct omap_overlay *ovl = omap_dss_get_overlay(plane); + enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane); enum omap_channel channel; channel = dispc_ovl_get_channel_out(plane); @@ -2516,7 +2539,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, oi->color_mode, oi->rotation, oi->mirror, channel, replication); - r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr, + r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, oi->color_mode, oi->rotation, oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, @@ -2524,6 +2547,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, return r; } +EXPORT_SYMBOL(dispc_ovl_setup); int dispc_wb_setup(const struct omap_dss_writeback_info *wi, bool mem_to_mem, const struct omap_video_timings *mgr_timings) @@ -2584,192 +2608,39 @@ int dispc_ovl_enable(enum omap_plane plane, bool enable) return 0; } +EXPORT_SYMBOL(dispc_ovl_enable); -static void dispc_disable_isr(void *data, u32 mask) +bool dispc_ovl_enabled(enum omap_plane plane) { - struct completion *compl = data; - complete(compl); + return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); } +EXPORT_SYMBOL(dispc_ovl_enabled); -static void _enable_lcd_out(enum omap_channel channel, bool enable) +void dispc_mgr_enable(enum omap_channel channel, bool enable) { mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); /* flush posted write */ mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); } - -static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) -{ - struct completion frame_done_completion; - bool is_on; - int r; - u32 irq; - - /* When we disable LCD output, we need to wait until frame is done. - * Otherwise the DSS is still working, and turning off the clocks - * prevents DSS from going to OFF mode */ - is_on = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); - - irq = mgr_desc[channel].framedone_irq; - - if (!enable && is_on) { - init_completion(&frame_done_completion); - - r = omap_dispc_register_isr(dispc_disable_isr, - &frame_done_completion, irq); - - if (r) - DSSERR("failed to register FRAMEDONE isr\n"); - } - - _enable_lcd_out(channel, enable); - - if (!enable && is_on) { - if (!wait_for_completion_timeout(&frame_done_completion, - msecs_to_jiffies(100))) - DSSERR("timeout waiting for FRAME DONE\n"); - - r = omap_dispc_unregister_isr(dispc_disable_isr, - &frame_done_completion, irq); - - if (r) - DSSERR("failed to unregister FRAMEDONE isr\n"); - } -} - -static void _enable_digit_out(bool enable) -{ - REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); - /* flush posted write */ - dispc_read_reg(DISPC_CONTROL); -} - -static void dispc_mgr_enable_digit_out(bool enable) -{ - struct completion frame_done_completion; - enum dss_hdmi_venc_clk_source_select src; - int r, i; - u32 irq_mask; - int num_irqs; - - if (REG_GET(DISPC_CONTROL, 1, 1) == enable) - return; - - src = dss_get_hdmi_venc_clk_source(); - - if (enable) { - unsigned long flags; - /* When we enable digit output, we'll get an extra digit - * sync lost interrupt, that we need to ignore */ - spin_lock_irqsave(&dispc.irq_lock, flags); - dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; - _omap_dispc_set_irqs(); - spin_unlock_irqrestore(&dispc.irq_lock, flags); - } - - /* When we disable digit output, we need to wait until fields are done. - * Otherwise the DSS is still working, and turning off the clocks - * prevents DSS from going to OFF mode. And when enabling, we need to - * wait for the extra sync losts */ - init_completion(&frame_done_completion); - - if (src == DSS_HDMI_M_PCLK && enable == false) { - irq_mask = DISPC_IRQ_FRAMEDONETV; - num_irqs = 1; - } else { - irq_mask = DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; - /* XXX I understand from TRM that we should only wait for the - * current field to complete. But it seems we have to wait for - * both fields */ - num_irqs = 2; - } - - r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion, - irq_mask); - if (r) - DSSERR("failed to register %x isr\n", irq_mask); - - _enable_digit_out(enable); - - for (i = 0; i < num_irqs; ++i) { - if (!wait_for_completion_timeout(&frame_done_completion, - msecs_to_jiffies(100))) - DSSERR("timeout waiting for digit out to %s\n", - enable ? "start" : "stop"); - } - - r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion, - irq_mask); - if (r) - DSSERR("failed to unregister %x isr\n", irq_mask); - - if (enable) { - unsigned long flags; - spin_lock_irqsave(&dispc.irq_lock, flags); - dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST_DIGIT; - dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); - _omap_dispc_set_irqs(); - spin_unlock_irqrestore(&dispc.irq_lock, flags); - } -} +EXPORT_SYMBOL(dispc_mgr_enable); bool dispc_mgr_is_enabled(enum omap_channel channel) { return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); } - -void dispc_mgr_enable(enum omap_channel channel, bool enable) -{ - if (dss_mgr_is_lcd(channel)) - dispc_mgr_enable_lcd_out(channel, enable); - else if (channel == OMAP_DSS_CHANNEL_DIGIT) - dispc_mgr_enable_digit_out(enable); - else - BUG(); -} +EXPORT_SYMBOL(dispc_mgr_is_enabled); void dispc_wb_enable(bool enable) { - enum omap_plane plane = OMAP_DSS_WB; - struct completion frame_done_completion; - bool is_on; - int r; - u32 irq; - - is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); - irq = DISPC_IRQ_FRAMEDONEWB; - - if (!enable && is_on) { - init_completion(&frame_done_completion); - - r = omap_dispc_register_isr(dispc_disable_isr, - &frame_done_completion, irq); - if (r) - DSSERR("failed to register FRAMEDONEWB isr\n"); - } - - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); - - if (!enable && is_on) { - if (!wait_for_completion_timeout(&frame_done_completion, - msecs_to_jiffies(100))) - DSSERR("timeout waiting for FRAMEDONEWB\n"); - - r = omap_dispc_unregister_isr(dispc_disable_isr, - &frame_done_completion, irq); - if (r) - DSSERR("failed to unregister FRAMEDONEWB isr\n"); - } + dispc_ovl_enable(OMAP_DSS_WB, enable); } bool dispc_wb_is_enabled(void) { - enum omap_plane plane = OMAP_DSS_WB; - - return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); + return dispc_ovl_enabled(OMAP_DSS_WB); } -void dispc_lcd_enable_signal_polarity(bool act_high) +static void dispc_lcd_enable_signal_polarity(bool act_high) { if (!dss_has_feature(FEAT_LCDENABLEPOL)) return; @@ -2793,13 +2664,13 @@ void dispc_pck_free_enable(bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); } -void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) { mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); } -void dispc_mgr_set_lcd_type_tft(enum omap_channel channel) +static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel) { mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1); } @@ -2842,7 +2713,7 @@ static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, } void dispc_mgr_setup(enum omap_channel channel, - struct omap_overlay_manager_info *info) + const struct omap_overlay_manager_info *info) { dispc_mgr_set_default_color(channel, info->default_color); dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); @@ -2854,8 +2725,9 @@ void dispc_mgr_setup(enum omap_channel channel, dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); } } +EXPORT_SYMBOL(dispc_mgr_setup); -void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) +static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) { int code; @@ -2880,7 +2752,7 @@ void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code); } -void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) +static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) { u32 l; int gpout0, gpout1; @@ -2909,15 +2781,33 @@ void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) dispc_write_reg(DISPC_CONTROL, l); } -void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) { mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable); } +void dispc_mgr_set_lcd_config(enum omap_channel channel, + const struct dss_lcd_mgr_config *config) +{ + dispc_mgr_set_io_pad_mode(config->io_pad_mode); + + dispc_mgr_enable_stallmode(channel, config->stallmode); + dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck); + + dispc_mgr_set_clock_div(channel, &config->clock_info); + + dispc_mgr_set_tft_data_lines(channel, config->video_port_width); + + dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity); + + dispc_mgr_set_lcd_type_tft(channel); +} +EXPORT_SYMBOL(dispc_mgr_set_lcd_config); + static bool _dispc_mgr_size_ok(u16 width, u16 height) { - return width <= dss_feat_get_param_max(FEAT_PARAM_MGR_WIDTH) && - height <= dss_feat_get_param_max(FEAT_PARAM_MGR_HEIGHT); + return width <= dispc.feat->mgr_width_max && + height <= dispc.feat->mgr_height_max; } static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, @@ -3012,7 +2902,7 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, /* change name to mode? */ void dispc_mgr_set_timings(enum omap_channel channel, - struct omap_video_timings *timings) + const struct omap_video_timings *timings) { unsigned xtot, ytot; unsigned long ht, vt; @@ -3051,6 +2941,7 @@ void dispc_mgr_set_timings(enum omap_channel channel, dispc_mgr_set_size(channel, t.x_res, t.y_res); } +EXPORT_SYMBOL(dispc_mgr_set_timings); static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, u16 pck_div) @@ -3078,7 +2969,7 @@ unsigned long dispc_fclk_rate(void) switch (dss_get_dispc_clk_source()) { case OMAP_DSS_CLK_SRC_FCK: - r = clk_get_rate(dispc.dss_clk); + r = dss_get_dispc_clk_rate(); break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: dsidev = dsi_get_dsidev_from_id(0); @@ -3103,28 +2994,32 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISORo(channel)); + if (dss_mgr_is_lcd(channel)) { + l = dispc_read_reg(DISPC_DIVISORo(channel)); - lcd = FLD_GET(l, 23, 16); + lcd = FLD_GET(l, 23, 16); - switch (dss_get_lcd_clk_source(channel)) { - case OMAP_DSS_CLK_SRC_FCK: - r = clk_get_rate(dispc.dss_clk); - break; - case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: - dsidev = dsi_get_dsidev_from_id(0); - r = dsi_get_pll_hsdiv_dispc_rate(dsidev); - break; - case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: - dsidev = dsi_get_dsidev_from_id(1); - r = dsi_get_pll_hsdiv_dispc_rate(dsidev); - break; - default: - BUG(); - return 0; - } + switch (dss_get_lcd_clk_source(channel)) { + case OMAP_DSS_CLK_SRC_FCK: + r = dss_get_dispc_clk_rate(); + break; + case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: + dsidev = dsi_get_dsidev_from_id(0); + r = dsi_get_pll_hsdiv_dispc_rate(dsidev); + break; + case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: + dsidev = dsi_get_dsidev_from_id(1); + r = dsi_get_pll_hsdiv_dispc_rate(dsidev); + break; + default: + BUG(); + return 0; + } - return r / lcd; + return r / lcd; + } else { + return dispc_fclk_rate(); + } } unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) @@ -3174,21 +3069,28 @@ unsigned long dispc_core_clk_rate(void) static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) { - enum omap_channel channel = dispc_ovl_get_channel_out(plane); + enum omap_channel channel; + + if (plane == OMAP_DSS_WB) + return 0; + + channel = dispc_ovl_get_channel_out(plane); return dispc_mgr_pclk_rate(channel); } static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) { - enum omap_channel channel = dispc_ovl_get_channel_out(plane); + enum omap_channel channel; - if (dss_mgr_is_lcd(channel)) - return dispc_mgr_lclk_rate(channel); - else - return dispc_fclk_rate(); + if (plane == OMAP_DSS_WB) + return 0; + + channel = dispc_ovl_get_channel_out(plane); + return dispc_mgr_lclk_rate(channel); } + static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) { int lcd, pcd; @@ -3246,64 +3148,6 @@ void dispc_dump_clocks(struct seq_file *s) dispc_runtime_put(); } -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -void dispc_dump_irqs(struct seq_file *s) -{ - unsigned long flags; - struct dispc_irq_stats stats; - - spin_lock_irqsave(&dispc.irq_stats_lock, flags); - - stats = dispc.irq_stats; - memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats)); - dispc.irq_stats.last_reset = jiffies; - - spin_unlock_irqrestore(&dispc.irq_stats_lock, flags); - - seq_printf(s, "period %u ms\n", - jiffies_to_msecs(jiffies - stats.last_reset)); - - seq_printf(s, "irqs %d\n", stats.irq_count); -#define PIS(x) \ - seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); - - PIS(FRAMEDONE); - PIS(VSYNC); - PIS(EVSYNC_EVEN); - PIS(EVSYNC_ODD); - PIS(ACBIAS_COUNT_STAT); - PIS(PROG_LINE_NUM); - PIS(GFX_FIFO_UNDERFLOW); - PIS(GFX_END_WIN); - PIS(PAL_GAMMA_MASK); - PIS(OCP_ERR); - PIS(VID1_FIFO_UNDERFLOW); - PIS(VID1_END_WIN); - PIS(VID2_FIFO_UNDERFLOW); - PIS(VID2_END_WIN); - if (dss_feat_get_num_ovls() > 3) { - PIS(VID3_FIFO_UNDERFLOW); - PIS(VID3_END_WIN); - } - PIS(SYNC_LOST); - PIS(SYNC_LOST_DIGIT); - PIS(WAKEUP); - if (dss_has_feature(FEAT_MGR_LCD2)) { - PIS(FRAMEDONE2); - PIS(VSYNC2); - PIS(ACBIAS_COUNT_STAT2); - PIS(SYNC_LOST2); - } - if (dss_has_feature(FEAT_MGR_LCD3)) { - PIS(FRAMEDONE3); - PIS(VSYNC3); - PIS(ACBIAS_COUNT_STAT3); - PIS(SYNC_LOST3); - } -#undef PIS -} -#endif - static void dispc_dump_regs(struct seq_file *s) { int i, j; @@ -3353,7 +3197,7 @@ static void dispc_dump_regs(struct seq_file *s) #define DISPC_REG(i, name) name(i) #define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ - 48 - strlen(#r) - strlen(p_names[i]), " ", \ + (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \ dispc_read_reg(DISPC_REG(i, r))) p_names = mgr_names; @@ -3430,7 +3274,7 @@ static void dispc_dump_regs(struct seq_file *s) #define DISPC_REG(plane, name, i) name(plane, i) #define DUMPREG(plane, name, i) \ seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ - 46 - strlen(#name) - strlen(p_names[plane]), " ", \ + (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \ dispc_read_reg(DISPC_REG(plane, name, i))) /* Video pipeline coefficient registers */ @@ -3533,7 +3377,7 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, } void dispc_mgr_set_clock_div(enum omap_channel channel, - struct dispc_clock_info *cinfo) + const struct dispc_clock_info *cinfo) { DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); @@ -3557,403 +3401,34 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, return 0; } -/* dispc.irq_lock has to be locked by the caller */ -static void _omap_dispc_set_irqs(void) +u32 dispc_read_irqstatus(void) { - u32 mask; - u32 old_mask; - int i; - struct omap_dispc_isr_data *isr_data; - - mask = dispc.irq_error_mask; - - for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { - isr_data = &dispc.registered_isr[i]; - - if (isr_data->isr == NULL) - continue; - - mask |= isr_data->mask; - } - - old_mask = dispc_read_reg(DISPC_IRQENABLE); - /* clear the irqstatus for newly enabled irqs */ - dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask); - - dispc_write_reg(DISPC_IRQENABLE, mask); -} - -int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) -{ - int i; - int ret; - unsigned long flags; - struct omap_dispc_isr_data *isr_data; - - if (isr == NULL) - return -EINVAL; - - spin_lock_irqsave(&dispc.irq_lock, flags); - - /* check for duplicate entry */ - for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { - isr_data = &dispc.registered_isr[i]; - if (isr_data->isr == isr && isr_data->arg == arg && - isr_data->mask == mask) { - ret = -EINVAL; - goto err; - } - } - - isr_data = NULL; - ret = -EBUSY; - - for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { - isr_data = &dispc.registered_isr[i]; - - if (isr_data->isr != NULL) - continue; - - isr_data->isr = isr; - isr_data->arg = arg; - isr_data->mask = mask; - ret = 0; - - break; - } - - if (ret) - goto err; - - _omap_dispc_set_irqs(); - - spin_unlock_irqrestore(&dispc.irq_lock, flags); - - return 0; -err: - spin_unlock_irqrestore(&dispc.irq_lock, flags); - - return ret; + return dispc_read_reg(DISPC_IRQSTATUS); } -EXPORT_SYMBOL(omap_dispc_register_isr); +EXPORT_SYMBOL(dispc_read_irqstatus); -int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) +void dispc_clear_irqstatus(u32 mask) { - int i; - unsigned long flags; - int ret = -EINVAL; - struct omap_dispc_isr_data *isr_data; - - spin_lock_irqsave(&dispc.irq_lock, flags); - - for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { - isr_data = &dispc.registered_isr[i]; - if (isr_data->isr != isr || isr_data->arg != arg || - isr_data->mask != mask) - continue; - - /* found the correct isr */ - - isr_data->isr = NULL; - isr_data->arg = NULL; - isr_data->mask = 0; - - ret = 0; - break; - } - - if (ret == 0) - _omap_dispc_set_irqs(); - - spin_unlock_irqrestore(&dispc.irq_lock, flags); - - return ret; + dispc_write_reg(DISPC_IRQSTATUS, mask); } -EXPORT_SYMBOL(omap_dispc_unregister_isr); +EXPORT_SYMBOL(dispc_clear_irqstatus); -#ifdef DEBUG -static void print_irq_status(u32 status) +u32 dispc_read_irqenable(void) { - if ((status & dispc.irq_error_mask) == 0) - return; - - printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status); - -#define PIS(x) \ - if (status & DISPC_IRQ_##x) \ - printk(#x " "); - PIS(GFX_FIFO_UNDERFLOW); - PIS(OCP_ERR); - PIS(VID1_FIFO_UNDERFLOW); - PIS(VID2_FIFO_UNDERFLOW); - if (dss_feat_get_num_ovls() > 3) - PIS(VID3_FIFO_UNDERFLOW); - PIS(SYNC_LOST); - PIS(SYNC_LOST_DIGIT); - if (dss_has_feature(FEAT_MGR_LCD2)) - PIS(SYNC_LOST2); - if (dss_has_feature(FEAT_MGR_LCD3)) - PIS(SYNC_LOST3); -#undef PIS - - printk("\n"); + return dispc_read_reg(DISPC_IRQENABLE); } -#endif +EXPORT_SYMBOL(dispc_read_irqenable); -/* Called from dss.c. Note that we don't touch clocks here, - * but we presume they are on because we got an IRQ. However, - * an irq handler may turn the clocks off, so we may not have - * clock later in the function. */ -static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) +void dispc_write_irqenable(u32 mask) { - int i; - u32 irqstatus, irqenable; - u32 handledirqs = 0; - u32 unhandled_errors; - struct omap_dispc_isr_data *isr_data; - struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; - - spin_lock(&dispc.irq_lock); - - irqstatus = dispc_read_reg(DISPC_IRQSTATUS); - irqenable = dispc_read_reg(DISPC_IRQENABLE); - - /* IRQ is not for us */ - if (!(irqstatus & irqenable)) { - spin_unlock(&dispc.irq_lock); - return IRQ_NONE; - } - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS - spin_lock(&dispc.irq_stats_lock); - dispc.irq_stats.irq_count++; - dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs); - spin_unlock(&dispc.irq_stats_lock); -#endif - -#ifdef DEBUG - if (dss_debug) - print_irq_status(irqstatus); -#endif - /* Ack the interrupt. Do it here before clocks are possibly turned - * off */ - dispc_write_reg(DISPC_IRQSTATUS, irqstatus); - /* flush posted write */ - dispc_read_reg(DISPC_IRQSTATUS); - - /* make a copy and unlock, so that isrs can unregister - * themselves */ - memcpy(registered_isr, dispc.registered_isr, - sizeof(registered_isr)); - - spin_unlock(&dispc.irq_lock); - - for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { - isr_data = ®istered_isr[i]; - - if (!isr_data->isr) - continue; - - if (isr_data->mask & irqstatus) { - isr_data->isr(isr_data->arg, irqstatus); - handledirqs |= isr_data->mask; - } - } - - spin_lock(&dispc.irq_lock); - - unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask; - - if (unhandled_errors) { - dispc.error_irqs |= unhandled_errors; - - dispc.irq_error_mask &= ~unhandled_errors; - _omap_dispc_set_irqs(); - - schedule_work(&dispc.error_work); - } - - spin_unlock(&dispc.irq_lock); - - return IRQ_HANDLED; -} - -static void dispc_error_worker(struct work_struct *work) -{ - int i; - u32 errors; - unsigned long flags; - static const unsigned fifo_underflow_bits[] = { - DISPC_IRQ_GFX_FIFO_UNDERFLOW, - DISPC_IRQ_VID1_FIFO_UNDERFLOW, - DISPC_IRQ_VID2_FIFO_UNDERFLOW, - DISPC_IRQ_VID3_FIFO_UNDERFLOW, - }; - - spin_lock_irqsave(&dispc.irq_lock, flags); - errors = dispc.error_irqs; - dispc.error_irqs = 0; - spin_unlock_irqrestore(&dispc.irq_lock, flags); - - dispc_runtime_get(); - - for (i = 0; i < omap_dss_get_num_overlays(); ++i) { - struct omap_overlay *ovl; - unsigned bit; - - ovl = omap_dss_get_overlay(i); - bit = fifo_underflow_bits[i]; - - if (bit & errors) { - DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", - ovl->name); - dispc_ovl_enable(ovl->id, false); - dispc_mgr_go(ovl->manager->id); - msleep(50); - } - } - - for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { - struct omap_overlay_manager *mgr; - unsigned bit; - - mgr = omap_dss_get_overlay_manager(i); - bit = mgr_desc[i].sync_lost_irq; - - if (bit & errors) { - struct omap_dss_device *dssdev = mgr->get_device(mgr); - bool enable; - - DSSERR("SYNC_LOST on channel %s, restarting the output " - "with video overlays disabled\n", - mgr->name); - - enable = dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; - dssdev->driver->disable(dssdev); - - for (i = 0; i < omap_dss_get_num_overlays(); ++i) { - struct omap_overlay *ovl; - ovl = omap_dss_get_overlay(i); - - if (ovl->id != OMAP_DSS_GFX && - ovl->manager == mgr) - dispc_ovl_enable(ovl->id, false); - } - - dispc_mgr_go(mgr->id); - msleep(50); - - if (enable) - dssdev->driver->enable(dssdev); - } - } - - if (errors & DISPC_IRQ_OCP_ERR) { - DSSERR("OCP_ERR\n"); - for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { - struct omap_overlay_manager *mgr; - struct omap_dss_device *dssdev; + u32 old_mask = dispc_read_reg(DISPC_IRQENABLE); - mgr = omap_dss_get_overlay_manager(i); - dssdev = mgr->get_device(mgr); - - if (dssdev && dssdev->driver) - dssdev->driver->disable(dssdev); - } - } - - spin_lock_irqsave(&dispc.irq_lock, flags); - dispc.irq_error_mask |= errors; - _omap_dispc_set_irqs(); - spin_unlock_irqrestore(&dispc.irq_lock, flags); - - dispc_runtime_put(); -} - -int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout) -{ - void dispc_irq_wait_handler(void *data, u32 mask) - { - complete((struct completion *)data); - } - - int r; - DECLARE_COMPLETION_ONSTACK(completion); - - r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, - irqmask); - - if (r) - return r; - - timeout = wait_for_completion_timeout(&completion, timeout); - - omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); - - if (timeout == 0) - return -ETIMEDOUT; - - if (timeout == -ERESTARTSYS) - return -ERESTARTSYS; - - return 0; -} - -int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, - unsigned long timeout) -{ - void dispc_irq_wait_handler(void *data, u32 mask) - { - complete((struct completion *)data); - } - - int r; - DECLARE_COMPLETION_ONSTACK(completion); - - r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, - irqmask); - - if (r) - return r; - - timeout = wait_for_completion_interruptible_timeout(&completion, - timeout); - - omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); - - if (timeout == 0) - return -ETIMEDOUT; - - if (timeout == -ERESTARTSYS) - return -ERESTARTSYS; - - return 0; -} - -static void _omap_dispc_initialize_irq(void) -{ - unsigned long flags; - - spin_lock_irqsave(&dispc.irq_lock, flags); - - memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); - - dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; - if (dss_has_feature(FEAT_MGR_LCD2)) - dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; - if (dss_has_feature(FEAT_MGR_LCD3)) - dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST3; - if (dss_feat_get_num_ovls() > 3) - dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; - - /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, - * so clear it */ - dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS)); - - _omap_dispc_set_irqs(); + /* clear the irqstatus for newly enabled irqs */ + dispc_clear_irqstatus((mask ^ old_mask) & mask); - spin_unlock_irqrestore(&dispc.irq_lock, flags); + dispc_write_reg(DISPC_IRQENABLE, mask); } +EXPORT_SYMBOL(dispc_write_irqenable); void dispc_enable_sidle(void) { @@ -4000,9 +3475,14 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = { .sw_max = 64, .vp_max = 255, .hp_max = 256, + .mgr_width_start = 10, + .mgr_height_start = 26, + .mgr_width_max = 2048, + .mgr_height_max = 2048, .calc_scaling = dispc_ovl_calc_scaling_24xx, .calc_core_clk = calc_core_clk_24xx, .num_fifos = 3, + .no_framedone_tv = true, }; static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { @@ -4012,9 +3492,14 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { .sw_max = 64, .vp_max = 255, .hp_max = 256, + .mgr_width_start = 10, + .mgr_height_start = 26, + .mgr_width_max = 2048, + .mgr_height_max = 2048, .calc_scaling = dispc_ovl_calc_scaling_34xx, .calc_core_clk = calc_core_clk_34xx, .num_fifos = 3, + .no_framedone_tv = true, }; static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { @@ -4024,9 +3509,14 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { .sw_max = 256, .vp_max = 4095, .hp_max = 4096, + .mgr_width_start = 10, + .mgr_height_start = 26, + .mgr_width_max = 2048, + .mgr_height_max = 2048, .calc_scaling = dispc_ovl_calc_scaling_34xx, .calc_core_clk = calc_core_clk_34xx, .num_fifos = 3, + .no_framedone_tv = true, }; static const struct dispc_features omap44xx_dispc_feats __initconst = { @@ -4036,35 +3526,70 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = { .sw_max = 256, .vp_max = 4095, .hp_max = 4096, + .mgr_width_start = 10, + .mgr_height_start = 26, + .mgr_width_max = 2048, + .mgr_height_max = 2048, + .calc_scaling = dispc_ovl_calc_scaling_44xx, + .calc_core_clk = calc_core_clk_44xx, + .num_fifos = 5, + .gfx_fifo_workaround = true, +}; + +static const struct dispc_features omap54xx_dispc_feats __initconst = { + .sw_start = 7, + .fp_start = 19, + .bp_start = 31, + .sw_max = 256, + .vp_max = 4095, + .hp_max = 4096, + .mgr_width_start = 11, + .mgr_height_start = 27, + .mgr_width_max = 4096, + .mgr_height_max = 4096, .calc_scaling = dispc_ovl_calc_scaling_44xx, .calc_core_clk = calc_core_clk_44xx, .num_fifos = 5, .gfx_fifo_workaround = true, }; -static int __init dispc_init_features(struct device *dev) +static int __init dispc_init_features(struct platform_device *pdev) { const struct dispc_features *src; struct dispc_features *dst; - dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); if (!dst) { - dev_err(dev, "Failed to allocate DISPC Features\n"); + dev_err(&pdev->dev, "Failed to allocate DISPC Features\n"); return -ENOMEM; } - if (cpu_is_omap24xx()) { + switch (omapdss_get_version()) { + case OMAPDSS_VER_OMAP24xx: src = &omap24xx_dispc_feats; - } else if (cpu_is_omap34xx()) { - if (omap_rev() < OMAP3430_REV_ES3_0) - src = &omap34xx_rev1_0_dispc_feats; - else - src = &omap34xx_rev3_0_dispc_feats; - } else if (cpu_is_omap44xx()) { - src = &omap44xx_dispc_feats; - } else if (soc_is_omap54xx()) { + break; + + case OMAPDSS_VER_OMAP34xx_ES1: + src = &omap34xx_rev1_0_dispc_feats; + break; + + case OMAPDSS_VER_OMAP34xx_ES3: + case OMAPDSS_VER_OMAP3630: + case OMAPDSS_VER_AM35xx: + src = &omap34xx_rev3_0_dispc_feats; + break; + + case OMAPDSS_VER_OMAP4430_ES1: + case OMAPDSS_VER_OMAP4430_ES2: + case OMAPDSS_VER_OMAP4: src = &omap44xx_dispc_feats; - } else { + break; + + case OMAPDSS_VER_OMAP5: + src = &omap54xx_dispc_feats; + break; + + default: return -ENODEV; } @@ -4074,29 +3599,32 @@ static int __init dispc_init_features(struct device *dev) return 0; } +int dispc_request_irq(irq_handler_t handler, void *dev_id) +{ + return devm_request_irq(&dispc.pdev->dev, dispc.irq, handler, + IRQF_SHARED, "OMAP DISPC", dev_id); +} +EXPORT_SYMBOL(dispc_request_irq); + +void dispc_free_irq(void *dev_id) +{ + devm_free_irq(&dispc.pdev->dev, dispc.irq, dev_id); +} +EXPORT_SYMBOL(dispc_free_irq); + /* DISPC HW IP initialisation */ static int __init omap_dispchw_probe(struct platform_device *pdev) { u32 rev; int r = 0; struct resource *dispc_mem; - struct clk *clk; dispc.pdev = pdev; - r = dispc_init_features(&dispc.pdev->dev); + r = dispc_init_features(dispc.pdev); if (r) return r; - spin_lock_init(&dispc.irq_lock); - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS - spin_lock_init(&dispc.irq_stats_lock); - dispc.irq_stats.last_reset = jiffies; -#endif - - INIT_WORK(&dispc.error_work, dispc_error_worker); - dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); if (!dispc_mem) { DSSERR("can't get IORESOURCE_MEM DISPC\n"); @@ -4116,22 +3644,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) return -ENODEV; } - r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler, - IRQF_SHARED, "OMAP DISPC", dispc.pdev); - if (r < 0) { - DSSERR("request_irq failed\n"); - return r; - } - - clk = clk_get(&pdev->dev, "fck"); - if (IS_ERR(clk)) { - DSSERR("can't get fck\n"); - r = PTR_ERR(clk); - return r; - } - - dispc.dss_clk = clk; - pm_runtime_enable(&pdev->dev); r = dispc_runtime_get(); @@ -4140,8 +3652,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) _omap_dispc_initial_config(); - _omap_dispc_initialize_irq(); - rev = dispc_read_reg(DISPC_REVISION); dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); @@ -4150,14 +3660,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) dss_debugfs_create_file("dispc", dispc_dump_regs); -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS - dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); -#endif return 0; err_runtime_get: pm_runtime_disable(&pdev->dev); - clk_put(dispc.dss_clk); return r; } @@ -4165,8 +3671,6 @@ static int __exit omap_dispchw_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - clk_put(dispc.dss_clk); - return 0; } diff --git a/drivers/video/omap2/dss/display-sysfs.c b/drivers/video/omap2/dss/display-sysfs.c new file mode 100644 index 00000000000..18211a9ab35 --- /dev/null +++ b/drivers/video/omap2/dss/display-sysfs.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * Some code and ideas taken from drivers/video/omap/ driver + * by Imre Deak. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "DISPLAY" + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> + +#include <video/omapdss.h> +#include "dss.h" +#include "dss_features.h" + +static ssize_t display_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED; + + return snprintf(buf, PAGE_SIZE, "%d\n", enabled); +} + +static ssize_t display_enabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + int r; + bool enabled; + + r = strtobool(buf, &enabled); + if (r) + return r; + + if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { + if (enabled) { + r = dssdev->driver->enable(dssdev); + if (r) + return r; + } else { + dssdev->driver->disable(dssdev); + } + } + + return size; +} + +static ssize_t display_tear_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", + dssdev->driver->get_te ? + dssdev->driver->get_te(dssdev) : 0); +} + +static ssize_t display_tear_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + int r; + bool te; + + if (!dssdev->driver->enable_te || !dssdev->driver->get_te) + return -ENOENT; + + r = strtobool(buf, &te); + if (r) + return r; + + r = dssdev->driver->enable_te(dssdev, te); + if (r) + return r; + + return size; +} + +static ssize_t display_timings_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_video_timings t; + + if (!dssdev->driver->get_timings) + return -ENOENT; + + dssdev->driver->get_timings(dssdev, &t); + + return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", + t.pixel_clock, + t.x_res, t.hfp, t.hbp, t.hsw, + t.y_res, t.vfp, t.vbp, t.vsw); +} + +static ssize_t display_timings_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_video_timings t = dssdev->panel.timings; + int r, found; + + if (!dssdev->driver->set_timings || !dssdev->driver->check_timings) + return -ENOENT; + + found = 0; +#ifdef CONFIG_OMAP2_DSS_VENC + if (strncmp("pal", buf, 3) == 0) { + t = omap_dss_pal_timings; + found = 1; + } else if (strncmp("ntsc", buf, 4) == 0) { + t = omap_dss_ntsc_timings; + found = 1; + } +#endif + if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu", + &t.pixel_clock, + &t.x_res, &t.hfp, &t.hbp, &t.hsw, + &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) + return -EINVAL; + + r = dssdev->driver->check_timings(dssdev, &t); + if (r) + return r; + + dssdev->driver->disable(dssdev); + dssdev->driver->set_timings(dssdev, &t); + r = dssdev->driver->enable(dssdev); + if (r) + return r; + + return size; +} + +static ssize_t display_rotate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + int rotate; + if (!dssdev->driver->get_rotate) + return -ENOENT; + rotate = dssdev->driver->get_rotate(dssdev); + return snprintf(buf, PAGE_SIZE, "%u\n", rotate); +} + +static ssize_t display_rotate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + int rot, r; + + if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) + return -ENOENT; + + r = kstrtoint(buf, 0, &rot); + if (r) + return r; + + r = dssdev->driver->set_rotate(dssdev, rot); + if (r) + return r; + + return size; +} + +static ssize_t display_mirror_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + int mirror; + if (!dssdev->driver->get_mirror) + return -ENOENT; + mirror = dssdev->driver->get_mirror(dssdev); + return snprintf(buf, PAGE_SIZE, "%u\n", mirror); +} + +static ssize_t display_mirror_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + int r; + bool mirror; + + if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) + return -ENOENT; + + r = strtobool(buf, &mirror); + if (r) + return r; + + r = dssdev->driver->set_mirror(dssdev, mirror); + if (r) + return r; + + return size; +} + +static ssize_t display_wss_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + unsigned int wss; + + if (!dssdev->driver->get_wss) + return -ENOENT; + + wss = dssdev->driver->get_wss(dssdev); + + return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss); +} + +static ssize_t display_wss_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + u32 wss; + int r; + + if (!dssdev->driver->get_wss || !dssdev->driver->set_wss) + return -ENOENT; + + r = kstrtou32(buf, 0, &wss); + if (r) + return r; + + if (wss > 0xfffff) + return -EINVAL; + + r = dssdev->driver->set_wss(dssdev, wss); + if (r) + return r; + + return size; +} + +static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, + display_enabled_show, display_enabled_store); +static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, + display_tear_show, display_tear_store); +static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, + display_timings_show, display_timings_store); +static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR, + display_rotate_show, display_rotate_store); +static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, + display_mirror_show, display_mirror_store); +static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, + display_wss_show, display_wss_store); + +static struct device_attribute *display_sysfs_attrs[] = { + &dev_attr_enabled, + &dev_attr_tear_elim, + &dev_attr_timings, + &dev_attr_rotate, + &dev_attr_mirror, + &dev_attr_wss, + NULL +}; + +int display_init_sysfs(struct platform_device *pdev, + struct omap_dss_device *dssdev) +{ + struct device_attribute *attr; + int i, r; + + /* create device sysfs files */ + i = 0; + while ((attr = display_sysfs_attrs[i++]) != NULL) { + r = device_create_file(&dssdev->dev, attr); + if (r) { + for (i = i - 2; i >= 0; i--) { + attr = display_sysfs_attrs[i]; + device_remove_file(&dssdev->dev, attr); + } + + DSSERR("failed to create sysfs file\n"); + return r; + } + } + + /* create display? sysfs links */ + r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, + dev_name(&dssdev->dev)); + if (r) { + while ((attr = display_sysfs_attrs[i++]) != NULL) + device_remove_file(&dssdev->dev, attr); + + DSSERR("failed to create sysfs display link\n"); + return r; + } + + return 0; +} + +void display_uninit_sysfs(struct platform_device *pdev, + struct omap_dss_device *dssdev) +{ + struct device_attribute *attr; + int i = 0; + + sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); + + while ((attr = display_sysfs_attrs[i++]) != NULL) + device_remove_file(&dssdev->dev, attr); +} diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index ccf8550fafd..0aa8ad8f966 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -31,250 +31,6 @@ #include "dss.h" #include "dss_features.h" -static ssize_t display_enabled_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED; - - return snprintf(buf, PAGE_SIZE, "%d\n", enabled); -} - -static ssize_t display_enabled_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - int r; - bool enabled; - - r = strtobool(buf, &enabled); - if (r) - return r; - - if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { - if (enabled) { - r = dssdev->driver->enable(dssdev); - if (r) - return r; - } else { - dssdev->driver->disable(dssdev); - } - } - - return size; -} - -static ssize_t display_tear_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", - dssdev->driver->get_te ? - dssdev->driver->get_te(dssdev) : 0); -} - -static ssize_t display_tear_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - int r; - bool te; - - if (!dssdev->driver->enable_te || !dssdev->driver->get_te) - return -ENOENT; - - r = strtobool(buf, &te); - if (r) - return r; - - r = dssdev->driver->enable_te(dssdev, te); - if (r) - return r; - - return size; -} - -static ssize_t display_timings_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - struct omap_video_timings t; - - if (!dssdev->driver->get_timings) - return -ENOENT; - - dssdev->driver->get_timings(dssdev, &t); - - return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", - t.pixel_clock, - t.x_res, t.hfp, t.hbp, t.hsw, - t.y_res, t.vfp, t.vbp, t.vsw); -} - -static ssize_t display_timings_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - struct omap_video_timings t = dssdev->panel.timings; - int r, found; - - if (!dssdev->driver->set_timings || !dssdev->driver->check_timings) - return -ENOENT; - - found = 0; -#ifdef CONFIG_OMAP2_DSS_VENC - if (strncmp("pal", buf, 3) == 0) { - t = omap_dss_pal_timings; - found = 1; - } else if (strncmp("ntsc", buf, 4) == 0) { - t = omap_dss_ntsc_timings; - found = 1; - } -#endif - if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu", - &t.pixel_clock, - &t.x_res, &t.hfp, &t.hbp, &t.hsw, - &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) - return -EINVAL; - - r = dssdev->driver->check_timings(dssdev, &t); - if (r) - return r; - - dssdev->driver->disable(dssdev); - dssdev->driver->set_timings(dssdev, &t); - r = dssdev->driver->enable(dssdev); - if (r) - return r; - - return size; -} - -static ssize_t display_rotate_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - int rotate; - if (!dssdev->driver->get_rotate) - return -ENOENT; - rotate = dssdev->driver->get_rotate(dssdev); - return snprintf(buf, PAGE_SIZE, "%u\n", rotate); -} - -static ssize_t display_rotate_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - int rot, r; - - if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) - return -ENOENT; - - r = kstrtoint(buf, 0, &rot); - if (r) - return r; - - r = dssdev->driver->set_rotate(dssdev, rot); - if (r) - return r; - - return size; -} - -static ssize_t display_mirror_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - int mirror; - if (!dssdev->driver->get_mirror) - return -ENOENT; - mirror = dssdev->driver->get_mirror(dssdev); - return snprintf(buf, PAGE_SIZE, "%u\n", mirror); -} - -static ssize_t display_mirror_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - int r; - bool mirror; - - if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) - return -ENOENT; - - r = strtobool(buf, &mirror); - if (r) - return r; - - r = dssdev->driver->set_mirror(dssdev, mirror); - if (r) - return r; - - return size; -} - -static ssize_t display_wss_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - unsigned int wss; - - if (!dssdev->driver->get_wss) - return -ENOENT; - - wss = dssdev->driver->get_wss(dssdev); - - return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss); -} - -static ssize_t display_wss_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - u32 wss; - int r; - - if (!dssdev->driver->get_wss || !dssdev->driver->set_wss) - return -ENOENT; - - r = kstrtou32(buf, 0, &wss); - if (r) - return r; - - if (wss > 0xfffff) - return -EINVAL; - - r = dssdev->driver->set_wss(dssdev, wss); - if (r) - return r; - - return size; -} - -static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, - display_enabled_show, display_enabled_store); -static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, - display_tear_show, display_tear_store); -static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, - display_timings_show, display_timings_store); -static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR, - display_rotate_show, display_rotate_store); -static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, - display_mirror_show, display_mirror_store); -static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, - display_wss_show, display_wss_store); - -static struct device_attribute *display_sysfs_attrs[] = { - &dev_attr_enabled, - &dev_attr_tear_elim, - &dev_attr_timings, - &dev_attr_rotate, - &dev_attr_mirror, - &dev_attr_wss, - NULL -}; - void omapdss_default_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres) { @@ -320,136 +76,8 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_default_get_timings); -/* - * Connect dssdev to a manager if the manager is free or if force is specified. - * Connect all overlays to that manager if they are free or if force is - * specified. - */ -static int dss_init_connections(struct omap_dss_device *dssdev, bool force) -{ - struct omap_dss_output *out; - struct omap_overlay_manager *mgr; - int i, r; - - out = omapdss_get_output_from_dssdev(dssdev); - - WARN_ON(dssdev->output); - WARN_ON(out->device); - - r = omapdss_output_set_device(out, dssdev); - if (r) { - DSSERR("failed to connect output to new device\n"); - return r; - } - - mgr = omap_dss_get_overlay_manager(dssdev->channel); - - if (mgr->output && !force) - return 0; - - if (mgr->output) - mgr->unset_output(mgr); - - r = mgr->set_output(mgr, out); - if (r) { - DSSERR("failed to connect manager to output of new device\n"); - - /* remove the output-device connection we just made */ - omapdss_output_unset_device(out); - return r; - } - - for (i = 0; i < omap_dss_get_num_overlays(); ++i) { - struct omap_overlay *ovl = omap_dss_get_overlay(i); - - if (!ovl->manager || force) { - if (ovl->manager) - ovl->unset_manager(ovl); - - r = ovl->set_manager(ovl, mgr); - if (r) { - DSSERR("failed to set initial overlay\n"); - return r; - } - } - } - - return 0; -} - -static void dss_uninit_connections(struct omap_dss_device *dssdev) -{ - if (dssdev->output) { - struct omap_overlay_manager *mgr = dssdev->output->manager; - - if (mgr) - mgr->unset_output(mgr); - - omapdss_output_unset_device(dssdev->output); - } -} - -int dss_init_device(struct platform_device *pdev, - struct omap_dss_device *dssdev) -{ - struct device_attribute *attr; - int i, r; - const char *def_disp_name = dss_get_default_display_name(); - bool force; - - force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0; - dss_init_connections(dssdev, force); - - /* create device sysfs files */ - i = 0; - while ((attr = display_sysfs_attrs[i++]) != NULL) { - r = device_create_file(&dssdev->dev, attr); - if (r) { - for (i = i - 2; i >= 0; i--) { - attr = display_sysfs_attrs[i]; - device_remove_file(&dssdev->dev, attr); - } - - dss_uninit_connections(dssdev); - - DSSERR("failed to create sysfs file\n"); - return r; - } - } - - /* create display? sysfs links */ - r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, - dev_name(&dssdev->dev)); - if (r) { - while ((attr = display_sysfs_attrs[i++]) != NULL) - device_remove_file(&dssdev->dev, attr); - - dss_uninit_connections(dssdev); - - DSSERR("failed to create sysfs display link\n"); - return r; - } - - return 0; -} - -void dss_uninit_device(struct platform_device *pdev, - struct omap_dss_device *dssdev) -{ - struct device_attribute *attr; - int i = 0; - - sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); - - while ((attr = display_sysfs_attrs[i++]) != NULL) - device_remove_file(&dssdev->dev, attr); - - dss_uninit_connections(dssdev); -} - static int dss_suspend_device(struct device *dev, void *data) { - int r; struct omap_dss_device *dssdev = to_dss_device(dev); if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { @@ -457,15 +85,7 @@ static int dss_suspend_device(struct device *dev, void *data) return 0; } - if (!dssdev->driver->suspend) { - DSSERR("display '%s' doesn't implement suspend\n", - dssdev->name); - return -ENOSYS; - } - - r = dssdev->driver->suspend(dssdev); - if (r) - return r; + dssdev->driver->disable(dssdev); dssdev->activate_after_resume = true; @@ -492,8 +112,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->driver->resume) { - r = dssdev->driver->resume(dssdev); + if (dssdev->activate_after_resume) { + r = dssdev->driver->enable(dssdev); if (r) return r; } diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 56748cf8760..4af136a04e5 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -49,34 +49,53 @@ static struct { struct omap_dss_output output; } dpi; -static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) +static struct platform_device *dpi_get_dsidev(enum omap_channel channel) { - int dsi_module; - - dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1; + /* + * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL + * would also be used for DISPC fclk. Meaning, when the DPI output is + * disabled, DISPC clock will be disabled, and TV out will stop. + */ + switch (omapdss_get_version()) { + case OMAPDSS_VER_OMAP24xx: + case OMAPDSS_VER_OMAP34xx_ES1: + case OMAPDSS_VER_OMAP34xx_ES3: + case OMAPDSS_VER_OMAP3630: + case OMAPDSS_VER_AM35xx: + return NULL; + default: + break; + } - return dsi_get_dsidev_from_id(dsi_module); + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return dsi_get_dsidev_from_id(0); + case OMAP_DSS_CHANNEL_LCD2: + return dsi_get_dsidev_from_id(1); + default: + return NULL; + } } -static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev) +static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) { - if (dssdev->clocks.dispc.dispc_fclk_src == - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || - dssdev->clocks.dispc.dispc_fclk_src == - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC || - dssdev->clocks.dispc.channel.lcd_clk_src == - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || - dssdev->clocks.dispc.channel.lcd_clk_src == - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC) - return true; - else - return false; + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC; + case OMAP_DSS_CHANNEL_LCD2: + return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; + default: + /* this shouldn't happen */ + WARN_ON(1); + return OMAP_DSS_CLK_SRC_FCK; + } } static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, unsigned long pck_req, unsigned long *fck, int *lck_div, int *pck_div) { + struct omap_overlay_manager *mgr = dssdev->output->manager; struct dsi_clock_info dsi_cinfo; struct dispc_clock_info dispc_cinfo; int r; @@ -90,7 +109,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, if (r) return r; - dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); + dss_select_lcd_clk_source(mgr->id, + dpi_get_alt_clk_src(mgr->id)); dpi.mgr_config.clock_info = dispc_cinfo; @@ -135,7 +155,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) unsigned long pck; int r = 0; - if (dpi_use_dsi_pll(dssdev)) + if (dpi.dsidev) r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, &lck_div, &pck_div); else @@ -214,7 +234,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_src_sel; - if (dpi_use_dsi_pll(dssdev)) { + if (dpi.dsidev) { r = dsi_runtime_get(dpi.dsidev); if (r) goto err_get_dsi; @@ -242,10 +262,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) err_mgr_enable: err_set_mode: - if (dpi_use_dsi_pll(dssdev)) + if (dpi.dsidev) dsi_pll_uninit(dpi.dsidev, true); err_dsi_pll_init: - if (dpi_use_dsi_pll(dssdev)) + if (dpi.dsidev) dsi_runtime_put(dpi.dsidev); err_get_dsi: err_src_sel: @@ -271,8 +291,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) dss_mgr_disable(mgr); - if (dpi_use_dsi_pll(dssdev)) { - dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); + if (dpi.dsidev) { + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); dsi_pll_uninit(dpi.dsidev, true); dsi_runtime_put(dpi.dsidev); } @@ -311,13 +331,13 @@ int dpi_check_timings(struct omap_dss_device *dssdev, unsigned long pck; struct dispc_clock_info dispc_cinfo; - if (dss_mgr_check_timings(mgr, timings)) + if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) return -EINVAL; if (timings->pixel_clock == 0) return -EINVAL; - if (dpi_use_dsi_pll(dssdev)) { + if (dpi.dsidev) { struct dsi_clock_info dsi_cinfo; r = dsi_pll_calc_clock_div_pck(dpi.dsidev, timings->pixel_clock * 1000, @@ -359,8 +379,32 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) } EXPORT_SYMBOL(omapdss_dpi_set_data_lines); +static int __init dpi_verify_dsi_pll(struct platform_device *dsidev) +{ + int r; + + /* do initial setup with the PLL to see if it is operational */ + + r = dsi_runtime_get(dsidev); + if (r) + return r; + + r = dsi_pll_init(dsidev, 0, 1); + if (r) { + dsi_runtime_put(dsidev); + return r; + } + + dsi_pll_uninit(dsidev, true); + dsi_runtime_put(dsidev); + + return 0; +} + static int __init dpi_init_display(struct omap_dss_device *dssdev) { + struct platform_device *dsidev; + DSSDBG("init_display\n"); if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && @@ -377,19 +421,30 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) dpi.vdds_dsi_reg = vdds_dsi; } - if (dpi_use_dsi_pll(dssdev)) { - enum omap_dss_clk_source dispc_fclk_src = - dssdev->clocks.dispc.dispc_fclk_src; - dpi.dsidev = dpi_get_dsidev(dispc_fclk_src); + /* + * XXX We shouldn't need dssdev->channel for this. The dsi pll clock + * source for DPI is SoC integration detail, not something that should + * be configured in the dssdev + */ + dsidev = dpi_get_dsidev(dssdev->channel); + + if (dsidev && dpi_verify_dsi_pll(dsidev)) { + dsidev = NULL; + DSSWARN("DSI PLL not operational\n"); } + if (dsidev) + DSSDBG("using DSI PLL for DPI clock\n"); + + dpi.dsidev = dsidev; + return 0; } static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - const char *def_disp_name = dss_get_default_display_name(); + const char *def_disp_name = omapdss_get_default_display_name(); struct omap_dss_device *def_dssdev; int i; @@ -438,9 +493,18 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev) return; } + r = omapdss_output_set_device(&dpi.output, dssdev); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dssdev->name); + dss_put_device(dssdev); + return; + } + r = dss_add_device(dssdev); if (r) { DSSERR("device %s register failed: %d\n", dssdev->name, r); + omapdss_output_unset_device(&dpi.output); dss_put_device(dssdev); return; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index bee92846cfa..28d41d16b7b 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -45,7 +45,6 @@ #include "dss.h" #include "dss_features.h" -/*#define VERBOSE_IRQ*/ #define DSI_CATCH_MISSING_TE struct dsi_reg { u16 idx; }; @@ -535,42 +534,38 @@ static inline void dsi_perf_show(struct platform_device *dsidev, } #endif +static int verbose_irq; + static void print_irq_status(u32 status) { if (status == 0) return; -#ifndef VERBOSE_IRQ - if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0) + if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0) return; -#endif - printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status); -#define PIS(x) \ - if (status & DSI_IRQ_##x) \ - printk(#x " "); -#ifdef VERBOSE_IRQ - PIS(VC0); - PIS(VC1); - PIS(VC2); - PIS(VC3); -#endif - PIS(WAKEUP); - PIS(RESYNC); - PIS(PLL_LOCK); - PIS(PLL_UNLOCK); - PIS(PLL_RECALL); - PIS(COMPLEXIO_ERR); - PIS(HS_TX_TIMEOUT); - PIS(LP_RX_TIMEOUT); - PIS(TE_TRIGGER); - PIS(ACK_TRIGGER); - PIS(SYNC_LOST); - PIS(LDO_POWER_GOOD); - PIS(TA_TIMEOUT); +#define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : "" + + pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + status, + verbose_irq ? PIS(VC0) : "", + verbose_irq ? PIS(VC1) : "", + verbose_irq ? PIS(VC2) : "", + verbose_irq ? PIS(VC3) : "", + PIS(WAKEUP), + PIS(RESYNC), + PIS(PLL_LOCK), + PIS(PLL_UNLOCK), + PIS(PLL_RECALL), + PIS(COMPLEXIO_ERR), + PIS(HS_TX_TIMEOUT), + PIS(LP_RX_TIMEOUT), + PIS(TE_TRIGGER), + PIS(ACK_TRIGGER), + PIS(SYNC_LOST), + PIS(LDO_POWER_GOOD), + PIS(TA_TIMEOUT)); #undef PIS - - printk("\n"); } static void print_irq_status_vc(int channel, u32 status) @@ -578,28 +573,24 @@ static void print_irq_status_vc(int channel, u32 status) if (status == 0) return; -#ifndef VERBOSE_IRQ - if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0) + if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0) return; -#endif - printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status); -#define PIS(x) \ - if (status & DSI_VC_IRQ_##x) \ - printk(#x " "); - PIS(CS); - PIS(ECC_CORR); -#ifdef VERBOSE_IRQ - PIS(PACKET_SENT); -#endif - PIS(FIFO_TX_OVF); - PIS(FIFO_RX_OVF); - PIS(BTA); - PIS(ECC_NO_CORR); - PIS(FIFO_TX_UDF); - PIS(PP_BUSY_CHANGE); +#define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : "" + + pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n", + channel, + status, + PIS(CS), + PIS(ECC_CORR), + PIS(ECC_NO_CORR), + verbose_irq ? PIS(PACKET_SENT) : "", + PIS(BTA), + PIS(FIFO_TX_OVF), + PIS(FIFO_RX_OVF), + PIS(FIFO_TX_UDF), + PIS(PP_BUSY_CHANGE)); #undef PIS - printk("\n"); } static void print_irq_status_cio(u32 status) @@ -607,34 +598,31 @@ static void print_irq_status_cio(u32 status) if (status == 0) return; - printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status); - -#define PIS(x) \ - if (status & DSI_CIO_IRQ_##x) \ - printk(#x " "); - PIS(ERRSYNCESC1); - PIS(ERRSYNCESC2); - PIS(ERRSYNCESC3); - PIS(ERRESC1); - PIS(ERRESC2); - PIS(ERRESC3); - PIS(ERRCONTROL1); - PIS(ERRCONTROL2); - PIS(ERRCONTROL3); - PIS(STATEULPS1); - PIS(STATEULPS2); - PIS(STATEULPS3); - PIS(ERRCONTENTIONLP0_1); - PIS(ERRCONTENTIONLP1_1); - PIS(ERRCONTENTIONLP0_2); - PIS(ERRCONTENTIONLP1_2); - PIS(ERRCONTENTIONLP0_3); - PIS(ERRCONTENTIONLP1_3); - PIS(ULPSACTIVENOT_ALL0); - PIS(ULPSACTIVENOT_ALL1); +#define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : "" + + pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + status, + PIS(ERRSYNCESC1), + PIS(ERRSYNCESC2), + PIS(ERRSYNCESC3), + PIS(ERRESC1), + PIS(ERRESC2), + PIS(ERRESC3), + PIS(ERRCONTROL1), + PIS(ERRCONTROL2), + PIS(ERRCONTROL3), + PIS(STATEULPS1), + PIS(STATEULPS2), + PIS(STATEULPS3), + PIS(ERRCONTENTIONLP0_1), + PIS(ERRCONTENTIONLP1_1), + PIS(ERRCONTENTIONLP0_2), + PIS(ERRCONTENTIONLP1_2), + PIS(ERRCONTENTIONLP0_3), + PIS(ERRCONTENTIONLP1_3), + PIS(ULPSACTIVENOT_ALL0), + PIS(ULPSACTIVENOT_ALL1)); #undef PIS - - printk("\n"); } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -1116,28 +1104,16 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, } } -#ifdef DEBUG static void _dsi_print_reset_status(struct platform_device *dsidev) { u32 l; int b0, b1, b2; - if (!dss_debug) - return; - /* A dummy read using the SCP interface to any DSIPHY register is * required after DSIPHY reset to complete the reset of the DSI complex * I/O. */ l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); - printk(KERN_DEBUG "DSI resets: "); - - l = dsi_read_reg(dsidev, DSI_PLL_STATUS); - printk("PLL (%d) ", FLD_GET(l, 0, 0)); - - l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); - printk("CIO (%d) ", FLD_GET(l, 29, 29)); - if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { b0 = 28; b1 = 27; @@ -1148,18 +1124,21 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) b2 = 26; } - l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); - printk("PHY (%x%x%x, %d, %d, %d)\n", - FLD_GET(l, b0, b0), - FLD_GET(l, b1, b1), - FLD_GET(l, b2, b2), - FLD_GET(l, 29, 29), - FLD_GET(l, 30, 30), - FLD_GET(l, 31, 31)); +#define DSI_FLD_GET(fld, start, end)\ + FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end) + + pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n", + DSI_FLD_GET(PLL_STATUS, 0, 0), + DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29), + DSI_FLD_GET(DSIPHY_CFG5, b0, b0), + DSI_FLD_GET(DSIPHY_CFG5, b1, b1), + DSI_FLD_GET(DSIPHY_CFG5, b2, b2), + DSI_FLD_GET(DSIPHY_CFG5, 29, 29), + DSI_FLD_GET(DSIPHY_CFG5, 30, 30), + DSI_FLD_GET(DSIPHY_CFG5, 31, 31)); + +#undef DSI_FLD_GET } -#else -#define _dsi_print_reset_status(x) -#endif static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) { @@ -1407,6 +1386,11 @@ retry: cur.dsi_pll_hsdiv_dispc_clk = cur.clkin4ddr / cur.regm_dispc; + if (cur.regm_dispc > 1 && + cur.regm_dispc % 2 != 0 && + req_pck >= 1000000) + continue; + /* this will narrow down the search a bit, * but still give pixclocks below what was * requested */ @@ -1621,7 +1605,7 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, u8 regn_start, regn_end, regm_start, regm_end; u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; - DSSDBGF(); + DSSDBG("DSI PLL clock config starts"); dsi->current_cinfo.clkin = cinfo->clkin; dsi->current_cinfo.fint = cinfo->fint; @@ -1757,11 +1741,21 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, DSSDBG("PLL init\n"); + /* + * It seems that on many OMAPs we need to enable both to have a + * functional HSDivider. + */ + enable_hsclk = enable_hsdiv = true; + if (dsi->vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); + /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ + if (IS_ERR(vdds_dsi)) + vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); + if (IS_ERR(vdds_dsi)) { DSSERR("can't get VDDS_DSI regulator\n"); return PTR_ERR(vdds_dsi); @@ -2440,7 +2434,7 @@ static int dsi_cio_init(struct platform_device *dsidev) int r; u32 l; - DSSDBGF(); + DSSDBG("DSI CIO init starts"); r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); if (r) @@ -2791,7 +2785,7 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) { u32 r; - DSSDBGF("%d", channel); + DSSDBG("Initial config of virtual channel %d", channel); r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); @@ -2823,7 +2817,7 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel, if (dsi->vc[channel].source == source) return 0; - DSSDBGF("%d", channel); + DSSDBG("Source config of virtual channel %d", channel); dsi_sync_vc(dsidev, channel); @@ -3581,7 +3575,7 @@ static int dsi_enter_ulps(struct platform_device *dsidev) int r, i; unsigned mask; - DSSDBGF(); + DSSDBG("Entering ULPS"); WARN_ON(!dsi_bus_is_locked(dsidev)); @@ -4285,7 +4279,7 @@ int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, unsigned long pck; int r; - DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); + DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); mutex_lock(&dsi->lock); @@ -4541,7 +4535,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) dsi_handle_framedone(dsi->pdev, -ETIMEDOUT); } -static void dsi_framedone_irq_callback(void *data, u32 mask) +static void dsi_framedone_irq_callback(void *data) { struct platform_device *dsidev = (struct platform_device *) data; struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); @@ -4615,7 +4609,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_overlay_manager *mgr = dssdev->output->manager; int r; - u32 irq = 0; if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { dsi->timings.hsw = 1; @@ -4625,12 +4618,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dsi->timings.vfp = 0; dsi->timings.vbp = 0; - irq = dispc_mgr_get_framedone_irq(mgr->id); - - r = omap_dispc_register_isr(dsi_framedone_irq_callback, - (void *) dsidev, irq); + r = dss_mgr_register_framedone_handler(mgr, + dsi_framedone_irq_callback, dsidev); if (r) { - DSSERR("can't get FRAMEDONE irq\n"); + DSSERR("can't register FRAMEDONE handler\n"); goto err; } @@ -4668,8 +4659,8 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) return 0; err1: if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) - omap_dispc_unregister_isr(dsi_framedone_irq_callback, - (void *) dsidev, irq); + dss_mgr_unregister_framedone_handler(mgr, + dsi_framedone_irq_callback, dsidev); err: return r; } @@ -4680,14 +4671,9 @@ static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_overlay_manager *mgr = dssdev->output->manager; - if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { - u32 irq; - - irq = dispc_mgr_get_framedone_irq(mgr->id); - - omap_dispc_unregister_isr(dsi_framedone_irq_callback, - (void *) dsidev, irq); - } + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) + dss_mgr_unregister_framedone_handler(mgr, + dsi_framedone_irq_callback, dsidev); } static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) @@ -4730,7 +4716,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) if (r) goto err1; - dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); dss_select_lcd_clk_source(mgr->id, dssdev->clocks.dispc.channel.lcd_clk_src); @@ -4765,7 +4750,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) err3: dsi_cio_uninit(dsidev); err2: - dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); @@ -4792,7 +4776,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dsi_vc_enable(dsidev, 2, 0); dsi_vc_enable(dsidev, 3, 0); - dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); dsi_cio_uninit(dsidev); @@ -4981,6 +4964,10 @@ static int __init dsi_init_display(struct omap_dss_device *dssdev) vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); + /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ + if (IS_ERR(vdds_dsi)) + vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); + if (IS_ERR(vdds_dsi)) { DSSERR("can't get VDDS_DSI regulator\n"); return PTR_ERR(vdds_dsi); @@ -5121,7 +5108,7 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p { struct omap_dss_board_info *pdata = pdev->dev.platform_data; struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); - const char *def_disp_name = dss_get_default_display_name(); + const char *def_disp_name = omapdss_get_default_display_name(); struct omap_dss_device *def_dssdev; int i; @@ -5151,6 +5138,7 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p static void __init dsi_probe_pdata(struct platform_device *dsidev) { + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_dss_device *plat_dssdev; struct omap_dss_device *dssdev; int r; @@ -5173,9 +5161,18 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) return; } + r = omapdss_output_set_device(&dsi->output, dssdev); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dssdev->name); + dss_put_device(dssdev); + return; + } + r = dss_add_device(dssdev); if (r) { DSSERR("device %s register failed: %d\n", dssdev->name, r); + omapdss_output_unset_device(&dsi->output); dss_put_device(dssdev); return; } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 5f6eea801b0..054c2a22b3f 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -32,11 +32,10 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/gfp.h> +#include <linux/sizes.h> #include <video/omapdss.h> -#include <plat/cpu.h> - #include "dss.h" #include "dss_features.h" @@ -78,6 +77,7 @@ static struct { struct clk *dpll4_m4_ck; struct clk *dss_clk; + unsigned long dss_clk_rate; unsigned long cache_req_pck; unsigned long cache_prate; @@ -98,6 +98,8 @@ static const char * const dss_generic_clk_source_names[] = { [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", + [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC", + [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI", }; static inline void dss_write_reg(const struct dss_reg idx, u32 val) @@ -153,6 +155,21 @@ static void dss_restore_context(void) #undef SR #undef RR +int dss_get_ctx_loss_count(void) +{ + struct omap_dss_board_info *board_data = dss.pdev->dev.platform_data; + int cnt; + + if (!board_data->get_context_loss_count) + return -ENOENT; + + cnt = board_data->get_context_loss_count(&dss.pdev->dev); + + WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); + + return cnt; +} + void dss_sdi_init(int datapairs) { u32 l; @@ -303,7 +320,7 @@ static void dss_dump_regs(struct seq_file *s) #undef DUMPREG } -void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) +static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) { struct platform_device *dsidev; int b; @@ -374,8 +391,10 @@ void dss_select_lcd_clk_source(enum omap_channel channel, struct platform_device *dsidev; int b, ix, pos; - if (!dss_has_feature(FEAT_LCD_CLK_SRC)) + if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { + dss_select_dispc_clk_source(clk_src); return; + } switch (clk_src) { case OMAP_DSS_CLK_SRC_FCK: @@ -431,6 +450,29 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) } } +/* calculate clock rates using dividers in cinfo */ +int dss_calc_clock_rates(struct dss_clock_info *cinfo) +{ + if (dss.dpll4_m4_ck) { + unsigned long prate; + + if (cinfo->fck_div > dss.feat->fck_div_max || + cinfo->fck_div == 0) + return -EINVAL; + + prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); + + cinfo->fck = prate / cinfo->fck_div * + dss.feat->dss_fck_multiplier; + } else { + if (cinfo->fck_div != 0) + return -EINVAL; + cinfo->fck = clk_get_rate(dss.dss_clk); + } + + return 0; +} + int dss_set_clock_div(struct dss_clock_info *cinfo) { if (dss.dpll4_m4_ck) { @@ -448,6 +490,10 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) return -EINVAL; } + dss.dss_clk_rate = clk_get_rate(dss.dss_clk); + + WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch"); + DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); return 0; @@ -461,6 +507,41 @@ unsigned long dss_get_dpll4_rate(void) return 0; } +unsigned long dss_get_dispc_clk_rate(void) +{ + return dss.dss_clk_rate; +} + +static int dss_setup_default_clock(void) +{ + unsigned long max_dss_fck, prate; + unsigned fck_div; + struct dss_clock_info dss_cinfo = { 0 }; + int r; + + if (dss.dpll4_m4_ck == NULL) + return 0; + + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + prate = dss_get_dpll4_rate(); + + fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier, + max_dss_fck); + + dss_cinfo.fck_div = fck_div; + + r = dss_calc_clock_rates(&dss_cinfo); + if (r) + return r; + + r = dss_set_clock_div(&dss_cinfo); + if (r) + return r; + + return 0; +} + int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, struct dispc_clock_info *dispc_cinfo) { @@ -750,7 +831,7 @@ static void dss_runtime_put(void) } /* DEBUGFS */ -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +#if defined(CONFIG_OMAP2_DSS_DEBUGFS) void dss_debug_dump_clocks(struct seq_file *s) { dss_dump_clocks(s); @@ -796,29 +877,45 @@ static const struct dss_features omap54xx_dss_feats __initconst = { .dpi_select_source = &dss_dpi_select_source_omap5, }; -static int __init dss_init_features(struct device *dev) +static int __init dss_init_features(struct platform_device *pdev) { const struct dss_features *src; struct dss_features *dst; - dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); if (!dst) { - dev_err(dev, "Failed to allocate local DSS Features\n"); + dev_err(&pdev->dev, "Failed to allocate local DSS Features\n"); return -ENOMEM; } - if (cpu_is_omap24xx()) + switch (omapdss_get_version()) { + case OMAPDSS_VER_OMAP24xx: src = &omap24xx_dss_feats; - else if (cpu_is_omap3630()) - src = &omap3630_dss_feats; - else if (cpu_is_omap34xx()) + break; + + case OMAPDSS_VER_OMAP34xx_ES1: + case OMAPDSS_VER_OMAP34xx_ES3: + case OMAPDSS_VER_AM35xx: src = &omap34xx_dss_feats; - else if (cpu_is_omap44xx()) + break; + + case OMAPDSS_VER_OMAP3630: + src = &omap3630_dss_feats; + break; + + case OMAPDSS_VER_OMAP4430_ES1: + case OMAPDSS_VER_OMAP4430_ES2: + case OMAPDSS_VER_OMAP4: src = &omap44xx_dss_feats; - else if (soc_is_omap54xx()) + break; + + case OMAPDSS_VER_OMAP5: src = &omap54xx_dss_feats; - else + break; + + default: return -ENODEV; + } memcpy(dst, src, sizeof(*dst)); dss.feat = dst; @@ -835,7 +932,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss.pdev = pdev; - r = dss_init_features(&dss.pdev->dev); + r = dss_init_features(dss.pdev); if (r) return r; @@ -856,15 +953,23 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) if (r) return r; + r = dss_setup_default_clock(); + if (r) + goto err_setup_clocks; + pm_runtime_enable(&pdev->dev); r = dss_runtime_get(); if (r) goto err_runtime_get; + dss.dss_clk_rate = clk_get_rate(dss.dss_clk); + /* Select DPLL */ REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); + dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); + #ifdef CONFIG_OMAP2_DSS_VENC REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ @@ -888,6 +993,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) err_runtime_get: pm_runtime_disable(&pdev->dev); +err_setup_clocks: dss_put_clocks(); return r; } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 6728892f9da..610c8e563da 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -23,44 +23,20 @@ #ifndef __OMAP2_DSS_H #define __OMAP2_DSS_H -#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT -#define DEBUG -#endif +#include <linux/interrupt.h> -#ifdef DEBUG -extern bool dss_debug; -#ifdef DSS_SUBSYS_NAME -#define DSSDBG(format, ...) \ - if (dss_debug) \ - printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \ - ## __VA_ARGS__) -#else -#define DSSDBG(format, ...) \ - if (dss_debug) \ - printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__) +#ifdef pr_fmt +#undef pr_fmt #endif #ifdef DSS_SUBSYS_NAME -#define DSSDBGF(format, ...) \ - if (dss_debug) \ - printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \ - ": %s(" format ")\n", \ - __func__, \ - ## __VA_ARGS__) +#define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt #else -#define DSSDBGF(format, ...) \ - if (dss_debug) \ - printk(KERN_DEBUG "omapdss: " \ - ": %s(" format ")\n", \ - __func__, \ - ## __VA_ARGS__) -#endif - -#else /* DEBUG */ -#define DSSDBG(format, ...) -#define DSSDBGF(format, ...) +#define pr_fmt(fmt) fmt #endif +#define DSSDBG(format, ...) \ + pr_debug(format, ## __VA_ARGS__) #ifdef DSS_SUBSYS_NAME #define DSSERR(format, ...) \ @@ -186,11 +162,10 @@ struct seq_file; struct platform_device; /* core */ -const char *dss_get_default_display_name(void); +struct platform_device *dss_get_core_pdev(void); struct bus_type *dss_get_bus(void); struct regulator *dss_get_vdds_dsi(void); struct regulator *dss_get_vdds_sdi(void); -int dss_get_ctx_loss_count(struct device *dev); int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask); void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); int dss_set_min_bus_tput(struct device *dev, unsigned long tput); @@ -204,55 +179,18 @@ void dss_put_device(struct omap_dss_device *dssdev); void dss_copy_device_pdata(struct omap_dss_device *dst, const struct omap_dss_device *src); -/* apply */ -void dss_apply_init(void); -int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr); -int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); -void dss_mgr_start_update(struct omap_overlay_manager *mgr); -int omap_dss_mgr_apply(struct omap_overlay_manager *mgr); - -int dss_mgr_enable(struct omap_overlay_manager *mgr); -void dss_mgr_disable(struct omap_overlay_manager *mgr); -int dss_mgr_set_info(struct omap_overlay_manager *mgr, - struct omap_overlay_manager_info *info); -void dss_mgr_get_info(struct omap_overlay_manager *mgr, - struct omap_overlay_manager_info *info); -int dss_mgr_set_device(struct omap_overlay_manager *mgr, - struct omap_dss_device *dssdev); -int dss_mgr_unset_device(struct omap_overlay_manager *mgr); -int dss_mgr_set_output(struct omap_overlay_manager *mgr, - struct omap_dss_output *output); -int dss_mgr_unset_output(struct omap_overlay_manager *mgr); -void dss_mgr_set_timings(struct omap_overlay_manager *mgr, - const struct omap_video_timings *timings); -void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, - const struct dss_lcd_mgr_config *config); -const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr); - -bool dss_ovl_is_enabled(struct omap_overlay *ovl); -int dss_ovl_enable(struct omap_overlay *ovl); -int dss_ovl_disable(struct omap_overlay *ovl); -int dss_ovl_set_info(struct omap_overlay *ovl, - struct omap_overlay_info *info); -void dss_ovl_get_info(struct omap_overlay *ovl, - struct omap_overlay_info *info); -int dss_ovl_set_manager(struct omap_overlay *ovl, - struct omap_overlay_manager *mgr); -int dss_ovl_unset_manager(struct omap_overlay *ovl); - /* output */ void dss_register_output(struct omap_dss_output *out); void dss_unregister_output(struct omap_dss_output *out); -struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev); /* display */ int dss_suspend_all_devices(void); int dss_resume_all_devices(void); void dss_disable_all_devices(void); -int dss_init_device(struct platform_device *pdev, +int display_init_sysfs(struct platform_device *pdev, struct omap_dss_device *dssdev); -void dss_uninit_device(struct platform_device *pdev, +void display_uninit_sysfs(struct platform_device *pdev, struct omap_dss_device *dssdev); /* manager */ @@ -299,21 +237,23 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl); int dss_init_platform_driver(void) __init; void dss_uninit_platform_driver(void); +unsigned long dss_get_dispc_clk_rate(void); int dss_dpi_select_source(enum omap_channel channel); void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); void dss_dump_clocks(struct seq_file *s); -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +#if defined(CONFIG_OMAP2_DSS_DEBUGFS) void dss_debug_dump_clocks(struct seq_file *s); #endif +int dss_get_ctx_loss_count(void); + void dss_sdi_init(int datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); -void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src); void dss_select_dsi_clk_source(int dsi_module, enum omap_dss_clk_source clk_src); void dss_select_lcd_clk_source(enum omap_channel channel, @@ -326,6 +266,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); unsigned long dss_get_dpll4_rate(void); +int dss_calc_clock_rates(struct dss_clock_info *cinfo); int dss_set_clock_div(struct dss_clock_info *cinfo); int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, struct dispc_clock_info *dispc_cinfo); @@ -413,8 +354,6 @@ static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev) } static inline struct platform_device *dsi_get_dsidev_from_id(int module) { - WARN("%s: DSI not compiled in, returning platform device as NULL\n", - __func__); return NULL; } #endif @@ -427,15 +366,10 @@ void dpi_uninit_platform_driver(void) __exit; int dispc_init_platform_driver(void) __init; void dispc_uninit_platform_driver(void) __exit; void dispc_dump_clocks(struct seq_file *s); -void dispc_irq_handler(void); - -int dispc_runtime_get(void); -void dispc_runtime_put(void); void dispc_enable_sidle(void); void dispc_disable_sidle(void); -void dispc_lcd_enable_signal_polarity(bool act_high); void dispc_lcd_enable_signal(bool enable); void dispc_pck_free_enable(bool enable); void dispc_enable_fifomerge(bool enable); @@ -455,36 +389,14 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, bool manual_update); -int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, - bool replication, const struct omap_video_timings *mgr_timings, - bool mem_to_mem); -int dispc_ovl_enable(enum omap_plane plane, bool enable); -void dispc_ovl_set_channel_out(enum omap_plane plane, - enum omap_channel channel); - -void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); -u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); -u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); -bool dispc_mgr_go_busy(enum omap_channel channel); -void dispc_mgr_go(enum omap_channel channel); -bool dispc_mgr_is_enabled(enum omap_channel channel); -void dispc_mgr_enable(enum omap_channel channel, bool enable); -bool dispc_mgr_is_channel_enabled(enum omap_channel channel); -void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); -void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable); -void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); -void dispc_mgr_set_lcd_type_tft(enum omap_channel channel); -void dispc_mgr_set_timings(enum omap_channel channel, - struct omap_video_timings *timings); + unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); unsigned long dispc_core_clk_rate(void); void dispc_mgr_set_clock_div(enum omap_channel channel, - struct dispc_clock_info *cinfo); + const struct dispc_clock_info *cinfo); int dispc_mgr_get_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo); -void dispc_mgr_setup(enum omap_channel channel, - struct omap_overlay_manager_info *info); u32 dispc_wb_get_framedone_irq(void); bool dispc_wb_go_busy(void); @@ -536,6 +448,8 @@ static inline unsigned long hdmi_get_pixel_clock(void) #endif int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); +int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev); +void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings); int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index acbc1e1efba..18688c12e30 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -18,12 +18,12 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/types.h> #include <linux/err.h> #include <linux/slab.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" @@ -430,8 +430,6 @@ static const struct dss_param_range omap2_dss_param_range[] = { * scaler cannot scale a image with width more than 768. */ [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, - [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, - [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, }; static const struct dss_param_range omap3_dss_param_range[] = { @@ -446,8 +444,6 @@ static const struct dss_param_range omap3_dss_param_range[] = { [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, - [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, - [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, }; static const struct dss_param_range omap4_dss_param_range[] = { @@ -462,8 +458,6 @@ static const struct dss_param_range omap4_dss_param_range[] = { [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, - [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, - [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, }; static const struct dss_param_range omap5_dss_param_range[] = { @@ -478,8 +472,6 @@ static const struct dss_param_range omap5_dss_param_range[] = { [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, - [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, - [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, }; static const enum dss_feat_id omap2_dss_feat_list[] = { @@ -821,14 +813,25 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { .audio_start = ti_hdmi_4xxx_audio_start, .audio_stop = ti_hdmi_4xxx_audio_stop, .audio_config = ti_hdmi_4xxx_audio_config, + .audio_get_dma_port = ti_hdmi_4xxx_audio_get_dma_port, #endif }; -void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data) +void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data, + enum omapdss_version version) { - if (cpu_is_omap44xx()) + switch (version) { + case OMAPDSS_VER_OMAP4430_ES1: + case OMAPDSS_VER_OMAP4430_ES2: + case OMAPDSS_VER_OMAP4: ip_data->ops = &omap4_hdmi_functions; + break; + default: + ip_data->ops = NULL; + } + + WARN_ON(ip_data->ops == NULL); } #endif @@ -837,11 +840,13 @@ int dss_feat_get_num_mgrs(void) { return omap_current_dss_features->num_mgrs; } +EXPORT_SYMBOL(dss_feat_get_num_mgrs); int dss_feat_get_num_ovls(void) { return omap_current_dss_features->num_ovls; } +EXPORT_SYMBOL(dss_feat_get_num_ovls); int dss_feat_get_num_wbs(void) { @@ -862,16 +867,19 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel { return omap_current_dss_features->supported_displays[channel]; } +EXPORT_SYMBOL(dss_feat_get_supported_displays); enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel) { return omap_current_dss_features->supported_outputs[channel]; } +EXPORT_SYMBOL(dss_feat_get_supported_outputs); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) { return omap_current_dss_features->supported_color_modes[plane]; } +EXPORT_SYMBOL(dss_feat_get_supported_color_modes); enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane) { @@ -929,29 +937,44 @@ bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type) return omap_current_dss_features->supported_rotation_types & rot_type; } -void dss_features_init(void) +void dss_features_init(enum omapdss_version version) { - if (cpu_is_omap24xx()) + switch (version) { + case OMAPDSS_VER_OMAP24xx: omap_current_dss_features = &omap2_dss_features; - else if (cpu_is_omap3630()) + break; + + case OMAPDSS_VER_OMAP34xx_ES1: + case OMAPDSS_VER_OMAP34xx_ES3: + omap_current_dss_features = &omap3430_dss_features; + break; + + case OMAPDSS_VER_OMAP3630: omap_current_dss_features = &omap3630_dss_features; - else if (cpu_is_omap34xx()) { - if (soc_is_am35xx()) { - omap_current_dss_features = &am35xx_dss_features; - } else { - omap_current_dss_features = &omap3430_dss_features; - } - } - else if (omap_rev() == OMAP4430_REV_ES1_0) + break; + + case OMAPDSS_VER_OMAP4430_ES1: omap_current_dss_features = &omap4430_es1_0_dss_features; - else if (omap_rev() == OMAP4430_REV_ES2_0 || - omap_rev() == OMAP4430_REV_ES2_1 || - omap_rev() == OMAP4430_REV_ES2_2) + break; + + case OMAPDSS_VER_OMAP4430_ES2: omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; - else if (cpu_is_omap44xx()) + break; + + case OMAPDSS_VER_OMAP4: omap_current_dss_features = &omap4_dss_features; - else if (soc_is_omap54xx()) + break; + + case OMAPDSS_VER_OMAP5: omap_current_dss_features = &omap5_dss_features; - else + break; + + case OMAPDSS_VER_AM35xx: + omap_current_dss_features = &am35xx_dss_features; + break; + + default: DSSWARN("Unsupported OMAP version"); + break; + } } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 9218113b5e8..489b9bec4a6 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -98,19 +98,12 @@ enum dss_range_param { FEAT_PARAM_DSI_FCK, FEAT_PARAM_DOWNSCALE, FEAT_PARAM_LINEWIDTH, - FEAT_PARAM_MGR_WIDTH, - FEAT_PARAM_MGR_HEIGHT, }; /* DSS Feature Functions */ -int dss_feat_get_num_mgrs(void); -int dss_feat_get_num_ovls(void); int dss_feat_get_num_wbs(void); unsigned long dss_feat_get_param_min(enum dss_range_param param); unsigned long dss_feat_get_param_max(enum dss_range_param param); -enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); -enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel); -enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, enum omap_color_mode color_mode); @@ -123,8 +116,9 @@ bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type); bool dss_has_feature(enum dss_feat_id id); void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); -void dss_features_init(void); +void dss_features_init(enum omapdss_version version); #if defined(CONFIG_OMAP4_DSS_HDMI) -void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data); +void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data, + enum omapdss_version version); #endif #endif diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 8c9b8b3b7f7..769d0828581 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -60,6 +60,7 @@ static struct { struct mutex lock; struct platform_device *pdev; + struct hdmi_ip_data ip_data; struct clk *sys_clk; @@ -295,6 +296,12 @@ static const struct hdmi_config vesa_timings[] = { false, }, { 0x55, HDMI_DVI }, }, + { + { 1920, 1200, 154000, 32, 48, 80, 6, 3, 26, + OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, + false, }, + { 0x44, HDMI_DVI }, + }, }; static int hdmi_runtime_get(void) @@ -333,13 +340,17 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) DSSDBG("init_display\n"); - dss_init_hdmi_ip_ops(&hdmi.ip_data); + dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); if (hdmi.vdda_hdmi_dac_reg == NULL) { struct regulator *reg; reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); + /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ + if (IS_ERR(reg)) + reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); + if (IS_ERR(reg)) { DSSERR("can't get VDDA_HDMI_DAC regulator\n"); return PTR_ERR(reg); @@ -355,7 +366,7 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) return 0; } -static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev) +static void hdmi_uninit_display(struct omap_dss_device *dssdev) { DSSDBG("uninit_display\n"); @@ -398,7 +409,8 @@ static bool hdmi_timings_compare(struct omap_video_timings *timing1, { int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; - if ((timing2->pixel_clock == timing1->pixel_clock) && + if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) == + DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) && (timing2->x_res == timing1->x_res) && (timing2->y_res == timing1->y_res)) { @@ -500,12 +512,9 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); } -static int hdmi_power_on(struct omap_dss_device *dssdev) +static int hdmi_power_on_core(struct omap_dss_device *dssdev) { int r; - struct omap_video_timings *p; - struct omap_overlay_manager *mgr = dssdev->output->manager; - unsigned long phy; gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); gpio_set_value(hdmi.ls_oe_gpio, 1); @@ -521,6 +530,38 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) if (r) goto err_runtime_get; + /* Make selection of HDMI in DSS */ + dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); + + return 0; + +err_runtime_get: + regulator_disable(hdmi.vdda_hdmi_dac_reg); +err_vdac_enable: + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); + return r; +} + +static void hdmi_power_off_core(struct omap_dss_device *dssdev) +{ + hdmi_runtime_put(); + regulator_disable(hdmi.vdda_hdmi_dac_reg); + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); +} + +static int hdmi_power_on_full(struct omap_dss_device *dssdev) +{ + int r; + struct omap_video_timings *p; + struct omap_overlay_manager *mgr = dssdev->output->manager; + unsigned long phy; + + r = hdmi_power_on_core(dssdev); + if (r) + return r; + dss_mgr_disable(mgr); p = &hdmi.ip_data.cfg.timings; @@ -548,17 +589,6 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) hdmi.ip_data.ops->video_configure(&hdmi.ip_data); - /* Make selection of HDMI in DSS */ - dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); - - /* Select the dispc clock source as PRCM clock, to ensure that it is not - * DSI PLL source as the clock selected by DSI PLL might not be - * sufficient for the resolution selected / that can be changed - * dynamically by user. This can be moved to single location , say - * Boardfile. - */ - dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); - /* bypass TV gamma table */ dispc_enable_gamma_table(0); @@ -582,16 +612,11 @@ err_vid_enable: err_phy_enable: hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); err_pll_enable: - hdmi_runtime_put(); -err_runtime_get: - regulator_disable(hdmi.vdda_hdmi_dac_reg); -err_vdac_enable: - gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); - gpio_set_value(hdmi.ls_oe_gpio, 0); + hdmi_power_off_core(dssdev); return -EIO; } -static void hdmi_power_off(struct omap_dss_device *dssdev) +static void hdmi_power_off_full(struct omap_dss_device *dssdev) { struct omap_overlay_manager *mgr = dssdev->output->manager; @@ -600,12 +625,8 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) hdmi.ip_data.ops->video_disable(&hdmi.ip_data); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); - hdmi_runtime_put(); - - regulator_disable(hdmi.vdda_hdmi_dac_reg); - gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); - gpio_set_value(hdmi.ls_oe_gpio, 0); + hdmi_power_off_core(dssdev); } int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, @@ -715,7 +736,7 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } - r = hdmi_power_on(dssdev); + r = hdmi_power_on_full(dssdev); if (r) { DSSERR("failed to power on device\n"); goto err1; @@ -737,13 +758,48 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - hdmi_power_off(dssdev); + hdmi_power_off_full(dssdev); omap_dss_stop_device(dssdev); mutex_unlock(&hdmi.lock); } +int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + + DSSDBG("ENTER omapdss_hdmi_core_enable\n"); + + mutex_lock(&hdmi.lock); + + hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; + + r = hdmi_power_on_core(dssdev); + if (r) { + DSSERR("failed to power on device\n"); + goto err0; + } + + mutex_unlock(&hdmi.lock); + return 0; + +err0: + mutex_unlock(&hdmi.lock); + return r; +} + +void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev) +{ + DSSDBG("Enter omapdss_hdmi_core_disable\n"); + + mutex_lock(&hdmi.lock); + + hdmi_power_off_core(dssdev); + + mutex_unlock(&hdmi.lock); +} + static int hdmi_get_clocks(struct platform_device *pdev) { struct clk *clk; @@ -912,7 +968,7 @@ int hdmi_audio_config(struct omap_dss_audio *audio) static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - const char *def_disp_name = dss_get_default_display_name(); + const char *def_disp_name = omapdss_get_default_display_name(); struct omap_dss_device *def_dssdev; int i; @@ -970,9 +1026,19 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) return; } + r = omapdss_output_set_device(&hdmi.output, dssdev); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dssdev->name); + dss_put_device(dssdev); + return; + } + r = dss_add_device(dssdev); if (r) { DSSERR("device %s register failed: %d\n", dssdev->name, r); + omapdss_output_unset_device(&hdmi.output); + hdmi_uninit_display(dssdev); dss_put_device(dssdev); return; } @@ -999,22 +1065,22 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev) /* HDMI HW IP initialisation */ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) { - struct resource *hdmi_mem; + struct resource *res; int r; hdmi.pdev = pdev; mutex_init(&hdmi.lock); + mutex_init(&hdmi.ip_data.lock); - hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); - if (!hdmi_mem) { + res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); + if (!res) { DSSERR("can't get IORESOURCE_MEM HDMI\n"); return -EINVAL; } /* Base address taken from platform */ - hdmi.ip_data.base_wp = ioremap(hdmi_mem->start, - resource_size(hdmi_mem)); + hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res); if (!hdmi.ip_data.base_wp) { DSSERR("can't ioremap WP\n"); return -ENOMEM; @@ -1022,7 +1088,7 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) r = hdmi_get_clocks(pdev); if (r) { - iounmap(hdmi.ip_data.base_wp); + DSSERR("can't get clocks\n"); return r; } @@ -1033,9 +1099,11 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) hdmi.ip_data.pll_offset = HDMI_PLLCTRL; hdmi.ip_data.phy_offset = HDMI_PHY; - mutex_init(&hdmi.ip_data.lock); - - hdmi_panel_init(); + r = hdmi_panel_init(); + if (r) { + DSSERR("can't init panel\n"); + goto err_panel_init; + } dss_debugfs_create_file("hdmi", hdmi_dump_regs); @@ -1044,6 +1112,10 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) hdmi_probe_pdata(pdev); return 0; + +err_panel_init: + hdmi_put_clocks(); + return r; } static int __exit hdmi_remove_child(struct device *dev, void *data) @@ -1067,8 +1139,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) hdmi_put_clocks(); - iounmap(hdmi.ip_data.base_wp); - return 0; } diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index 69fb115bab3..dfb8eda81b6 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c @@ -280,58 +280,6 @@ static void hdmi_panel_disable(struct omap_dss_device *dssdev) mutex_unlock(&hdmi.lock); } -static int hdmi_panel_suspend(struct omap_dss_device *dssdev) -{ - int r = 0; - - mutex_lock(&hdmi.lock); - - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { - r = -EINVAL; - goto err; - } - - /* - * TODO: notify audio users that the display was suspended. For now, - * disable audio locally to not break our audio state machine. - */ - hdmi_panel_audio_disable(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - omapdss_hdmi_display_disable(dssdev); - -err: - mutex_unlock(&hdmi.lock); - - return r; -} - -static int hdmi_panel_resume(struct omap_dss_device *dssdev) -{ - int r = 0; - - mutex_lock(&hdmi.lock); - - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { - r = -EINVAL; - goto err; - } - - r = omapdss_hdmi_display_enable(dssdev); - if (r) { - DSSERR("failed to power on\n"); - goto err; - } - /* TODO: notify audio users that the panel resumed. */ - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - -err: - mutex_unlock(&hdmi.lock); - - return r; -} - static void hdmi_get_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { @@ -379,20 +327,22 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev, static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) { int r; + bool need_enable; mutex_lock(&hdmi.lock); - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { - r = omapdss_hdmi_display_enable(dssdev); + need_enable = dssdev->state == OMAP_DSS_DISPLAY_DISABLED; + + if (need_enable) { + r = omapdss_hdmi_core_enable(dssdev); if (r) goto err; } r = omapdss_hdmi_read_edid(buf, len); - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED || - dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) - omapdss_hdmi_display_disable(dssdev); + if (need_enable) + omapdss_hdmi_core_disable(dssdev); err: mutex_unlock(&hdmi.lock); @@ -402,20 +352,22 @@ err: static bool hdmi_detect(struct omap_dss_device *dssdev) { int r; + bool need_enable; mutex_lock(&hdmi.lock); - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { - r = omapdss_hdmi_display_enable(dssdev); + need_enable = dssdev->state == OMAP_DSS_DISPLAY_DISABLED; + + if (need_enable) { + r = omapdss_hdmi_core_enable(dssdev); if (r) goto err; } r = omapdss_hdmi_detect(); - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED || - dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) - omapdss_hdmi_display_disable(dssdev); + if (need_enable) + omapdss_hdmi_core_disable(dssdev); err: mutex_unlock(&hdmi.lock); @@ -427,8 +379,6 @@ static struct omap_dss_driver hdmi_driver = { .remove = hdmi_panel_remove, .enable = hdmi_panel_enable, .disable = hdmi_panel_disable, - .suspend = hdmi_panel_suspend, - .resume = hdmi_panel_resume, .get_timings = hdmi_get_timings, .set_timings = hdmi_set_timings, .check_timings = hdmi_check_timings, @@ -454,9 +404,7 @@ int hdmi_panel_init(void) spin_lock_init(&hdmi.audio_lock); #endif - omap_dss_register_driver(&hdmi_driver); - - return 0; + return omap_dss_register_driver(&hdmi_driver); } void hdmi_panel_exit(void) diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index c54d2f620ce..2551eaa14c4 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -36,36 +36,6 @@ static int num_managers; static struct omap_overlay_manager *managers; -static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) -{ - return mgr->output ? mgr->output->device : NULL; -} - -static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) -{ - unsigned long timeout = msecs_to_jiffies(500); - struct omap_dss_device *dssdev = mgr->get_device(mgr); - u32 irq; - int r; - - r = dispc_runtime_get(); - if (r) - return r; - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) - irq = DISPC_IRQ_EVSYNC_ODD; - else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) - irq = DISPC_IRQ_EVSYNC_EVEN; - else - irq = dispc_mgr_get_vsync_irq(mgr->id); - - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - - dispc_runtime_put(); - - return r; -} - int dss_init_overlay_managers(struct platform_device *pdev) { int i, r; @@ -99,15 +69,6 @@ int dss_init_overlay_managers(struct platform_device *pdev) break; } - mgr->set_output = &dss_mgr_set_output; - mgr->unset_output = &dss_mgr_unset_output; - mgr->apply = &omap_dss_mgr_apply; - mgr->set_manager_info = &dss_mgr_set_info; - mgr->get_manager_info = &dss_mgr_get_info; - mgr->wait_for_go = &dss_mgr_wait_for_go; - mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; - mgr->get_device = &dss_mgr_get_device; - mgr->caps = 0; mgr->supported_displays = dss_feat_get_supported_displays(mgr->id); diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c index 813f26682b7..79dea1a1a73 100644 --- a/drivers/video/omap2/dss/output.c +++ b/drivers/video/omap2/dss/output.c @@ -114,35 +114,67 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) return NULL; } -struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev) +static const struct dss_mgr_ops *dss_mgr_ops; + +int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) { - struct omap_dss_output *out = NULL; - enum omap_dss_output_id id; - - switch (dssdev->type) { - case OMAP_DISPLAY_TYPE_DPI: - out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI); - break; - case OMAP_DISPLAY_TYPE_DBI: - out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI); - break; - case OMAP_DISPLAY_TYPE_SDI: - out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI); - break; - case OMAP_DISPLAY_TYPE_VENC: - out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC); - break; - case OMAP_DISPLAY_TYPE_HDMI: - out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI); - break; - case OMAP_DISPLAY_TYPE_DSI: - id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 : - OMAP_DSS_OUTPUT_DSI2; - out = omap_dss_get_output(id); - break; - default: - break; - } + if (dss_mgr_ops) + return -EBUSY; + + dss_mgr_ops = mgr_ops; + + return 0; +} +EXPORT_SYMBOL(dss_install_mgr_ops); + +void dss_uninstall_mgr_ops(void) +{ + dss_mgr_ops = NULL; +} +EXPORT_SYMBOL(dss_uninstall_mgr_ops); + +void dss_mgr_set_timings(struct omap_overlay_manager *mgr, + const struct omap_video_timings *timings) +{ + dss_mgr_ops->set_timings(mgr, timings); +} +EXPORT_SYMBOL(dss_mgr_set_timings); + +void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, + const struct dss_lcd_mgr_config *config) +{ + dss_mgr_ops->set_lcd_config(mgr, config); +} +EXPORT_SYMBOL(dss_mgr_set_lcd_config); + +int dss_mgr_enable(struct omap_overlay_manager *mgr) +{ + return dss_mgr_ops->enable(mgr); +} +EXPORT_SYMBOL(dss_mgr_enable); + +void dss_mgr_disable(struct omap_overlay_manager *mgr) +{ + dss_mgr_ops->disable(mgr); +} +EXPORT_SYMBOL(dss_mgr_disable); - return out; +void dss_mgr_start_update(struct omap_overlay_manager *mgr) +{ + dss_mgr_ops->start_update(mgr); +} +EXPORT_SYMBOL(dss_mgr_start_update); + +int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr, + void (*handler)(void *), void *data) +{ + return dss_mgr_ops->register_framedone_handler(mgr, handler, data); +} +EXPORT_SYMBOL(dss_mgr_register_framedone_handler); + +void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr, + void (*handler)(void *), void *data) +{ + dss_mgr_ops->unregister_framedone_handler(mgr, handler, data); } +EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 45f4994bc6b..eccde322c28 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -38,13 +38,6 @@ static int num_overlays; static struct omap_overlay *overlays; -static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) -{ - return ovl->manager ? - (ovl->manager->output ? ovl->manager->output->device : NULL) : - NULL; -} - int omap_dss_get_num_overlays(void) { return num_overlays; @@ -93,16 +86,6 @@ void dss_init_overlays(struct platform_device *pdev) break; } - ovl->is_enabled = &dss_ovl_is_enabled; - ovl->enable = &dss_ovl_enable; - ovl->disable = &dss_ovl_disable; - ovl->set_manager = &dss_ovl_set_manager; - ovl->unset_manager = &dss_ovl_unset_manager; - ovl->set_overlay_info = &dss_ovl_set_info; - ovl->get_overlay_info = &dss_ovl_get_info; - ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; - ovl->get_device = &dss_ovl_get_device; - ovl->caps = dss_feat_get_overlay_caps(ovl->id); ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 7282e5af3e1..e903dd3f54d 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -342,7 +342,7 @@ static int rfbi_transfer_area(struct omap_dss_device *dssdev, return 0; } -static void framedone_callback(void *data, u32 mask) +static void framedone_callback(void *data) { void (*callback)(void *data); @@ -908,8 +908,8 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) goto err0; } - r = omap_dispc_register_isr(framedone_callback, NULL, - DISPC_IRQ_FRAMEDONE); + r = dss_mgr_register_framedone_handler(out->manager, + framedone_callback, NULL); if (r) { DSSERR("can't get FRAMEDONE irq\n"); goto err1; @@ -933,8 +933,10 @@ EXPORT_SYMBOL(omapdss_rfbi_display_enable); void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) { - omap_dispc_unregister_isr(framedone_callback, NULL, - DISPC_IRQ_FRAMEDONE); + struct omap_dss_output *out = dssdev->output; + + dss_mgr_unregister_framedone_handler(out->manager, + framedone_callback, NULL); omap_dss_stop_device(dssdev); rfbi_runtime_put(); @@ -950,7 +952,7 @@ static int __init rfbi_init_display(struct omap_dss_device *dssdev) static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - const char *def_disp_name = dss_get_default_display_name(); + const char *def_disp_name = omapdss_get_default_display_name(); struct omap_dss_device *def_dssdev; int i; @@ -999,9 +1001,18 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev) return; } + r = omapdss_output_set_device(&rfbi.output, dssdev); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dssdev->name); + dss_put_device(dssdev); + return; + } + r = dss_add_device(dssdev); if (r) { DSSERR("device %s register failed: %d\n", dssdev->name, r); + omapdss_output_unset_device(&rfbi.output); dss_put_device(dssdev); return; } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 7760851f6e5..62b5374ce43 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -205,7 +205,7 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - const char *def_disp_name = dss_get_default_display_name(); + const char *def_disp_name = omapdss_get_default_display_name(); struct omap_dss_device *def_dssdev; int i; @@ -254,9 +254,18 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev) return; } + r = omapdss_output_set_device(&sdi.output, dssdev); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dssdev->name); + dss_put_device(dssdev); + return; + } + r = dss_add_device(dssdev); if (r) { DSSERR("device %s register failed: %d\n", dssdev->name, r); + omapdss_output_unset_device(&sdi.output); dss_put_device(dssdev); return; } diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index b046c208cb9..216aa704f9d 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -102,6 +102,8 @@ struct ti_hdmi_ip_ops { int (*audio_config)(struct hdmi_ip_data *ip_data, struct omap_dss_audio *audio); + + int (*audio_get_dma_port)(u32 *offset, u32 *size); #endif }; @@ -183,5 +185,6 @@ int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data); void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data); int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, struct omap_dss_audio *audio); +int ti_hdmi_4xxx_audio_get_dma_port(u32 *offset, u32 *size); #endif #endif diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index c23b85a20cd..e18b222ed73 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -899,7 +899,7 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) #define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\ hdmi_read_reg(hdmi_av_base(ip_data), r)) #define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \ - (i < 10) ? 32 - strlen(#r) : 31 - strlen(#r), " ", \ + (i < 10) ? 32 - (int)strlen(#r) : 31 - (int)strlen(#r), " ", \ hdmi_read_reg(hdmi_av_base(ip_data), CORE_REG(i, r))) DUMPCORE(HDMI_CORE_SYS_VND_IDL); @@ -1418,4 +1418,13 @@ void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data) REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, false, 30, 30); } + +int ti_hdmi_4xxx_audio_get_dma_port(u32 *offset, u32 *size) +{ + if (!offset || !size) + return -EINVAL; + *offset = HDMI_WP_AUDIO_DATA; + *size = 4; + return 0; +} #endif diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 56efa3bb465..006caf3cb50 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -744,7 +744,7 @@ static void venc_put_clocks(void) static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - const char *def_disp_name = dss_get_default_display_name(); + const char *def_disp_name = omapdss_get_default_display_name(); struct omap_dss_device *def_dssdev; int i; @@ -795,9 +795,18 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) return; } + r = omapdss_output_set_device(&venc.output, dssdev); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dssdev->name); + dss_put_device(dssdev); + return; + } + r = dss_add_device(dssdev); if (r) { DSSERR("device %s register failed: %d\n", dssdev->name, r); + omapdss_output_unset_device(&venc.output); dss_put_device(dssdev); return; } diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c index d55b8784ecf..0d2b1a0834a 100644 --- a/drivers/video/omap2/dss/venc_panel.c +++ b/drivers/video/omap2/dss/venc_panel.c @@ -157,12 +157,6 @@ static void venc_panel_disable(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) goto end; - if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { - /* suspended is the same as disabled with venc */ - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - goto end; - } - omapdss_venc_display_disable(dssdev); dssdev->state = OMAP_DSS_DISPLAY_DISABLED; @@ -170,17 +164,6 @@ end: mutex_unlock(&venc_panel.lock); } -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 void venc_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { @@ -222,8 +205,6 @@ static struct omap_dss_driver venc_driver = { .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, diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index 4ea17dc3258..4cb12ce6885 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig @@ -2,7 +2,6 @@ menuconfig FB_OMAP2 tristate "OMAP2+ frame buffer support" depends on FB && OMAP2_DSS && !DRM_OMAP - select OMAP2_VRAM select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index d630b26a005..d30b45d7264 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -28,10 +28,10 @@ #include <linux/omapfb.h> #include <linux/vmalloc.h> #include <linux/export.h> +#include <linux/sizes.h> #include <video/omapdss.h> -#include <plat/vrfb.h> -#include <plat/vram.h> +#include <video/omapvrfb.h> #include "omapfb.h" @@ -211,6 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; + struct omap_dss_device *display = fb2display(fbi); struct omapfb2_mem_region *rg; int r = 0, i; size_t size; @@ -220,6 +221,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) size = PAGE_ALIGN(mi->size); + if (display && display->driver->sync) + display->driver->sync(display); + rg = ofbi->region; down_write_nested(&rg->lock, rg->id); @@ -279,7 +283,7 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) return 0; } -static int omapfb_update_window_nolock(struct fb_info *fbi, +static int omapfb_update_window(struct fb_info *fbi, u32 x, u32 y, u32 w, u32 h) { struct omap_dss_device *display = fb2display(fbi); @@ -299,27 +303,6 @@ static int omapfb_update_window_nolock(struct fb_info *fbi, return display->driver->update(display, x, y, w, h); } -/* This function is exported for SGX driver use */ -int omapfb_update_window(struct fb_info *fbi, - u32 x, u32 y, u32 w, u32 h) -{ - struct omapfb_info *ofbi = FB2OFB(fbi); - struct omapfb2_device *fbdev = ofbi->fbdev; - int r; - - if (!lock_fb_info(fbi)) - return -ENODEV; - omapfb_lock(fbdev); - - r = omapfb_update_window_nolock(fbi, x, y, w, h); - - omapfb_unlock(fbdev); - unlock_fb_info(fbi); - - return r; -} -EXPORT_SYMBOL(omapfb_update_window); - int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode) { @@ -646,7 +629,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; } - r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y, + r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y, p.uwnd_o.width, p.uwnd_o.height); break; @@ -663,7 +646,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; } - r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y, + r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y, p.uwnd.width, p.uwnd.height); break; @@ -853,14 +836,15 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; case OMAPFB_GET_VRAM_INFO: { - unsigned long vram, free, largest; - DBG("ioctl GET_VRAM_INFO\n"); - omap_vram_get_info(&vram, &free, &largest); - p.vram_info.total = vram; - p.vram_info.free = free; - p.vram_info.largest_free_block = largest; + /* + * We don't have the ability to get this vram info anymore. + * Fill in something that should keep the applications working. + */ + p.vram_info.total = SZ_1M * 64; + p.vram_info.free = SZ_1M * 64; + p.vram_info.largest_free_block = SZ_1M * 64; if (copy_to_user((void __user *)arg, &p.vram_info, sizeof(p.vram_info))) diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 16db1589bd9..ca585ef37f2 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -31,9 +31,7 @@ #include <linux/omapfb.h> #include <video/omapdss.h> -#include <plat/cpu.h> -#include <plat/vram.h> -#include <plat/vrfb.h> +#include <video/omapvrfb.h> #include "omapfb.h" @@ -1259,11 +1257,10 @@ static int omapfb_blank(int blank, struct fb_info *fbi) switch (blank) { case FB_BLANK_UNBLANK: - if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) + if (display->state == OMAP_DSS_DISPLAY_ACTIVE) goto exit; - if (display->driver->resume) - r = display->driver->resume(display); + r = display->driver->enable(display); if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && d->update_mode == OMAPFB_AUTO_UPDATE && @@ -1284,8 +1281,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi) if (d->auto_update_work_enabled) omapfb_stop_auto_update(fbdev, display); - if (display->driver->suspend) - r = display->driver->suspend(display); + display->driver->disable(display); break; @@ -1336,24 +1332,25 @@ static void omapfb_free_fbmem(struct fb_info *fbi) rg = ofbi->region; - WARN_ON(atomic_read(&rg->map_count)); - - if (rg->paddr) - if (omap_vram_free(rg->paddr, rg->size)) - dev_err(fbdev->dev, "VRAM FREE failed\n"); + if (rg->token == NULL) + return; - if (rg->vaddr) - iounmap(rg->vaddr); + WARN_ON(atomic_read(&rg->map_count)); if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { /* unmap the 0 angle rotation */ if (rg->vrfb.vaddr[0]) { iounmap(rg->vrfb.vaddr[0]); - omap_vrfb_release_ctx(&rg->vrfb); rg->vrfb.vaddr[0] = NULL; } + + omap_vrfb_release_ctx(&rg->vrfb); } + dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle, + &rg->attrs); + + rg->token = NULL; rg->vaddr = NULL; rg->paddr = 0; rg->alloc = 0; @@ -1388,7 +1385,9 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_mem_region *rg; - void __iomem *vaddr; + void *token; + DEFINE_DMA_ATTRS(attrs); + dma_addr_t dma_handle; int r; rg = ofbi->region; @@ -1403,42 +1402,40 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, size = PAGE_ALIGN(size); - if (!paddr) { - DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); - r = omap_vram_alloc(size, &paddr); - } else { - DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr, - ofbi->id); - r = omap_vram_reserve(paddr, size); - } + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); - if (r) { + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); + + DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); + + token = dma_alloc_attrs(fbdev->dev, size, &dma_handle, + GFP_KERNEL, &attrs); + + if (token == NULL) { dev_err(fbdev->dev, "failed to allocate framebuffer\n"); return -ENOMEM; } - if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) { - vaddr = ioremap_wc(paddr, size); - - if (!vaddr) { - dev_err(fbdev->dev, "failed to ioremap framebuffer\n"); - omap_vram_free(paddr, size); - return -ENOMEM; - } + DBG("allocated VRAM paddr %lx, vaddr %p\n", + (unsigned long)dma_handle, token); - DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr); - } else { + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { r = omap_vrfb_request_ctx(&rg->vrfb); if (r) { + dma_free_attrs(fbdev->dev, size, token, dma_handle, + &attrs); dev_err(fbdev->dev, "vrfb create ctx failed\n"); return r; } - - vaddr = NULL; } - rg->paddr = paddr; - rg->vaddr = vaddr; + rg->attrs = attrs; + rg->token = token; + rg->dma_handle = dma_handle; + + rg->paddr = (unsigned long)dma_handle; + rg->vaddr = (void __iomem *)token; rg->size = size; rg->alloc = 1; @@ -1532,6 +1529,9 @@ static int omapfb_parse_vram_param(const char *param, int max_entries, } + WARN_ONCE(paddr, + "reserving memory at predefined address not supported\n"); + paddrs[fbnum] = paddr; sizes[fbnum] = size; @@ -1611,7 +1611,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; - struct omap_dss_device *display = fb2display(fbi); struct omapfb2_mem_region *rg = ofbi->region; unsigned long old_size = rg->size; unsigned long old_paddr = rg->paddr; @@ -1626,9 +1625,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) if (old_size == size && old_type == type) return 0; - if (display && display->driver->sync) - display->driver->sync(display); - omapfb_free_fbmem(fbi); if (size == 0) { @@ -1883,7 +1879,6 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) } dev_set_drvdata(fbdev->dev, NULL); - kfree(fbdev); } static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) @@ -2259,26 +2254,28 @@ static int omapfb_find_best_mode(struct omap_dss_device *display, { struct fb_monspecs *specs; u8 *edid; - int r, i, best_xres, best_idx, len; + int r, i, best_idx, len; if (!display->driver->read_edid) return -ENODEV; len = 0x80 * 2; edid = kmalloc(len, GFP_KERNEL); + if (edid == NULL) + return -ENOMEM; r = display->driver->read_edid(display, edid, len); if (r < 0) goto err1; specs = kzalloc(sizeof(*specs), GFP_KERNEL); + if (specs == NULL) { + r = -ENOMEM; + goto err1; + } fb_edid_to_monspecs(edid, specs); - if (edid[126] > 0) - fb_edid_add_monspecs(edid + 0x80, specs); - - best_xres = 0; best_idx = -1; for (i = 0; i < specs->modedb_len; ++i) { @@ -2294,16 +2291,20 @@ static int omapfb_find_best_mode(struct omap_dss_device *display, if (m->xres == 2880 || m->xres == 1440) continue; + if (m->vmode & FB_VMODE_INTERLACED || + m->vmode & FB_VMODE_DOUBLE) + continue; + fb_videomode_to_omap_timings(m, display, &t); r = display->driver->check_timings(display, &t); - if (r == 0 && best_xres < m->xres) { - best_xres = m->xres; + if (r == 0) { best_idx = i; + break; } } - if (best_xres == 0) { + if (best_idx == -1) { r = -ENOENT; goto err2; } @@ -2372,15 +2373,62 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, return 0; } +static int omapfb_init_connections(struct omapfb2_device *fbdev, + struct omap_dss_device *def_dssdev) +{ + int i, r; + struct omap_overlay_manager *mgr; + + if (!def_dssdev->output) { + dev_err(fbdev->dev, "no output for the default display\n"); + return -EINVAL; + } + + for (i = 0; i < fbdev->num_displays; ++i) { + struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; + struct omap_dss_output *out = dssdev->output; + + mgr = omap_dss_get_overlay_manager(dssdev->channel); + + if (!mgr || !out) + continue; + + if (mgr->output) + mgr->unset_output(mgr); + + mgr->set_output(mgr, out); + } + + mgr = def_dssdev->output->manager; + + if (!mgr) { + dev_err(fbdev->dev, "no ovl manager for the default display\n"); + return -EINVAL; + } + + for (i = 0; i < fbdev->num_overlays; i++) { + struct omap_overlay *ovl = fbdev->overlays[i]; + + if (ovl->manager) + ovl->unset_manager(ovl); + + r = ovl->set_manager(ovl, mgr); + if (r) + dev_warn(fbdev->dev, + "failed to connect overlay %s to manager %s\n", + ovl->name, mgr->name); + } + + return 0; +} + static int __init omapfb_probe(struct platform_device *pdev) { struct omapfb2_device *fbdev = NULL; int r = 0; int i; - struct omap_overlay *ovl; struct omap_dss_device *def_display; struct omap_dss_device *dssdev; - struct omap_dss_device *ovl_device; DBG("omapfb_probe\n"); @@ -2390,28 +2438,28 @@ static int __init omapfb_probe(struct platform_device *pdev) goto err0; } - fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL); + fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device), + GFP_KERNEL); if (fbdev == NULL) { r = -ENOMEM; goto err0; } - /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE - * available for OMAP2 and OMAP3 - */ - if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) { + if (def_vrfb && !omap_vrfb_supported()) { def_vrfb = 0; dev_warn(&pdev->dev, "VRFB is not supported on this hardware, " "ignoring the module parameter vrfb=y\n"); } + r = omapdss_compat_init(); + if (r) + goto err0; mutex_init(&fbdev->mtx); fbdev->dev = &pdev->dev; platform_set_drvdata(pdev, fbdev); - r = 0; fbdev->num_displays = 0; dssdev = NULL; for_each_dss_dev(dssdev) { @@ -2434,9 +2482,6 @@ static int __init omapfb_probe(struct platform_device *pdev) d->update_mode = OMAPFB_AUTO_UPDATE; } - if (r) - goto cleanup; - if (fbdev->num_displays == 0) { dev_err(&pdev->dev, "no displays\n"); r = -EINVAL; @@ -2451,15 +2496,33 @@ static int __init omapfb_probe(struct platform_device *pdev) for (i = 0; i < fbdev->num_managers; i++) fbdev->managers[i] = omap_dss_get_overlay_manager(i); - /* gfx overlay should be the default one. find a display - * connected to that, and use it as default display */ - ovl = omap_dss_get_overlay(0); - ovl_device = ovl->get_device(ovl); - if (ovl_device) { - def_display = ovl_device; - } else { - dev_warn(&pdev->dev, "cannot find default display\n"); - def_display = NULL; + def_display = NULL; + + for (i = 0; i < fbdev->num_displays; ++i) { + struct omap_dss_device *dssdev; + const char *def_name; + + def_name = omapdss_get_default_display_name(); + + dssdev = fbdev->displays[i].dssdev; + + if (def_name == NULL || + (dssdev->name && strcmp(def_name, dssdev->name) == 0)) { + def_display = dssdev; + break; + } + } + + if (def_display == NULL) { + dev_err(fbdev->dev, "failed to find default display\n"); + r = -EINVAL; + goto cleanup; + } + + r = omapfb_init_connections(fbdev, def_display); + if (r) { + dev_err(fbdev->dev, "failed to init overlay connections\n"); + goto cleanup; } if (def_mode && strlen(def_mode) > 0) { @@ -2510,6 +2573,7 @@ static int __init omapfb_probe(struct platform_device *pdev) cleanup: omapfb_free_resources(fbdev); + omapdss_compat_uninit(); err0: dev_err(&pdev->dev, "failed to setup omapfb\n"); return r; @@ -2525,6 +2589,8 @@ static int __exit omapfb_remove(struct platform_device *pdev) omapfb_free_resources(fbdev); + omapdss_compat_uninit(); + return 0; } diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index e8d8cc76a43..18fa9e1d003 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -30,7 +30,7 @@ #include <linux/omapfb.h> #include <video/omapdss.h> -#include <plat/vrfb.h> +#include <video/omapvrfb.h> #include "omapfb.h" @@ -441,6 +441,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; + struct omap_dss_device *display = fb2display(fbi); struct omapfb2_mem_region *rg; unsigned long size; int r; @@ -455,6 +456,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, if (!lock_fb_info(fbi)) return -ENODEV; + if (display && display->driver->sync) + display->driver->sync(display); + rg = ofbi->region; down_write_nested(&rg->lock, rg->id); diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 5ced9b334d3..623cd872a36 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -28,6 +28,8 @@ #endif #include <linux/rwsem.h> +#include <linux/dma-attrs.h> +#include <linux/dma-mapping.h> #include <video/omapdss.h> @@ -49,6 +51,9 @@ extern bool omapfb_debug; struct omapfb2_mem_region { int id; + struct dma_attrs attrs; + void *token; + dma_addr_t dma_handle; u32 paddr; void __iomem *vaddr; struct vrfb vrfb; @@ -124,9 +129,6 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev); int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg); -int omapfb_update_window(struct fb_info *fbi, - u32 x, u32 y, u32 w, u32 h); - int dss_mode_to_fb_mode(enum omap_color_mode dssmode, struct fb_var_screeninfo *var); @@ -144,16 +146,16 @@ int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode); static inline struct omap_dss_device *fb2display(struct fb_info *fbi) { struct omapfb_info *ofbi = FB2OFB(fbi); - int i; + struct omap_overlay *ovl; /* XXX: returns the display connected to first attached overlay */ - for (i = 0; i < ofbi->num_overlays; i++) { - struct omap_overlay *ovl = ofbi->overlays[i]; - return ovl->get_device(ovl); - } + if (ofbi->num_overlays == 0) + return NULL; - return NULL; + ovl = ofbi->overlays[0]; + + return ovl->get_device(ovl); } static inline struct omapfb_display_data *get_display_data( diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c deleted file mode 100644 index f2b15c4a75b..00000000000 --- a/drivers/video/omap2/vram.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - * VRAM manager for OMAP - * - * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/*#define DEBUG*/ - -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/seq_file.h> -#include <linux/memblock.h> -#include <linux/completion.h> -#include <linux/debugfs.h> -#include <linux/jiffies.h> -#include <linux/module.h> - -#include <asm/setup.h> - -#include <plat/vram.h> - -#ifdef DEBUG -#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__) -#else -#define DBG(format, ...) -#endif - -/* postponed regions are used to temporarily store region information at boot - * time when we cannot yet allocate the region list */ -#define MAX_POSTPONED_REGIONS 10 - -static bool vram_initialized; -static int postponed_cnt; -static struct { - unsigned long paddr; - size_t size; -} postponed_regions[MAX_POSTPONED_REGIONS]; - -struct vram_alloc { - struct list_head list; - unsigned long paddr; - unsigned pages; -}; - -struct vram_region { - struct list_head list; - struct list_head alloc_list; - unsigned long paddr; - unsigned pages; -}; - -static DEFINE_MUTEX(region_mutex); -static LIST_HEAD(region_list); - -static struct vram_region *omap_vram_create_region(unsigned long paddr, - unsigned pages) -{ - struct vram_region *rm; - - rm = kzalloc(sizeof(*rm), GFP_KERNEL); - - if (rm) { - INIT_LIST_HEAD(&rm->alloc_list); - rm->paddr = paddr; - rm->pages = pages; - } - - return rm; -} - -#if 0 -static void omap_vram_free_region(struct vram_region *vr) -{ - list_del(&vr->list); - kfree(vr); -} -#endif - -static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr, - unsigned long paddr, unsigned pages) -{ - struct vram_alloc *va; - struct vram_alloc *new; - - new = kzalloc(sizeof(*va), GFP_KERNEL); - - if (!new) - return NULL; - - new->paddr = paddr; - new->pages = pages; - - list_for_each_entry(va, &vr->alloc_list, list) { - if (va->paddr > new->paddr) - break; - } - - list_add_tail(&new->list, &va->list); - - return new; -} - -static void omap_vram_free_allocation(struct vram_alloc *va) -{ - list_del(&va->list); - kfree(va); -} - -int omap_vram_add_region(unsigned long paddr, size_t size) -{ - struct vram_region *rm; - unsigned pages; - - if (vram_initialized) { - DBG("adding region paddr %08lx size %d\n", - paddr, size); - - size &= PAGE_MASK; - pages = size >> PAGE_SHIFT; - - rm = omap_vram_create_region(paddr, pages); - if (rm == NULL) - return -ENOMEM; - - list_add(&rm->list, ®ion_list); - } else { - if (postponed_cnt == MAX_POSTPONED_REGIONS) - return -ENOMEM; - - postponed_regions[postponed_cnt].paddr = paddr; - postponed_regions[postponed_cnt].size = size; - - ++postponed_cnt; - } - return 0; -} - -int omap_vram_free(unsigned long paddr, size_t size) -{ - struct vram_region *rm; - struct vram_alloc *alloc; - unsigned start, end; - - DBG("free mem paddr %08lx size %d\n", paddr, size); - - size = PAGE_ALIGN(size); - - mutex_lock(®ion_mutex); - - list_for_each_entry(rm, ®ion_list, list) { - list_for_each_entry(alloc, &rm->alloc_list, list) { - start = alloc->paddr; - end = alloc->paddr + (alloc->pages >> PAGE_SHIFT); - - if (start >= paddr && end < paddr + size) - goto found; - } - } - - mutex_unlock(®ion_mutex); - return -EINVAL; - -found: - omap_vram_free_allocation(alloc); - - mutex_unlock(®ion_mutex); - return 0; -} -EXPORT_SYMBOL(omap_vram_free); - -static int _omap_vram_reserve(unsigned long paddr, unsigned pages) -{ - struct vram_region *rm; - struct vram_alloc *alloc; - size_t size; - - size = pages << PAGE_SHIFT; - - list_for_each_entry(rm, ®ion_list, list) { - unsigned long start, end; - - DBG("checking region %lx %d\n", rm->paddr, rm->pages); - - start = rm->paddr; - end = start + (rm->pages << PAGE_SHIFT) - 1; - if (start > paddr || end < paddr + size - 1) - continue; - - DBG("block ok, checking allocs\n"); - - list_for_each_entry(alloc, &rm->alloc_list, list) { - end = alloc->paddr - 1; - - if (start <= paddr && end >= paddr + size - 1) - goto found; - - start = alloc->paddr + (alloc->pages << PAGE_SHIFT); - } - - end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1; - - if (!(start <= paddr && end >= paddr + size - 1)) - continue; -found: - DBG("found area start %lx, end %lx\n", start, end); - - if (omap_vram_create_allocation(rm, paddr, pages) == NULL) - return -ENOMEM; - - return 0; - } - - return -ENOMEM; -} - -int omap_vram_reserve(unsigned long paddr, size_t size) -{ - unsigned pages; - int r; - - DBG("reserve mem paddr %08lx size %d\n", paddr, size); - - size = PAGE_ALIGN(size); - pages = size >> PAGE_SHIFT; - - mutex_lock(®ion_mutex); - - r = _omap_vram_reserve(paddr, pages); - - mutex_unlock(®ion_mutex); - - return r; -} -EXPORT_SYMBOL(omap_vram_reserve); - -static int _omap_vram_alloc(unsigned pages, unsigned long *paddr) -{ - struct vram_region *rm; - struct vram_alloc *alloc; - - list_for_each_entry(rm, ®ion_list, list) { - unsigned long start, end; - - DBG("checking region %lx %d\n", rm->paddr, rm->pages); - - start = rm->paddr; - - list_for_each_entry(alloc, &rm->alloc_list, list) { - end = alloc->paddr; - - if (end - start >= pages << PAGE_SHIFT) - goto found; - - start = alloc->paddr + (alloc->pages << PAGE_SHIFT); - } - - end = rm->paddr + (rm->pages << PAGE_SHIFT); -found: - if (end - start < pages << PAGE_SHIFT) - continue; - - DBG("found %lx, end %lx\n", start, end); - - alloc = omap_vram_create_allocation(rm, start, pages); - if (alloc == NULL) - return -ENOMEM; - - *paddr = start; - - return 0; - } - - return -ENOMEM; -} - -int omap_vram_alloc(size_t size, unsigned long *paddr) -{ - unsigned pages; - int r; - - BUG_ON(!size); - - DBG("alloc mem size %d\n", size); - - size = PAGE_ALIGN(size); - pages = size >> PAGE_SHIFT; - - mutex_lock(®ion_mutex); - - r = _omap_vram_alloc(pages, paddr); - - mutex_unlock(®ion_mutex); - - return r; -} -EXPORT_SYMBOL(omap_vram_alloc); - -void omap_vram_get_info(unsigned long *vram, - unsigned long *free_vram, - unsigned long *largest_free_block) -{ - struct vram_region *vr; - struct vram_alloc *va; - - *vram = 0; - *free_vram = 0; - *largest_free_block = 0; - - mutex_lock(®ion_mutex); - - list_for_each_entry(vr, ®ion_list, list) { - unsigned free; - unsigned long pa; - - pa = vr->paddr; - *vram += vr->pages << PAGE_SHIFT; - - list_for_each_entry(va, &vr->alloc_list, list) { - free = va->paddr - pa; - *free_vram += free; - if (free > *largest_free_block) - *largest_free_block = free; - pa = va->paddr + (va->pages << PAGE_SHIFT); - } - - free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa; - *free_vram += free; - if (free > *largest_free_block) - *largest_free_block = free; - } - - mutex_unlock(®ion_mutex); -} -EXPORT_SYMBOL(omap_vram_get_info); - -#if defined(CONFIG_DEBUG_FS) -static int vram_debug_show(struct seq_file *s, void *unused) -{ - struct vram_region *vr; - struct vram_alloc *va; - unsigned size; - - mutex_lock(®ion_mutex); - - list_for_each_entry(vr, ®ion_list, list) { - size = vr->pages << PAGE_SHIFT; - seq_printf(s, "%08lx-%08lx (%d bytes)\n", - vr->paddr, vr->paddr + size - 1, - size); - - list_for_each_entry(va, &vr->alloc_list, list) { - size = va->pages << PAGE_SHIFT; - seq_printf(s, " %08lx-%08lx (%d bytes)\n", - va->paddr, va->paddr + size - 1, - size); - } - } - - mutex_unlock(®ion_mutex); - - return 0; -} - -static int vram_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, vram_debug_show, inode->i_private); -} - -static const struct file_operations vram_debug_fops = { - .open = vram_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init omap_vram_create_debugfs(void) -{ - struct dentry *d; - - d = debugfs_create_file("vram", S_IRUGO, NULL, - NULL, &vram_debug_fops); - if (IS_ERR(d)) - return PTR_ERR(d); - - return 0; -} -#endif - -static __init int omap_vram_init(void) -{ - int i; - - vram_initialized = 1; - - for (i = 0; i < postponed_cnt; i++) - omap_vram_add_region(postponed_regions[i].paddr, - postponed_regions[i].size); - -#ifdef CONFIG_DEBUG_FS - if (omap_vram_create_debugfs()) - pr_err("VRAM: Failed to create debugfs file\n"); -#endif - - return 0; -} - -arch_initcall(omap_vram_init); - -/* boottime vram alloc stuff */ - -/* set from board file */ -static u32 omap_vram_sdram_start __initdata; -static u32 omap_vram_sdram_size __initdata; - -/* set from kernel cmdline */ -static u32 omap_vram_def_sdram_size __initdata; -static u32 omap_vram_def_sdram_start __initdata; - -static int __init omap_vram_early_vram(char *p) -{ - omap_vram_def_sdram_size = memparse(p, &p); - if (*p == ',') - omap_vram_def_sdram_start = simple_strtoul(p + 1, &p, 16); - return 0; -} -early_param("vram", omap_vram_early_vram); - -/* - * Called from map_io. We need to call to this early enough so that we - * can reserve the fixed SDRAM regions before VM could get hold of them. - */ -void __init omap_vram_reserve_sdram_memblock(void) -{ - u32 paddr; - u32 size = 0; - - /* cmdline arg overrides the board file definition */ - if (omap_vram_def_sdram_size) { - size = omap_vram_def_sdram_size; - paddr = omap_vram_def_sdram_start; - } - - if (!size) { - size = omap_vram_sdram_size; - paddr = omap_vram_sdram_start; - } - -#ifdef CONFIG_OMAP2_VRAM_SIZE - if (!size) { - size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024; - paddr = 0; - } -#endif - - if (!size) - return; - - size = ALIGN(size, SZ_2M); - - if (paddr) { - if (paddr & ~PAGE_MASK) { - pr_err("VRAM start address 0x%08x not page aligned\n", - paddr); - return; - } - - if (!memblock_is_region_memory(paddr, size)) { - pr_err("Illegal SDRAM region 0x%08x..0x%08x for VRAM\n", - paddr, paddr + size - 1); - return; - } - - if (memblock_is_region_reserved(paddr, size)) { - pr_err("FB: failed to reserve VRAM - busy\n"); - return; - } - - if (memblock_reserve(paddr, size) < 0) { - pr_err("FB: failed to reserve VRAM - no memory\n"); - return; - } - } else { - paddr = memblock_alloc(size, SZ_2M); - } - - memblock_free(paddr, size); - memblock_remove(paddr, size); - - omap_vram_add_region(paddr, size); - - pr_info("Reserving %u bytes SDRAM for VRAM\n", size); -} - -void __init omap_vram_set_sdram_vram(u32 size, u32 start) -{ - omap_vram_sdram_start = start; - omap_vram_sdram_size = size; -} diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c index 7e990220ad2..5d8fdac3b80 100644 --- a/drivers/video/omap2/vrfb.c +++ b/drivers/video/omap2/vrfb.c @@ -26,9 +26,9 @@ #include <linux/io.h> #include <linux/bitops.h> #include <linux/mutex.h> +#include <linux/platform_device.h> -#include <plat/vrfb.h> -#include <plat/sdrc.h> +#include <video/omapvrfb.h> #ifdef DEBUG #define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__) @@ -36,10 +36,10 @@ #define DBG(format, ...) #endif -#define SMS_ROT_VIRT_BASE(context, rot) \ - (((context >= 4) ? 0xD0000000 : 0x70000000) \ - + (0x4000000 * (context)) \ - + (0x1000000 * (rot))) +#define SMS_ROT_CONTROL(context) (0x0 + 0x10 * context) +#define SMS_ROT_SIZE(context) (0x4 + 0x10 * context) +#define SMS_ROT_PHYSICAL_BA(context) (0x8 + 0x10 * context) +#define SMS_ROT_VIRT_BASE(rot) (0x1000000 * (rot)) #define OMAP_VRFB_SIZE (2048 * 2048 * 4) @@ -53,10 +53,16 @@ #define SMS_PW_OFFSET 4 #define SMS_PS_OFFSET 0 -#define VRFB_NUM_CTXS 12 /* bitmap of reserved contexts */ static unsigned long ctx_map; +struct vrfb_ctx { + u32 base; + u32 physical_ba; + u32 control; + u32 size; +}; + static DEFINE_MUTEX(ctx_lock); /* @@ -65,17 +71,34 @@ static DEFINE_MUTEX(ctx_lock); * we don't need locking, since no drivers will run until after the wake-up * has finished. */ -static struct { - u32 physical_ba; - u32 control; - u32 size; -} vrfb_hw_context[VRFB_NUM_CTXS]; + +static void __iomem *vrfb_base; + +static int num_ctxs; +static struct vrfb_ctx *ctxs; + +static bool vrfb_loaded; + +static void omap2_sms_write_rot_control(u32 val, unsigned ctx) +{ + __raw_writel(val, vrfb_base + SMS_ROT_CONTROL(ctx)); +} + +static void omap2_sms_write_rot_size(u32 val, unsigned ctx) +{ + __raw_writel(val, vrfb_base + SMS_ROT_SIZE(ctx)); +} + +static void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx) +{ + __raw_writel(val, vrfb_base + SMS_ROT_PHYSICAL_BA(ctx)); +} static inline void restore_hw_context(int ctx) { - omap2_sms_write_rot_control(vrfb_hw_context[ctx].control, ctx); - omap2_sms_write_rot_size(vrfb_hw_context[ctx].size, ctx); - omap2_sms_write_rot_physical_ba(vrfb_hw_context[ctx].physical_ba, ctx); + omap2_sms_write_rot_control(ctxs[ctx].control, ctx); + omap2_sms_write_rot_size(ctxs[ctx].size, ctx); + omap2_sms_write_rot_physical_ba(ctxs[ctx].physical_ba, ctx); } static u32 get_image_width_roundup(u16 width, u8 bytespp) @@ -196,9 +219,9 @@ void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr, control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET; control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET; - vrfb_hw_context[ctx].physical_ba = paddr; - vrfb_hw_context[ctx].size = size; - vrfb_hw_context[ctx].control = control; + ctxs[ctx].physical_ba = paddr; + ctxs[ctx].size = size; + ctxs[ctx].control = control; omap2_sms_write_rot_physical_ba(paddr, ctx); omap2_sms_write_rot_size(size, ctx); @@ -274,11 +297,11 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb) mutex_lock(&ctx_lock); - for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx) + for (ctx = 0; ctx < num_ctxs; ++ctx) if ((ctx_map & (1 << ctx)) == 0) break; - if (ctx == VRFB_NUM_CTXS) { + if (ctx == num_ctxs) { pr_err("vrfb: no free contexts\n"); r = -EBUSY; goto out; @@ -293,7 +316,7 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb) vrfb->context = ctx; for (rot = 0; rot < 4; ++rot) { - paddr = SMS_ROT_VIRT_BASE(ctx, rot); + paddr = ctxs[ctx].base + SMS_ROT_VIRT_BASE(rot); if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) { pr_err("vrfb: failed to reserve VRFB " "area for ctx %d, rotation %d\n", @@ -314,3 +337,80 @@ out: return r; } EXPORT_SYMBOL(omap_vrfb_request_ctx); + +bool omap_vrfb_supported(void) +{ + return vrfb_loaded; +} +EXPORT_SYMBOL(omap_vrfb_supported); + +static int __init vrfb_probe(struct platform_device *pdev) +{ + struct resource *mem; + int i; + + /* first resource is the register res, the rest are vrfb contexts */ + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "can't get vrfb base address\n"); + return -EINVAL; + } + + vrfb_base = devm_request_and_ioremap(&pdev->dev, mem); + if (!vrfb_base) { + dev_err(&pdev->dev, "can't ioremap vrfb memory\n"); + return -ENOMEM; + } + + num_ctxs = pdev->num_resources - 1; + + ctxs = devm_kzalloc(&pdev->dev, + sizeof(struct vrfb_ctx) * num_ctxs, + GFP_KERNEL); + + if (!ctxs) + return -ENOMEM; + + for (i = 0; i < num_ctxs; ++i) { + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i); + if (!mem) { + dev_err(&pdev->dev, "can't get vrfb ctx %d address\n", + i); + return -EINVAL; + } + + ctxs[i].base = mem->start; + } + + vrfb_loaded = true; + + return 0; +} + +static void __exit vrfb_remove(struct platform_device *pdev) +{ + vrfb_loaded = false; +} + +static struct platform_driver vrfb_driver = { + .driver.name = "omapvrfb", + .remove = __exit_p(vrfb_remove), +}; + +static int __init vrfb_init(void) +{ + return platform_driver_probe(&vrfb_driver, &vrfb_probe); +} + +static void __exit vrfb_exit(void) +{ + platform_driver_unregister(&vrfb_driver); +} + +module_init(vrfb_init); +module_exit(vrfb_exit); + +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); +MODULE_DESCRIPTION("OMAP VRFB"); +MODULE_LICENSE("GPL v2"); |