diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-21 13:48:00 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-21 13:48:00 -0700 |
commit | 266c73b77706f2d05b4a3e70a5bb702ed35431d6 (patch) | |
tree | 381461b90a8bd10c0c36b0cdbb2e6e4bbf6c5e87 /drivers/gpu/drm/omapdrm | |
parent | 2c856e14dad8cb1b085ae1f30c5e125c6d46019b (diff) | |
parent | 568d7c764ae01f3706085ac8f0d8a8ac7e826bd7 (diff) | |
download | linux-266c73b77706f2d05b4a3e70a5bb702ed35431d6.tar.gz linux-266c73b77706f2d05b4a3e70a5bb702ed35431d6.tar.bz2 linux-266c73b77706f2d05b4a3e70a5bb702ed35431d6.zip |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"This is the main drm pull request for 4.6 kernel.
Overall the coolest thing here for me is the nouveau maxwell signed
firmware support from NVidia, it's taken a long while to extract this
from them.
I also wish the ARM vendors just designed one set of display IP, ARM
display block proliferation is definitely increasing.
Core:
- drm_event cleanups
- Internal API cleanup making mode_fixup optional.
- Apple GMUX vga switcheroo support.
- DP AUX testing interface
Panel:
- Refactoring of DSI core for use over more transports.
New driver:
- ARM hdlcd driver
i915:
- FBC/PSR (framebuffer compression, panel self refresh) enabled by default.
- Ongoing atomic display support work
- Ongoing runtime PM work
- Pixel clock limit checks
- VBT DSI description support
- GEM fixes
- GuC firmware scheduler enhancements
amdkfd:
- Deferred probing fixes to avoid make file or link ordering.
amdgpu/radeon:
- ACP support for i2s audio support.
- Command Submission/GPU scheduler/GPUVM optimisations
- Initial GPU reset support for amdgpu
vmwgfx:
- Support for DX10 gen mipmaps
- Pageflipping and other fixes.
exynos:
- Exynos5420 SoC support for FIMD
- Exynos5422 SoC support for MIPI-DSI
nouveau:
- GM20x secure boot support - adds acceleration for Maxwell GPUs.
- GM200 support
- GM20B clock driver support
- Power sensors work
etnaviv:
- Correctness fixes for GPU cache flushing
- Better support for i.MX6 systems.
imx-drm:
- VBlank IRQ support
- Fence support
- OF endpoint support
msm:
- HDMI support for 8996 (snapdragon 820)
- Adreno 430 support
- Timestamp queries support
virtio-gpu:
- Fixes for Android support.
rockchip:
- Add support for Innosilicion HDMI
rcar-du:
- Support for 4 crtcs
- R8A7795 support
- RCar Gen 3 support
omapdrm:
- HDMI interlace output support
- dma-buf import support
- Refactoring to remove a lot of legacy code.
tilcdc:
- Rewrite of pageflipping code
- dma-buf support
- pinctrl support
vc4:
- HDMI modesetting bug fixes
- Significant 3D performance improvement.
fsl-dcu (FreeScale):
- Lots of fixes
tegra:
- Two small fixes
sti:
- Atomic support for planes
- Improved HDMI support"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (1063 commits)
drm/amdgpu: release_pages requires linux/pagemap.h
drm/sti: restore mode_fixup callback
drm/amdgpu/gfx7: add MTYPE definition
drm/amdgpu: removing BO_VAs shouldn't be interruptible
drm/amd/powerplay: show uvd/vce power gate enablement for tonga.
drm/amd/powerplay: show uvd/vce power gate info for fiji
drm/amdgpu: use sched fence if possible
drm/amdgpu: move ib.fence to job.fence
drm/amdgpu: give a fence param to ib_free
drm/amdgpu: include the right version of gmc header files for iceland
drm/radeon: fix indentation.
drm/amd/powerplay: add uvd/vce dpm enabling flag to fix the performance issue for CZ
drm/amdgpu: switch back to 32bit hw fences v2
drm/amdgpu: remove amdgpu_fence_is_signaled
drm/amdgpu: drop the extra fence range check v2
drm/amdgpu: signal fences directly in amdgpu_fence_process
drm/amdgpu: cleanup amdgpu_fence_wait_empty v2
drm/amdgpu: keep all fences in an RCU protected array v2
drm/amdgpu: add number of hardware submissions to amdgpu_fence_driver_init_ring
drm/amdgpu: RCU protected amd_sched_fence_release
...
Diffstat (limited to 'drivers/gpu/drm/omapdrm')
46 files changed, 863 insertions, 5343 deletions
diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index 336ad4de9981..73241c4eb7aa 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -2,7 +2,6 @@ config DRM_OMAP tristate "OMAP DRM" depends on DRM depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM - select OMAP2_DSS select DRM_KMS_HELPER select DRM_KMS_FB_HELPER select FB_SYS_FILLRECT diff --git a/drivers/gpu/drm/omapdrm/Makefile b/drivers/gpu/drm/omapdrm/Makefile index fe4c2228bc18..48b7b750c05c 100644 --- a/drivers/gpu/drm/omapdrm/Makefile +++ b/drivers/gpu/drm/omapdrm/Makefile @@ -6,7 +6,7 @@ obj-y += dss/ obj-y += displays/ -ccflags-y := -Iinclude/drm -Werror +ccflags-y := -Iinclude/drm omapdrm-y := omap_drv.o \ omap_irq.o \ omap_debugfs.o \ diff --git a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c index d811e6dcaef7..747f26a55e43 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c @@ -236,46 +236,6 @@ static struct omap_dss_driver dvic_driver = { .detect = dvic_detect, }; -static int dvic_probe_pdata(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct connector_dvi_platform_data *pdata; - struct omap_dss_device *in, *dssdev; - int i2c_bus_num; - - pdata = dev_get_platdata(&pdev->dev); - i2c_bus_num = pdata->i2c_bus_num; - - if (i2c_bus_num != -1) { - struct i2c_adapter *adapter; - - adapter = i2c_get_adapter(i2c_bus_num); - if (!adapter) { - dev_err(&pdev->dev, - "Failed to get I2C adapter, bus %d\n", - i2c_bus_num); - return -EPROBE_DEFER; - } - - ddata->i2c_adapter = adapter; - } - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - i2c_put_adapter(ddata->i2c_adapter); - - dev_err(&pdev->dev, "Failed to find video source\n"); - return -EPROBE_DEFER; - } - - ddata->in = in; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - return 0; -} - static int dvic_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); @@ -319,17 +279,12 @@ static int dvic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (dev_get_platdata(&pdev->dev)) { - r = dvic_probe_pdata(pdev); - if (r) - return r; - } else if (pdev->dev.of_node) { - r = dvic_probe_of(pdev); - if (r) - return r; - } else { + if (!pdev->dev.of_node) return -ENODEV; - } + + r = dvic_probe_of(pdev); + if (r) + return r; ddata->timings = dvic_default_timings; diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c index 6ee4129bc0c0..225fd8d6ab31 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c @@ -206,30 +206,6 @@ static struct omap_dss_driver hdmic_driver = { .set_hdmi_infoframe = hdmic_set_infoframe, }; -static int hdmic_probe_pdata(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct connector_hdmi_platform_data *pdata; - struct omap_dss_device *in, *dssdev; - - pdata = dev_get_platdata(&pdev->dev); - - ddata->hpd_gpio = -ENODEV; - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&pdev->dev, "Failed to find video source\n"); - return -EPROBE_DEFER; - } - - ddata->in = in; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - return 0; -} - static int hdmic_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); @@ -268,17 +244,12 @@ static int hdmic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->dev = &pdev->dev; - if (dev_get_platdata(&pdev->dev)) { - r = hdmic_probe_pdata(pdev); - if (r) - return r; - } else if (pdev->dev.of_node) { - r = hdmic_probe_of(pdev); - if (r) - return r; - } else { + if (!pdev->dev.of_node) return -ENODEV; - } + + r = hdmic_probe_of(pdev); + if (r) + return r; if (gpio_is_valid(ddata->hpd_gpio)) { r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c index d9048b3df495..2fd5602880a7 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c @@ -166,32 +166,6 @@ static const struct omapdss_dvi_ops tfp410_dvi_ops = { .get_timings = tfp410_get_timings, }; -static int tfp410_probe_pdata(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct encoder_tfp410_platform_data *pdata; - struct omap_dss_device *dssdev, *in; - - pdata = dev_get_platdata(&pdev->dev); - - ddata->pd_gpio = pdata->power_down_gpio; - - ddata->data_lines = pdata->data_lines; - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&pdev->dev, "Failed to find video source\n"); - return -ENODEV; - } - - ddata->in = in; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - return 0; -} - static int tfp410_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); @@ -231,17 +205,12 @@ static int tfp410_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (dev_get_platdata(&pdev->dev)) { - r = tfp410_probe_pdata(pdev); - if (r) - return r; - } else if (pdev->dev.of_node) { - r = tfp410_probe_of(pdev); - if (r) - return r; - } else { + if (!pdev->dev.of_node) return -ENODEV; - } + + r = tfp410_probe_of(pdev); + if (r) + return r; if (gpio_is_valid(ddata->pd_gpio)) { r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio, diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index 990af6baeb0f..916a89978387 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -13,9 +13,8 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/gpio.h> #include <linux/platform_device.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -24,9 +23,9 @@ struct panel_drv_data { struct omap_dss_device dssdev; struct omap_dss_device *in; - int ct_cp_hpd_gpio; - int ls_oe_gpio; - int hpd_gpio; + struct gpio_desc *ct_cp_hpd_gpio; + struct gpio_desc *ls_oe_gpio; + struct gpio_desc *hpd_gpio; struct omap_video_timings timings; }; @@ -47,7 +46,7 @@ static int tpd_connect(struct omap_dss_device *dssdev, dst->src = dssdev; dssdev->dst = dst; - gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1); + gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1); /* DC-DC converter needs at max 300us to get to 90% of 5V */ udelay(300); @@ -65,7 +64,7 @@ static void tpd_disconnect(struct omap_dss_device *dssdev, if (dst != dssdev->dst) return; - gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0); + gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0); dst->src = NULL; dssdev->dst = NULL; @@ -145,16 +144,14 @@ static int tpd_read_edid(struct omap_dss_device *dssdev, struct omap_dss_device *in = ddata->in; int r; - if (!gpio_get_value_cansleep(ddata->hpd_gpio)) + if (!gpiod_get_value_cansleep(ddata->hpd_gpio)) return -ENODEV; - if (gpio_is_valid(ddata->ls_oe_gpio)) - gpio_set_value_cansleep(ddata->ls_oe_gpio, 1); + gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1); r = in->ops.hdmi->read_edid(in, edid, len); - if (gpio_is_valid(ddata->ls_oe_gpio)) - gpio_set_value_cansleep(ddata->ls_oe_gpio, 0); + gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0); return r; } @@ -163,7 +160,7 @@ static bool tpd_detect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - return gpio_get_value_cansleep(ddata->hpd_gpio); + return gpiod_get_value_cansleep(ddata->hpd_gpio); } static int tpd_set_infoframe(struct omap_dss_device *dssdev, @@ -201,63 +198,11 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = { .set_hdmi_mode = tpd_set_hdmi_mode, }; -static int tpd_probe_pdata(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct encoder_tpd12s015_platform_data *pdata; - struct omap_dss_device *dssdev, *in; - - pdata = dev_get_platdata(&pdev->dev); - - ddata->ct_cp_hpd_gpio = pdata->ct_cp_hpd_gpio; - ddata->ls_oe_gpio = pdata->ls_oe_gpio; - ddata->hpd_gpio = pdata->hpd_gpio; - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&pdev->dev, "Failed to find video source\n"); - return -ENODEV; - } - - ddata->in = in; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - return 0; -} - static int tpd_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; struct omap_dss_device *in; - int gpio; - - /* CT CP HPD GPIO */ - gpio = of_get_gpio(node, 0); - if (!gpio_is_valid(gpio)) { - dev_err(&pdev->dev, "failed to parse CT CP HPD gpio\n"); - return gpio; - } - ddata->ct_cp_hpd_gpio = gpio; - - /* LS OE GPIO */ - gpio = of_get_gpio(node, 1); - if (gpio_is_valid(gpio) || gpio == -ENOENT) { - ddata->ls_oe_gpio = gpio; - } else { - dev_err(&pdev->dev, "failed to parse LS OE gpio\n"); - return gpio; - } - - /* HPD GPIO */ - gpio = of_get_gpio(node, 2); - if (!gpio_is_valid(gpio)) { - dev_err(&pdev->dev, "failed to parse HPD gpio\n"); - return gpio; - } - ddata->hpd_gpio = gpio; in = omapdss_of_find_source_for_first_ep(node); if (IS_ERR(in)) { @@ -275,6 +220,7 @@ static int tpd_probe(struct platform_device *pdev) struct omap_dss_device *in, *dssdev; struct panel_drv_data *ddata; int r; + struct gpio_desc *gpio; ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) @@ -282,35 +228,35 @@ static int tpd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (dev_get_platdata(&pdev->dev)) { - r = tpd_probe_pdata(pdev); - if (r) - return r; - } else if (pdev->dev.of_node) { - r = tpd_probe_of(pdev); - if (r) - return r; - } else { + if (!pdev->dev.of_node) return -ENODEV; - } - r = devm_gpio_request_one(&pdev->dev, ddata->ct_cp_hpd_gpio, - GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd"); + r = tpd_probe_of(pdev); if (r) + return r; + + + gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0, + GPIOD_OUT_LOW); + if (IS_ERR(gpio)) goto err_gpio; - if (gpio_is_valid(ddata->ls_oe_gpio)) { - r = devm_gpio_request_one(&pdev->dev, ddata->ls_oe_gpio, - GPIOF_OUT_INIT_LOW, "hdmi_ls_oe"); - if (r) - goto err_gpio; - } + ddata->ct_cp_hpd_gpio = gpio; - r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, - GPIOF_DIR_IN, "hdmi_hpd"); - if (r) + gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1, + GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + goto err_gpio; + + ddata->ls_oe_gpio = gpio; + + gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2, + GPIOD_IN); + if (IS_ERR(gpio)) goto err_gpio; + ddata->hpd_gpio = gpio; + dssdev = &ddata->dssdev; dssdev->ops.hdmi = &tpd_hdmi_ops; dssdev->dev = &pdev->dev; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 3414c2609320..36485c2137ce 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -1127,40 +1127,6 @@ static struct omap_dss_driver dsicm_ops = { .memory_read = dsicm_memory_read, }; -static int dsicm_probe_pdata(struct platform_device *pdev) -{ - const struct panel_dsicm_platform_data *pdata; - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct omap_dss_device *dssdev, *in; - - pdata = dev_get_platdata(&pdev->dev); - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&pdev->dev, "failed to find video source\n"); - return -EPROBE_DEFER; - } - ddata->in = in; - - ddata->reset_gpio = pdata->reset_gpio; - - if (pdata->use_ext_te) - ddata->ext_te_gpio = pdata->ext_te_gpio; - else - ddata->ext_te_gpio = -1; - - ddata->ulps_timeout = pdata->ulps_timeout; - - ddata->use_dsi_backlight = pdata->use_dsi_backlight; - - ddata->pin_config = pdata->pin_config; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - return 0; -} - static int dsicm_probe_of(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -1214,17 +1180,12 @@ static int dsicm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->pdev = pdev; - if (dev_get_platdata(dev)) { - r = dsicm_probe_pdata(pdev); - if (r) - return r; - } else if (pdev->dev.of_node) { - r = dsicm_probe_of(pdev); - if (r) - return r; - } else { + if (!pdev->dev.of_node) return -ENODEV; - } + + r = dsicm_probe_of(pdev); + if (r) + return r; ddata->timings.x_res = 864; ddata->timings.y_res = 480; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c index 18eb60e9c9ec..458f77bc473d 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c @@ -240,44 +240,6 @@ static struct omap_dss_driver lb035q02_ops = { .get_resolution = omapdss_default_get_resolution, }; -static int lb035q02_probe_pdata(struct spi_device *spi) -{ - const struct panel_lb035q02_platform_data *pdata; - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev, *in; - int r; - - pdata = dev_get_platdata(&spi->dev); - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&spi->dev, "failed to find video source '%s'\n", - pdata->source); - return -EPROBE_DEFER; - } - - ddata->in = in; - - ddata->data_lines = pdata->data_lines; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - r = devm_gpio_request_one(&spi->dev, pdata->enable_gpio, - GPIOF_OUT_INIT_LOW, "panel enable"); - if (r) - goto err_gpio; - - ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio); - - ddata->backlight_gpio = pdata->backlight_gpio; - - return 0; -err_gpio: - omap_dss_put_device(ddata->in); - return r; -} - static int lb035q02_probe_of(struct spi_device *spi) { struct device_node *node = spi->dev.of_node; @@ -320,17 +282,12 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) ddata->spi = spi; - if (dev_get_platdata(&spi->dev)) { - r = lb035q02_probe_pdata(spi); - if (r) - return r; - } else if (spi->dev.of_node) { - r = lb035q02_probe_of(spi); - if (r) - return r; - } else { + if (!spi->dev.of_node) return -ENODEV; - } + + r = lb035q02_probe_of(spi); + if (r) + return r; if (gpio_is_valid(ddata->backlight_gpio)) { r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio, diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c index 8a928c9a2fc9..780cb263a318 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c @@ -19,7 +19,6 @@ #include <linux/of_gpio.h> #include <video/omapdss.h> -#include <video/omap-panel-data.h> struct panel_drv_data { struct omap_dss_device dssdev; @@ -232,34 +231,6 @@ static struct omap_dss_driver nec_8048_ops = { .get_resolution = omapdss_default_get_resolution, }; - -static int nec_8048_probe_pdata(struct spi_device *spi) -{ - const struct panel_nec_nl8048hl11_platform_data *pdata; - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev, *in; - - pdata = dev_get_platdata(&spi->dev); - - ddata->qvga_gpio = pdata->qvga_gpio; - ddata->res_gpio = pdata->res_gpio; - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&spi->dev, "failed to find video source '%s'\n", - pdata->source); - return -EPROBE_DEFER; - } - ddata->in = in; - - ddata->data_lines = pdata->data_lines; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - return 0; -} - static int nec_8048_probe_of(struct spi_device *spi) { struct device_node *node = spi->dev.of_node; @@ -315,17 +286,12 @@ static int nec_8048_probe(struct spi_device *spi) ddata->spi = spi; - if (dev_get_platdata(&spi->dev)) { - r = nec_8048_probe_pdata(spi); - if (r) - return r; - } else if (spi->dev.of_node) { - r = nec_8048_probe_of(spi); - if (r) - return r; - } else { + if (!spi->dev.of_node) return -ENODEV; - } + + r = nec_8048_probe_of(spi); + if (r) + return r; if (gpio_is_valid(ddata->qvga_gpio)) { r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio, diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c index abfd1f6e3327..529a017602e4 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c @@ -18,7 +18,6 @@ #include <linux/slab.h> #include <linux/regulator/consumer.h> #include <video/omapdss.h> -#include <video/omap-panel-data.h> struct panel_drv_data { struct omap_dss_device dssdev; @@ -197,73 +196,6 @@ static struct omap_dss_driver sharp_ls_ops = { .get_resolution = omapdss_default_get_resolution, }; -static int sharp_ls_get_gpio(struct device *dev, int gpio, unsigned long flags, - char *desc, struct gpio_desc **gpiod) -{ - struct gpio_desc *gd; - int r; - - *gpiod = NULL; - - r = devm_gpio_request_one(dev, gpio, flags, desc); - if (r) - return r == -ENOENT ? 0 : r; - - gd = gpio_to_desc(gpio); - if (IS_ERR(gd)) - return PTR_ERR(gd) == -ENOENT ? 0 : PTR_ERR(gd); - - *gpiod = gd; - return 0; -} - -static int sharp_ls_probe_pdata(struct platform_device *pdev) -{ - const struct panel_sharp_ls037v7dw01_platform_data *pdata; - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct omap_dss_device *dssdev, *in; - int r; - - pdata = dev_get_platdata(&pdev->dev); - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&pdev->dev, "failed to find video source '%s'\n", - pdata->source); - return -EPROBE_DEFER; - } - - ddata->in = in; - - ddata->data_lines = pdata->data_lines; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - r = sharp_ls_get_gpio(&pdev->dev, pdata->mo_gpio, GPIOF_OUT_INIT_LOW, - "lcd MO", &ddata->mo_gpio); - if (r) - return r; - r = sharp_ls_get_gpio(&pdev->dev, pdata->lr_gpio, GPIOF_OUT_INIT_HIGH, - "lcd LR", &ddata->lr_gpio); - if (r) - return r; - r = sharp_ls_get_gpio(&pdev->dev, pdata->ud_gpio, GPIOF_OUT_INIT_HIGH, - "lcd UD", &ddata->ud_gpio); - if (r) - return r; - r = sharp_ls_get_gpio(&pdev->dev, pdata->resb_gpio, GPIOF_OUT_INIT_LOW, - "lcd RESB", &ddata->resb_gpio); - if (r) - return r; - r = sharp_ls_get_gpio(&pdev->dev, pdata->ini_gpio, GPIOF_OUT_INIT_LOW, - "lcd INI", &ddata->ini_gpio); - if (r) - return r; - - return 0; -} - static int sharp_ls_get_gpio_of(struct device *dev, int index, int val, const char *desc, struct gpio_desc **gpiod) { @@ -340,17 +272,12 @@ static int sharp_ls_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (dev_get_platdata(&pdev->dev)) { - r = sharp_ls_probe_pdata(pdev); - if (r) - return r; - } else if (pdev->dev.of_node) { - r = sharp_ls_probe_of(pdev); - if (r) - return r; - } else { + if (!pdev->dev.of_node) return -ENODEV; - } + + r = sharp_ls_probe_of(pdev); + if (r) + return r; ddata->videomode = sharp_ls_timings; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index 4d657f3ab679..bd8d85041926 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -29,7 +29,6 @@ #include <linux/spi/spi.h> #include <linux/gpio.h> #include <video/omapdss.h> -#include <video/omap-panel-data.h> struct panel_drv_data { struct omap_dss_device dssdev; @@ -365,31 +364,6 @@ static struct omap_dss_driver td028ttec1_ops = { .check_timings = td028ttec1_panel_check_timings, }; -static int td028ttec1_panel_probe_pdata(struct spi_device *spi) -{ - const struct panel_tpo_td028ttec1_platform_data *pdata; - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev, *in; - - pdata = dev_get_platdata(&spi->dev); - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&spi->dev, "failed to find video source '%s'\n", - pdata->source); - return -EPROBE_DEFER; - } - - ddata->in = in; - - ddata->data_lines = pdata->data_lines; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - return 0; -} - static int td028ttec1_probe_of(struct spi_device *spi) { struct device_node *node = spi->dev.of_node; @@ -432,17 +406,12 @@ static int td028ttec1_panel_probe(struct spi_device *spi) ddata->spi_dev = spi; - if (dev_get_platdata(&spi->dev)) { - r = td028ttec1_panel_probe_pdata(spi); - if (r) - return r; - } else if (spi->dev.of_node) { - r = td028ttec1_probe_of(spi); - if (r) - return r; - } else { + if (!spi->dev.of_node) return -ENODEV; - } + + r = td028ttec1_probe_of(spi); + if (r) + return r; ddata->videomode = td028ttec1_panel_timings; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c index 68e3b68a2920..03e2beb7b4f0 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c @@ -20,7 +20,6 @@ #include <linux/of_gpio.h> #include <video/omapdss.h> -#include <video/omap-panel-data.h> #define TPO_R02_MODE(x) ((x) & 7) #define TPO_R02_MODE_800x480 7 @@ -464,33 +463,6 @@ static struct omap_dss_driver tpo_td043_ops = { .get_resolution = omapdss_default_get_resolution, }; - -static int tpo_td043_probe_pdata(struct spi_device *spi) -{ - const struct panel_tpo_td043mtea1_platform_data *pdata; - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev, *in; - - pdata = dev_get_platdata(&spi->dev); - - ddata->nreset_gpio = pdata->nreset_gpio; - - in = omap_dss_find_output(pdata->source); - if (in == NULL) { - dev_err(&spi->dev, "failed to find video source '%s'\n", - pdata->source); - return -EPROBE_DEFER; - } - ddata->in = in; - - ddata->data_lines = pdata->data_lines; - - dssdev = &ddata->dssdev; - dssdev->name = pdata->name; - - return 0; -} - static int tpo_td043_probe_of(struct spi_device *spi) { struct device_node *node = spi->dev.of_node; @@ -541,17 +513,12 @@ static int tpo_td043_probe(struct spi_device *spi) ddata->spi = spi; - if (dev_get_platdata(&spi->dev)) { - r = tpo_td043_probe_pdata(spi); - if (r) - return r; - } else if (spi->dev.of_node) { - r = tpo_td043_probe_of(spi); - if (r) - return r; - } else { + if (!spi->dev.of_node) return -ENODEV; - } + + r = tpo_td043_probe_of(spi); + if (r) + return r; ddata->mode = TPO_R02_MODE_800x480; memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma)); diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile index b5136d3d4b77..b651ec9751e6 100644 --- a/drivers/gpu/drm/omapdrm/dss/Makefile +++ b/drivers/gpu/drm/omapdrm/dss/Makefile @@ -3,9 +3,6 @@ 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 \ output.o dss-of.o pll.o video-pll.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 diff --git a/drivers/gpu/drm/omapdrm/dss/apply.c b/drivers/gpu/drm/omapdrm/dss/apply.c deleted file mode 100644 index 663ccc3bf4e5..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/apply.c +++ /dev/null @@ -1,1702 +0,0 @@ -/* - * Copyright (C) 2011 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 <video/omapdss.h> - -#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 - * the latter two in HW. - * - * set_info() - * v - * +--------------------+ - * | user_info | - * +--------------------+ - * v - * apply() - * v - * +--------------------+ - * | info | - * +--------------------+ - * v - * write_regs() - * v - * +--------------------+ - * | shadow registers | - * +--------------------+ - * v - * VFP or lcd/digit_enable - * v - * +--------------------+ - * | registers | - * +--------------------+ - */ - -struct ovl_priv_data { - - bool user_info_dirty; - struct omap_overlay_info user_info; - - bool info_dirty; - struct omap_overlay_info info; - - bool shadow_info_dirty; - - bool extra_info_dirty; - bool shadow_extra_info_dirty; - - bool enabled; - u32 fifo_low, fifo_high; - - /* - * True if overlay is to be enabled. Used to check and calculate configs - * for the overlay before it is enabled in the HW. - */ - bool enabling; -}; - -struct mgr_priv_data { - - bool user_info_dirty; - struct omap_overlay_manager_info user_info; - - bool info_dirty; - struct omap_overlay_manager_info info; - - bool shadow_info_dirty; - - /* If true, GO bit is up and shadow registers cannot be written. - * Never true for manual update displays */ - bool busy; - - /* If true, dispc output is enabled */ - bool updating; - - /* If true, a display is enabled using this manager */ - bool enabled; - - bool extra_info_dirty; - bool shadow_extra_info_dirty; - - struct omap_video_timings timings; - struct dss_lcd_mgr_config lcd_config; - - void (*framedone_handler)(void *); - void *framedone_handler_data; -}; - -static struct { - struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; - struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; - - bool irq_enabled; -} dss_data; - -/* protects dss_data */ -static spinlock_t data_lock; -/* lock for blocking functions */ -static DEFINE_MUTEX(apply_lock); -static DECLARE_COMPLETION(extra_updated_completion); - -static void dss_register_vsync_isr(void); - -static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl) -{ - return &dss_data.ovl_priv_data_array[ovl->id]; -} - -static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) -{ - return &dss_data.mgr_priv_data_array[mgr->id]; -} - -static void apply_init_priv(void) -{ - const int num_ovls = dss_feat_get_num_ovls(); - struct mgr_priv_data *mp; - int i; - - spin_lock_init(&data_lock); - - for (i = 0; i < num_ovls; ++i) { - struct ovl_priv_data *op; - - op = &dss_data.ovl_priv_data_array[i]; - - op->info.color_mode = OMAP_DSS_COLOR_RGB16; - op->info.rotation_type = OMAP_DSS_ROT_DMA; - - op->info.global_alpha = 255; - - switch (i) { - case 0: - op->info.zorder = 0; - break; - case 1: - op->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; - break; - case 2: - op->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; - break; - case 3: - op->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; - break; - } - - op->user_info = op->info; - } - - /* - * Initialize some of the lcd_config fields for TV manager, this lets - * us prevent checking if the manager is LCD or TV at some places - */ - mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT]; - - mp->lcd_config.video_port_width = 24; - mp->lcd_config.clock_info.lck_div = 1; - mp->lcd_config.clock_info.pck_div = 1; -} - -/* - * A LCD manager's stallmode decides whether it is in manual or auto update. TV - * manager is always auto update, stallmode field for TV manager is false by - * default - */ -static bool ovl_manual_update(struct omap_overlay *ovl) -{ - struct mgr_priv_data *mp = get_mgr_priv(ovl->manager); - - return mp->lcd_config.stallmode; -} - -static bool mgr_manual_update(struct omap_overlay_manager *mgr) -{ - struct mgr_priv_data *mp = get_mgr_priv(mgr); - - return mp->lcd_config.stallmode; -} - -static int dss_check_settings_low(struct omap_overlay_manager *mgr, - bool applying) -{ - struct omap_overlay_info *oi; - struct omap_overlay_manager_info *mi; - struct omap_overlay *ovl; - struct omap_overlay_info *ois[MAX_DSS_OVERLAYS]; - struct ovl_priv_data *op; - struct mgr_priv_data *mp; - - mp = get_mgr_priv(mgr); - - if (!mp->enabled) - return 0; - - if (applying && mp->user_info_dirty) - mi = &mp->user_info; - else - mi = &mp->info; - - /* collect the infos to be tested into the array */ - list_for_each_entry(ovl, &mgr->overlays, list) { - op = get_ovl_priv(ovl); - - if (!op->enabled && !op->enabling) - oi = NULL; - else if (applying && op->user_info_dirty) - oi = &op->user_info; - else - oi = &op->info; - - ois[ovl->id] = oi; - } - - return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois); -} - -/* - * check manager and overlay settings using overlay_info from data->info - */ -static int dss_check_settings(struct omap_overlay_manager *mgr) -{ - return dss_check_settings_low(mgr, false); -} - -/* - * check manager and overlay settings using overlay_info from ovl->info if - * dirty and from data->info otherwise - */ -static int dss_check_settings_apply(struct omap_overlay_manager *mgr) -{ - return dss_check_settings_low(mgr, true); -} - -static bool need_isr(void) -{ - const int num_mgrs = dss_feat_get_num_mgrs(); - int i; - - for (i = 0; i < num_mgrs; ++i) { - struct omap_overlay_manager *mgr; - struct mgr_priv_data *mp; - struct omap_overlay *ovl; - - mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (!mp->enabled) - continue; - - if (mgr_manual_update(mgr)) { - /* to catch FRAMEDONE */ - if (mp->updating) - return true; - } else { - /* to catch GO bit going down */ - if (mp->busy) - return true; - - /* to write new values to registers */ - if (mp->info_dirty) - return true; - - /* to set GO bit */ - if (mp->shadow_info_dirty) - return true; - - /* - * NOTE: we don't check extra_info flags for disabled - * managers, once the manager is enabled, the extra_info - * related manager changes will be taken in by HW. - */ - - /* to write new values to registers */ - if (mp->extra_info_dirty) - return true; - - /* to set GO bit */ - if (mp->shadow_extra_info_dirty) - return true; - - list_for_each_entry(ovl, &mgr->overlays, list) { - struct ovl_priv_data *op; - - op = get_ovl_priv(ovl); - - /* - * NOTE: we check extra_info flags even for - * disabled overlays, as extra_infos need to be - * always written. - */ - - /* to write new values to registers */ - if (op->extra_info_dirty) - return true; - - /* to set GO bit */ - if (op->shadow_extra_info_dirty) - return true; - - if (!op->enabled) - continue; - - /* to write new values to registers */ - if (op->info_dirty) - return true; - - /* to set GO bit */ - if (op->shadow_info_dirty) - return true; - } - } - } - - return false; -} - -static bool need_go(struct omap_overlay_manager *mgr) -{ - struct omap_overlay *ovl; - struct mgr_priv_data *mp; - struct ovl_priv_data *op; - - mp = get_mgr_priv(mgr); - - if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty) - return true; - - list_for_each_entry(ovl, &mgr->overlays, list) { - op = get_ovl_priv(ovl); - if (op->shadow_info_dirty || op->shadow_extra_info_dirty) - return true; - } - - return false; -} - -/* returns true if an extra_info field is currently being updated */ -static bool extra_info_update_ongoing(void) -{ - const int num_mgrs = dss_feat_get_num_mgrs(); - int i; - - for (i = 0; i < num_mgrs; ++i) { - struct omap_overlay_manager *mgr; - struct omap_overlay *ovl; - struct mgr_priv_data *mp; - - mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (!mp->enabled) - continue; - - if (!mp->updating) - continue; - - if (mp->extra_info_dirty || mp->shadow_extra_info_dirty) - return true; - - list_for_each_entry(ovl, &mgr->overlays, list) { - struct ovl_priv_data *op = get_ovl_priv(ovl); - - if (op->extra_info_dirty || op->shadow_extra_info_dirty) - return true; - } - } - - return false; -} - -/* wait until no extra_info updates are pending */ -static void wait_pending_extra_info_updates(void) -{ - bool updating; - unsigned long flags; - unsigned long t; - int r; - - spin_lock_irqsave(&data_lock, flags); - - updating = extra_info_update_ongoing(); - - if (!updating) { - spin_unlock_irqrestore(&data_lock, flags); - return; - } - - init_completion(&extra_updated_completion); - - spin_unlock_irqrestore(&data_lock, flags); - - t = msecs_to_jiffies(500); - r = wait_for_completion_timeout(&extra_updated_completion, t); - if (r == 0) - DSSWARN("timeout in wait_pending_extra_info_updates\n"); -} - -static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) -{ - struct omap_dss_device *dssdev; - - dssdev = mgr->output; - if (dssdev == NULL) - return NULL; - - while (dssdev->dst) - dssdev = dssdev->dst; - - if (dssdev->driver) - return dssdev; - else - return NULL; -} - -static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) -{ - return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL; -} - -static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) -{ - unsigned long timeout = msecs_to_jiffies(500); - u32 irq; - int r; - - if (mgr->output == NULL) - return -ENODEV; - - r = dispc_runtime_get(); - if (r) - return r; - - switch (mgr->output->id) { - case OMAP_DSS_OUTPUT_VENC: - irq = DISPC_IRQ_EVSYNC_ODD; - break; - case OMAP_DSS_OUTPUT_HDMI: - irq = DISPC_IRQ_EVSYNC_EVEN; - break; - default: - irq = dispc_mgr_get_vsync_irq(mgr->id); - break; - } - - 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); - u32 irq; - unsigned long flags; - int r; - int i; - - spin_lock_irqsave(&data_lock, flags); - - if (mgr_manual_update(mgr)) { - spin_unlock_irqrestore(&data_lock, flags); - return 0; - } - - if (!mp->enabled) { - spin_unlock_irqrestore(&data_lock, flags); - return 0; - } - - spin_unlock_irqrestore(&data_lock, flags); - - r = dispc_runtime_get(); - if (r) - return r; - - irq = dispc_mgr_get_vsync_irq(mgr->id); - - i = 0; - while (1) { - bool shadow_dirty, dirty; - - spin_lock_irqsave(&data_lock, flags); - dirty = mp->info_dirty; - shadow_dirty = mp->shadow_info_dirty; - spin_unlock_irqrestore(&data_lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } - - /* 4 iterations is the worst case: - * 1 - initial iteration, dirty = true (between VFP and VSYNC) - * 2 - first VSYNC, dirty = true - * 3 - dirty = false, shadow_dirty = true - * 4 - shadow_dirty = false */ - if (i++ == 3) { - DSSERR("mgr(%d)->wait_for_go() not finishing\n", - mgr->id); - r = 0; - break; - } - - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; - - if (r) { - DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); - break; - } - } - - dispc_runtime_put(); - - return r; -} - -static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) -{ - unsigned long timeout = msecs_to_jiffies(500); - struct ovl_priv_data *op; - struct mgr_priv_data *mp; - u32 irq; - unsigned long flags; - int r; - int i; - - if (!ovl->manager) - return 0; - - mp = get_mgr_priv(ovl->manager); - - spin_lock_irqsave(&data_lock, flags); - - if (ovl_manual_update(ovl)) { - spin_unlock_irqrestore(&data_lock, flags); - return 0; - } - - if (!mp->enabled) { - spin_unlock_irqrestore(&data_lock, flags); - return 0; - } - - spin_unlock_irqrestore(&data_lock, flags); - - r = dispc_runtime_get(); - if (r) - return r; - - irq = dispc_mgr_get_vsync_irq(ovl->manager->id); - - op = get_ovl_priv(ovl); - i = 0; - while (1) { - bool shadow_dirty, dirty; - - spin_lock_irqsave(&data_lock, flags); - dirty = op->info_dirty; - shadow_dirty = op->shadow_info_dirty; - spin_unlock_irqrestore(&data_lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } - - /* 4 iterations is the worst case: - * 1 - initial iteration, dirty = true (between VFP and VSYNC) - * 2 - first VSYNC, dirty = true - * 3 - dirty = false, shadow_dirty = true - * 4 - shadow_dirty = false */ - if (i++ == 3) { - DSSERR("ovl(%d)->wait_for_go() not finishing\n", - ovl->id); - r = 0; - break; - } - - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; - - if (r) { - DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); - break; - } - } - - dispc_runtime_put(); - - return r; -} - -static void dss_ovl_write_regs(struct omap_overlay *ovl) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - struct omap_overlay_info *oi; - bool replication; - struct mgr_priv_data *mp; - int r; - - DSSDBG("writing ovl %d regs\n", ovl->id); - - if (!op->enabled || !op->info_dirty) - return; - - oi = &op->info; - - mp = get_mgr_priv(ovl->manager); - - replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); - - r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false); - if (r) { - /* - * We can't do much here, as this function can be called from - * vsync interrupt. - */ - DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id); - - /* This will leave fifo configurations in a nonoptimal state */ - op->enabled = false; - dispc_ovl_enable(ovl->id, false); - return; - } - - op->info_dirty = false; - if (mp->updating) - op->shadow_info_dirty = true; -} - -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; - - DSSDBG("writing ovl %d regs extra\n", ovl->id); - - if (!op->extra_info_dirty) - return; - - /* note: write also when op->enabled == false, so that the ovl gets - * disabled */ - - dispc_ovl_enable(ovl->id, op->enabled); - dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); - - mp = get_mgr_priv(ovl->manager); - - op->extra_info_dirty = false; - if (mp->updating) - op->shadow_extra_info_dirty = true; -} - -static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) -{ - struct mgr_priv_data *mp = get_mgr_priv(mgr); - struct omap_overlay *ovl; - - DSSDBG("writing mgr %d regs\n", mgr->id); - - if (!mp->enabled) - return; - - WARN_ON(mp->busy); - - /* Commit overlay settings */ - list_for_each_entry(ovl, &mgr->overlays, list) { - dss_ovl_write_regs(ovl); - dss_ovl_write_regs_extra(ovl); - } - - if (mp->info_dirty) { - dispc_mgr_setup(mgr->id, &mp->info); - - mp->info_dirty = false; - if (mp->updating) - mp->shadow_info_dirty = true; - } -} - -static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) -{ - struct mgr_priv_data *mp = get_mgr_priv(mgr); - - DSSDBG("writing mgr %d regs extra\n", mgr->id); - - if (!mp->extra_info_dirty) - return; - - dispc_mgr_set_timings(mgr->id, &mp->timings); - - /* lcd_config parameters */ - 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) - mp->shadow_extra_info_dirty = true; -} - -static void dss_write_regs(void) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - int i; - - for (i = 0; i < num_mgrs; ++i) { - struct omap_overlay_manager *mgr; - struct mgr_priv_data *mp; - int r; - - mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) - continue; - - r = dss_check_settings(mgr); - if (r) { - DSSERR("cannot write registers for manager %s: " - "illegal configuration\n", mgr->name); - continue; - } - - dss_mgr_write_regs(mgr); - dss_mgr_write_regs_extra(mgr); - } -} - -static void dss_set_go_bits(void) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - int i; - - 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 (!mp->enabled || mgr_manual_update(mgr) || mp->busy) - continue; - - if (!need_go(mgr)) - continue; - - mp->busy = true; - - if (!dss_data.irq_enabled && need_isr()) - dss_register_vsync_isr(); - - dispc_mgr_go(mgr->id); - } - -} - -static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) -{ - struct omap_overlay *ovl; - struct mgr_priv_data *mp; - struct ovl_priv_data *op; - - mp = get_mgr_priv(mgr); - mp->shadow_info_dirty = false; - mp->shadow_extra_info_dirty = false; - - list_for_each_entry(ovl, &mgr->overlays, list) { - op = get_ovl_priv(ovl); - op->shadow_info_dirty = false; - op->shadow_extra_info_dirty = false; - } -} - -static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr, - struct omap_dss_device *dst) -{ - return mgr->set_output(mgr, dst); -} - -static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr, - struct omap_dss_device *dst) -{ - mgr->unset_output(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; - int r; - - spin_lock_irqsave(&data_lock, flags); - - WARN_ON(mp->updating); - - r = dss_check_settings(mgr); - if (r) { - DSSERR("cannot start manual update: illegal configuration\n"); - spin_unlock_irqrestore(&data_lock, flags); - return; - } - - dss_mgr_write_regs(mgr); - dss_mgr_write_regs_extra(mgr); - - mp->updating = true; - - if (!dss_data.irq_enabled && need_isr()) - dss_register_vsync_isr(); - - dispc_mgr_enable_sync(mgr->id); - - spin_unlock_irqrestore(&data_lock, flags); -} - -static void dss_apply_irq_handler(void *data, u32 mask); - -static void dss_register_vsync_isr(void) -{ - const int num_mgrs = dss_feat_get_num_mgrs(); - u32 mask; - int r, i; - - mask = 0; - for (i = 0; i < num_mgrs; ++i) - mask |= dispc_mgr_get_vsync_irq(i); - - for (i = 0; i < num_mgrs; ++i) - mask |= dispc_mgr_get_framedone_irq(i); - - r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); - WARN_ON(r); - - dss_data.irq_enabled = true; -} - -static void dss_unregister_vsync_isr(void) -{ - const int num_mgrs = dss_feat_get_num_mgrs(); - u32 mask; - int r, i; - - mask = 0; - for (i = 0; i < num_mgrs; ++i) - mask |= dispc_mgr_get_vsync_irq(i); - - for (i = 0; i < num_mgrs; ++i) - mask |= dispc_mgr_get_framedone_irq(i); - - r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); - WARN_ON(r); - - dss_data.irq_enabled = false; -} - -static void dss_apply_irq_handler(void *data, u32 mask) -{ - const int num_mgrs = dss_feat_get_num_mgrs(); - int i; - bool extra_updating; - - spin_lock(&data_lock); - - /* clear busy, updating flags, shadow_dirty flags */ - 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 (!mp->enabled) - continue; - - mp->updating = dispc_mgr_is_enabled(i); - - if (!mgr_manual_update(mgr)) { - bool was_busy = mp->busy; - mp->busy = dispc_mgr_go_busy(i); - - if (was_busy && !mp->busy) - mgr_clear_shadow_dirty(mgr); - } - } - - dss_write_regs(); - dss_set_go_bits(); - - extra_updating = extra_info_update_ongoing(); - 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(); - - spin_unlock(&data_lock); -} - -static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) -{ - struct ovl_priv_data *op; - - op = get_ovl_priv(ovl); - - if (!op->user_info_dirty) - return; - - op->user_info_dirty = false; - op->info_dirty = true; - op->info = op->user_info; -} - -static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) -{ - struct mgr_priv_data *mp; - - mp = get_mgr_priv(mgr); - - if (!mp->user_info_dirty) - return; - - mp->user_info_dirty = false; - mp->info_dirty = true; - mp->info = mp->user_info; -} - -static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) -{ - unsigned long flags; - struct omap_overlay *ovl; - int r; - - DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); - - spin_lock_irqsave(&data_lock, flags); - - r = dss_check_settings_apply(mgr); - if (r) { - spin_unlock_irqrestore(&data_lock, flags); - DSSERR("failed to apply settings: illegal configuration.\n"); - return r; - } - - /* Configure overlays */ - list_for_each_entry(ovl, &mgr->overlays, list) - omap_dss_mgr_apply_ovl(ovl); - - /* Configure manager */ - omap_dss_mgr_apply_mgr(mgr); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - return 0; -} - -static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable) -{ - struct ovl_priv_data *op; - - op = get_ovl_priv(ovl); - - if (op->enabled == enable) - return; - - op->enabled = enable; - op->extra_info_dirty = true; -} - -static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, - u32 fifo_low, u32 fifo_high) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - - if (op->fifo_low == fifo_low && op->fifo_high == fifo_high) - return; - - op->fifo_low = fifo_low; - op->fifo_high = fifo_high; - op->extra_info_dirty = true; -} - -static void dss_ovl_setup_fifo(struct omap_overlay *ovl) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - u32 fifo_low, fifo_high; - bool use_fifo_merge = false; - - if (!op->enabled && !op->enabling) - return; - - dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high, - use_fifo_merge, ovl_manual_update(ovl)); - - dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); -} - -static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) -{ - struct omap_overlay *ovl; - struct mgr_priv_data *mp; - - mp = get_mgr_priv(mgr); - - if (!mp->enabled) - return; - - list_for_each_entry(ovl, &mgr->overlays, list) - dss_ovl_setup_fifo(ovl); -} - -static void dss_setup_fifos(void) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - struct omap_overlay_manager *mgr; - int i; - - for (i = 0; i < num_mgrs; ++i) { - mgr = omap_dss_get_overlay_manager(i); - dss_mgr_setup_fifos(mgr); - } -} - -static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr) -{ - struct mgr_priv_data *mp = get_mgr_priv(mgr); - unsigned long flags; - int r; - - mutex_lock(&apply_lock); - - if (mp->enabled) - goto out; - - spin_lock_irqsave(&data_lock, flags); - - mp->enabled = true; - - r = dss_check_settings(mgr); - if (r) { - DSSERR("failed to enable manager %d: check_settings failed\n", - mgr->id); - goto err; - } - - dss_setup_fifos(); - - dss_write_regs(); - dss_set_go_bits(); - - 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_sync(mgr->id); - -out: - mutex_unlock(&apply_lock); - - return 0; - -err: - mp->enabled = false; - spin_unlock_irqrestore(&data_lock, flags); - mutex_unlock(&apply_lock); - return r; -} - -static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr) -{ - struct mgr_priv_data *mp = get_mgr_priv(mgr); - unsigned long flags; - - mutex_lock(&apply_lock); - - if (!mp->enabled) - goto out; - - wait_pending_extra_info_updates(); - - if (!mgr_manual_update(mgr)) - dispc_mgr_disable_sync(mgr->id); - - spin_lock_irqsave(&data_lock, flags); - - mp->updating = false; - mp->enabled = false; - - spin_unlock_irqrestore(&data_lock, flags); - -out: - mutex_unlock(&apply_lock); -} - -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); - unsigned long flags; - int r; - - r = dss_mgr_simple_check(mgr, info); - if (r) - return r; - - spin_lock_irqsave(&data_lock, flags); - - mp->user_info = *info; - mp->user_info_dirty = true; - - spin_unlock_irqrestore(&data_lock, flags); - - return 0; -} - -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); - unsigned long flags; - - spin_lock_irqsave(&data_lock, flags); - - *info = mp->user_info; - - spin_unlock_irqrestore(&data_lock, flags); -} - -static int dss_mgr_set_output(struct omap_overlay_manager *mgr, - struct omap_dss_device *output) -{ - int r; - - mutex_lock(&apply_lock); - - if (mgr->output) { - DSSERR("manager %s is already connected to an output\n", - mgr->name); - r = -EINVAL; - goto err; - } - - if ((mgr->supported_outputs & output->id) == 0) { - DSSERR("output does not support manager %s\n", - mgr->name); - r = -EINVAL; - goto err; - } - - output->manager = mgr; - mgr->output = output; - - mutex_unlock(&apply_lock); - - return 0; -err: - mutex_unlock(&apply_lock); - return r; -} - -static int dss_mgr_unset_output(struct omap_overlay_manager *mgr) -{ - int r; - struct mgr_priv_data *mp = get_mgr_priv(mgr); - unsigned long flags; - - mutex_lock(&apply_lock); - - if (!mgr->output) { - DSSERR("failed to unset output, output not set\n"); - r = -EINVAL; - goto err; - } - - spin_lock_irqsave(&data_lock, flags); - - if (mp->enabled) { - DSSERR("output can't be unset when manager is enabled\n"); - r = -EINVAL; - goto err1; - } - - spin_unlock_irqrestore(&data_lock, flags); - - mgr->output->manager = NULL; - mgr->output = NULL; - - mutex_unlock(&apply_lock); - - return 0; -err1: - spin_unlock_irqrestore(&data_lock, flags); -err: - mutex_unlock(&apply_lock); - - return r; -} - -static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, - const struct omap_video_timings *timings) -{ - struct mgr_priv_data *mp = get_mgr_priv(mgr); - - mp->timings = *timings; - mp->extra_info_dirty = true; -} - -static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr, - const struct omap_video_timings *timings) -{ - unsigned long flags; - struct mgr_priv_data *mp = get_mgr_priv(mgr); - - spin_lock_irqsave(&data_lock, flags); - - if (mp->updating) { - DSSERR("cannot set timings for %s: manager needs to be disabled\n", - mgr->name); - goto out; - } - - dss_apply_mgr_timings(mgr, timings); -out: - spin_unlock_irqrestore(&data_lock, flags); -} - -static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, - const struct dss_lcd_mgr_config *config) -{ - struct mgr_priv_data *mp = get_mgr_priv(mgr); - - mp->lcd_config = *config; - mp->extra_info_dirty = true; -} - -static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr, - const struct dss_lcd_mgr_config *config) -{ - unsigned long flags; - struct mgr_priv_data *mp = get_mgr_priv(mgr); - - spin_lock_irqsave(&data_lock, flags); - - if (mp->enabled) { - DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", - mgr->name); - goto out; - } - - dss_apply_mgr_lcd_config(mgr, config); -out: - spin_unlock_irqrestore(&data_lock, flags); -} - -static int dss_ovl_set_info(struct omap_overlay *ovl, - struct omap_overlay_info *info) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - unsigned long flags; - int r; - - r = dss_ovl_simple_check(ovl, info); - if (r) - return r; - - spin_lock_irqsave(&data_lock, flags); - - op->user_info = *info; - op->user_info_dirty = true; - - spin_unlock_irqrestore(&data_lock, flags); - - return 0; -} - -static void dss_ovl_get_info(struct omap_overlay *ovl, - struct omap_overlay_info *info) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - unsigned long flags; - - spin_lock_irqsave(&data_lock, flags); - - *info = op->user_info; - - spin_unlock_irqrestore(&data_lock, flags); -} - -static int dss_ovl_set_manager(struct omap_overlay *ovl, - struct omap_overlay_manager *mgr) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - unsigned long flags; - int r; - - if (!mgr) - return -EINVAL; - - mutex_lock(&apply_lock); - - if (ovl->manager) { - DSSERR("overlay '%s' already has a manager '%s'\n", - ovl->name, ovl->manager->name); - r = -EINVAL; - 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 err1; - } - - 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); - - dispc_runtime_put(); - - mutex_unlock(&apply_lock); - - return 0; - -err1: - dispc_runtime_put(); -err: - mutex_unlock(&apply_lock); - return r; -} - -static int dss_ovl_unset_manager(struct omap_overlay *ovl) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - unsigned long flags; - int r; - - mutex_lock(&apply_lock); - - if (!ovl->manager) { - DSSERR("failed to detach overlay: manager not set\n"); - r = -EINVAL; - goto err; - } - - spin_lock_irqsave(&data_lock, flags); - - if (op->enabled) { - spin_unlock_irqrestore(&data_lock, flags); - DSSERR("overlay has to be disabled to unset the manager\n"); - r = -EINVAL; - goto err; - } - - spin_unlock_irqrestore(&data_lock, flags); - - /* 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); - - 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); - - spin_unlock_irqrestore(&data_lock, flags); - - mutex_unlock(&apply_lock); - - return 0; -err: - mutex_unlock(&apply_lock); - return r; -} - -static bool dss_ovl_is_enabled(struct omap_overlay *ovl) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - unsigned long flags; - bool e; - - spin_lock_irqsave(&data_lock, flags); - - e = op->enabled; - - spin_unlock_irqrestore(&data_lock, flags); - - return e; -} - -static int dss_ovl_enable(struct omap_overlay *ovl) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - unsigned long flags; - int r; - - mutex_lock(&apply_lock); - - if (op->enabled) { - r = 0; - goto err1; - } - - if (ovl->manager == NULL || ovl->manager->output == NULL) { - r = -EINVAL; - goto err1; - } - - spin_lock_irqsave(&data_lock, flags); - - op->enabling = true; - - r = dss_check_settings(ovl->manager); - if (r) { - DSSERR("failed to enable overlay %d: check_settings failed\n", - ovl->id); - goto err2; - } - - dss_setup_fifos(); - - op->enabling = false; - dss_apply_ovl_enable(ovl, true); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - mutex_unlock(&apply_lock); - - return 0; -err2: - op->enabling = false; - spin_unlock_irqrestore(&data_lock, flags); -err1: - mutex_unlock(&apply_lock); - return r; -} - -static int dss_ovl_disable(struct omap_overlay *ovl) -{ - struct ovl_priv_data *op = get_ovl_priv(ovl); - unsigned long flags; - int r; - - mutex_lock(&apply_lock); - - if (!op->enabled) { - r = 0; - goto err; - } - - if (ovl->manager == NULL || ovl->manager->output == NULL) { - r = -EINVAL; - goto err; - } - - spin_lock_irqsave(&data_lock, flags); - - dss_apply_ovl_enable(ovl, false); - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - mutex_unlock(&apply_lock); - - return 0; - -err: - mutex_unlock(&apply_lock); - 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 = { - .connect = dss_mgr_connect_compat, - .disconnect = dss_mgr_disconnect_compat, - .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(); - int i, r; - - mutex_lock(&compat_init_lock); - - if (compat_refcnt++ > 0) - goto out; - - apply_init_priv(); - - dss_init_overlay_managers_sysfs(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; - - r = display_init_sysfs(pdev); - 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(); - display_uninit_sysfs(pdev); - -err_disp_sysfs: - dss_uninstall_mgr_ops(); - -err_mgr_ops: - dss_uninit_overlay_managers_sysfs(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(); - - mutex_lock(&compat_init_lock); - - if (--compat_refcnt > 0) - goto out; - - dss_dispc_uninitialize_irq(); - - display_uninit_sysfs(pdev); - - dss_uninstall_mgr_ops(); - - dss_uninit_overlay_managers_sysfs(pdev); - dss_uninit_overlays(pdev); -out: - mutex_unlock(&compat_init_lock); -} -EXPORT_SYMBOL(omapdss_compat_uninit); diff --git a/drivers/gpu/drm/omapdrm/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c index 54eeb507f9b3..7e4e5bebabbe 100644 --- a/drivers/gpu/drm/omapdrm/dss/core.c +++ b/drivers/gpu/drm/omapdrm/dss/core.c @@ -165,32 +165,20 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) #endif /* CONFIG_OMAP2_DSS_DEBUGFS */ /* PLATFORM DEVICE */ -static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) + +static void dss_disable_all_devices(void) { - DSSDBG("pm notif %lu\n", v); - - switch (v) { - case PM_SUSPEND_PREPARE: - case PM_HIBERNATION_PREPARE: - case PM_RESTORE_PREPARE: - DSSDBG("suspending displays\n"); - return dss_suspend_all_devices(); - - case PM_POST_SUSPEND: - case PM_POST_HIBERNATION: - case PM_POST_RESTORE: - DSSDBG("resuming displays\n"); - return dss_resume_all_devices(); - - default: - return 0; + struct omap_dss_device *dssdev = NULL; + + for_each_dss_dev(dssdev) { + if (!dssdev->driver) + continue; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + dssdev->driver->disable(dssdev); } } -static struct notifier_block omap_dss_pm_notif_block = { - .notifier_call = omap_dss_pm_notif, -}; - static int __init omap_dss_probe(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; @@ -211,8 +199,6 @@ static int __init omap_dss_probe(struct platform_device *pdev) else if (pdata->default_device) core.default_display_name = pdata->default_device->name; - register_pm_notifier(&omap_dss_pm_notif_block); - return 0; err_debugfs: @@ -222,8 +208,6 @@ err_debugfs: static int omap_dss_remove(struct platform_device *pdev) { - unregister_pm_notifier(&omap_dss_pm_notif_block); - dss_uninitialize_debugfs(); return 0; diff --git a/drivers/gpu/drm/omapdrm/dss/dispc-compat.c b/drivers/gpu/drm/omapdrm/dss/dispc-compat.c deleted file mode 100644 index 0918b3bfe82a..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/dispc-compat.c +++ /dev/null @@ -1,667 +0,0 @@ -/* - * 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); - ovl->disable(ovl); - 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)) - 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)) - 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)) - 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); -} - -static inline void dispc_irq_wait_handler(void *data, u32 mask) -{ - complete((struct completion *)data); -} - -int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, - unsigned long timeout) -{ - - 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/gpu/drm/omapdrm/dss/dispc-compat.h b/drivers/gpu/drm/omapdrm/dss/dispc-compat.h deleted file mode 100644 index 14a69b3d4fb0..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/dispc-compat.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 6b50476ec669..f83608b69e68 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -104,6 +104,15 @@ struct dispc_features { bool supports_sync_align:1; bool has_writeback:1; + + bool supports_double_pixel:1; + + /* + * Field order for VENC is different than HDMI. We should handle this in + * some intelligent manner, but as the SoCs have either HDMI or VENC, + * never both, we can just use this flag for now. + */ + bool reverse_ilace_field_order:1; }; #define DISPC_MAX_NR_FIFOS 5 @@ -2552,47 +2561,6 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, 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 = false; - 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 = true; - - 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, @@ -2747,6 +2715,9 @@ static int dispc_ovl_setup_common(enum omap_plane plane, dispc_ovl_configure_burst_type(plane, rotation_type); + if (dispc.feat->reverse_ilace_field_order) + swap(offset0, offset1); + dispc_ovl_set_ba0(plane, paddr + offset0); dispc_ovl_set_ba1(plane, paddr + offset1); @@ -2898,6 +2869,12 @@ bool dispc_ovl_enabled(enum omap_plane plane) } EXPORT_SYMBOL(dispc_ovl_enabled); +enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel) +{ + return dss_feat_get_supported_outputs(channel); +} +EXPORT_SYMBOL(dispc_mgr_get_supported_outputs); + void dispc_mgr_enable(enum omap_channel channel, bool enable) { mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); @@ -3287,6 +3264,10 @@ void dispc_mgr_set_timings(enum omap_channel channel, } else { if (t.interlace) t.y_res /= 2; + + if (dispc.feat->supports_double_pixel) + REG_FLD_MOD(DISPC_CONTROL, t.double_pixel ? 1 : 0, + 19, 17); } dispc_mgr_set_size(channel, t.x_res, t.y_res); @@ -3951,6 +3932,8 @@ static const struct dispc_features omap44xx_dispc_feats = { .set_max_preload = true, .supports_sync_align = true, .has_writeback = true, + .supports_double_pixel = true, + .reverse_ilace_field_order = true, }; static const struct dispc_features omap54xx_dispc_feats = { @@ -3974,6 +3957,8 @@ static const struct dispc_features omap54xx_dispc_feats = { .set_max_preload = true, .supports_sync_align = true, .has_writeback = true, + .supports_double_pixel = true, + .reverse_ilace_field_order = true, }; static int dispc_init_features(struct platform_device *pdev) @@ -4129,8 +4114,6 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) dispc_runtime_put(); - dss_init_overlay_managers(); - dss_debugfs_create_file("dispc", dispc_dump_regs); return 0; @@ -4144,8 +4127,6 @@ static void dispc_unbind(struct device *dev, struct device *master, void *data) { pm_runtime_disable(dev); - - dss_uninit_overlay_managers(); } static const struct component_ops dispc_component_ops = { diff --git a/drivers/gpu/drm/omapdrm/dss/display-sysfs.c b/drivers/gpu/drm/omapdrm/dss/display-sysfs.c deleted file mode 100644 index 6ad0991f8259..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/display-sysfs.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * 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/platform_device.h> -#include <linux/sysfs.h> - -#include <video/omapdss.h> -#include "dss.h" - -static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", - dssdev->name ? - dssdev->name : ""); -} - -static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - omapdss_device_is_enabled(dssdev)); -} - -static ssize_t display_enabled_store(struct omap_dss_device *dssdev, - const char *buf, size_t size) -{ - int r; - bool enable; - - r = strtobool(buf, &enable); - if (r) - return r; - - if (enable == omapdss_device_is_enabled(dssdev)) - return size; - - if (omapdss_device_is_connected(dssdev) == false) - return -ENODEV; - - if (enable) { - r = dssdev->driver->enable(dssdev); - if (r) - return r; - } else { - dssdev->driver->disable(dssdev); - } - - return size; -} - -static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - dssdev->driver->get_te ? - dssdev->driver->get_te(dssdev) : 0); -} - -static ssize_t display_tear_store(struct omap_dss_device *dssdev, - const char *buf, size_t size) -{ - 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 omap_dss_device *dssdev, char *buf) -{ - 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.pixelclock, - 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 omap_dss_device *dssdev, - const char *buf, size_t size) -{ - 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.pixelclock, - &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 omap_dss_device *dssdev, char *buf) -{ - 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 omap_dss_device *dssdev, - const char *buf, size_t size) -{ - 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 omap_dss_device *dssdev, char *buf) -{ - 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 omap_dss_device *dssdev, - const char *buf, size_t size) -{ - 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 omap_dss_device *dssdev, char *buf) -{ - 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 omap_dss_device *dssdev, - const char *buf, size_t size) -{ - 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; -} - -struct display_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_dss_device *, char *); - ssize_t (*store)(struct omap_dss_device *, const char *, size_t); -}; - -#define DISPLAY_ATTR(_name, _mode, _show, _store) \ - struct display_attribute display_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL); -static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL); -static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR, - display_enabled_show, display_enabled_store); -static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR, - display_tear_show, display_tear_store); -static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR, - display_timings_show, display_timings_store); -static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR, - display_rotate_show, display_rotate_store); -static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR, - display_mirror_show, display_mirror_store); -static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR, - display_wss_show, display_wss_store); - -static struct attribute *display_sysfs_attrs[] = { - &display_attr_name.attr, - &display_attr_display_name.attr, - &display_attr_enabled.attr, - &display_attr_tear_elim.attr, - &display_attr_timings.attr, - &display_attr_rotate.attr, - &display_attr_mirror.attr, - &display_attr_wss.attr, - NULL -}; - -static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_dss_device *dssdev; - struct display_attribute *display_attr; - - dssdev = container_of(kobj, struct omap_dss_device, kobj); - display_attr = container_of(attr, struct display_attribute, attr); - - if (!display_attr->show) - return -ENOENT; - - return display_attr->show(dssdev, buf); -} - -static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_dss_device *dssdev; - struct display_attribute *display_attr; - - dssdev = container_of(kobj, struct omap_dss_device, kobj); - display_attr = container_of(attr, struct display_attribute, attr); - - if (!display_attr->store) - return -ENOENT; - - return display_attr->store(dssdev, buf, size); -} - -static const struct sysfs_ops display_sysfs_ops = { - .show = display_attr_show, - .store = display_attr_store, -}; - -static struct kobj_type display_ktype = { - .sysfs_ops = &display_sysfs_ops, - .default_attrs = display_sysfs_attrs, -}; - -int display_init_sysfs(struct platform_device *pdev) -{ - struct omap_dss_device *dssdev = NULL; - int r; - - for_each_dss_dev(dssdev) { - r = kobject_init_and_add(&dssdev->kobj, &display_ktype, - &pdev->dev.kobj, "%s", dssdev->alias); - if (r) { - DSSERR("failed to create sysfs files\n"); - omap_dss_put_device(dssdev); - goto err; - } - } - - return 0; - -err: - display_uninit_sysfs(pdev); - - return r; -} - -void display_uninit_sysfs(struct platform_device *pdev) -{ - struct omap_dss_device *dssdev = NULL; - - for_each_dss_dev(dssdev) { - if (kobject_name(&dssdev->kobj) == NULL) - continue; - - kobject_del(&dssdev->kobj); - kobject_put(&dssdev->kobj); - - memset(&dssdev->kobj, 0, sizeof(dssdev->kobj)); - } -} diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index ef5b9027985d..9f3dd09b0a6c 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -78,55 +78,6 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_default_get_timings); -int dss_suspend_all_devices(void) -{ - struct omap_dss_device *dssdev = NULL; - - for_each_dss_dev(dssdev) { - if (!dssdev->driver) - continue; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - dssdev->driver->disable(dssdev); - dssdev->activate_after_resume = true; - } else { - dssdev->activate_after_resume = false; - } - } - - return 0; -} - -int dss_resume_all_devices(void) -{ - struct omap_dss_device *dssdev = NULL; - - for_each_dss_dev(dssdev) { - if (!dssdev->driver) - continue; - - if (dssdev->activate_after_resume) { - dssdev->driver->enable(dssdev); - dssdev->activate_after_resume = false; - } - } - - return 0; -} - -void dss_disable_all_devices(void) -{ - struct omap_dss_device *dssdev = NULL; - - for_each_dss_dev(dssdev) { - if (!dssdev->driver) - continue; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - dssdev->driver->disable(dssdev); - } -} - static LIST_HEAD(panel_list); static DEFINE_MUTEX(panel_list_mutex); static int disp_num_counter; diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 7953e6a52346..97ea60257884 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -334,7 +334,7 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, static int dpi_set_mode(struct dpi_data *dpi) { struct omap_dss_device *out = &dpi->output; - struct omap_overlay_manager *mgr = out->manager; + enum omap_channel channel = out->dispc_channel; struct omap_video_timings *t = &dpi->timings; int lck_div = 0, pck_div = 0; unsigned long fck = 0; @@ -342,7 +342,7 @@ static int dpi_set_mode(struct dpi_data *dpi) int r = 0; if (dpi->pll) - r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck, + r = dpi_set_dsi_clk(dpi, channel, t->pixelclock, &fck, &lck_div, &pck_div); else r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck, @@ -359,7 +359,7 @@ static int dpi_set_mode(struct dpi_data *dpi) t->pixelclock = pck; } - dss_mgr_set_timings(mgr, t); + dss_mgr_set_timings(channel, t); return 0; } @@ -367,7 +367,7 @@ static int dpi_set_mode(struct dpi_data *dpi) static void dpi_config_lcd_manager(struct dpi_data *dpi) { struct omap_dss_device *out = &dpi->output; - struct omap_overlay_manager *mgr = out->manager; + enum omap_channel channel = out->dispc_channel; dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; @@ -378,13 +378,14 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) dpi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(mgr, &dpi->mgr_config); + dss_mgr_set_lcd_config(channel, &dpi->mgr_config); } static int dpi_display_enable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); struct omap_dss_device *out = &dpi->output; + enum omap_channel channel = out->dispc_channel; int r; mutex_lock(&dpi->lock); @@ -395,7 +396,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) goto err_no_reg; } - if (out->manager == NULL) { + if (!out->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err_no_out_mgr; @@ -411,7 +412,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_get_dispc; - r = dss_dpi_select_source(out->port_num, out->manager->id); + r = dss_dpi_select_source(out->port_num, channel); if (r) goto err_src_sel; @@ -429,7 +430,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - r = dss_mgr_enable(out->manager); + r = dss_mgr_enable(channel); if (r) goto err_mgr_enable; @@ -457,14 +458,14 @@ err_no_reg: static void dpi_display_disable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - struct omap_overlay_manager *mgr = dpi->output.manager; + enum omap_channel channel = dpi->output.dispc_channel; mutex_lock(&dpi->lock); - dss_mgr_disable(mgr); + dss_mgr_disable(channel); if (dpi->pll) { - dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK); dss_pll_disable(dpi->pll); } @@ -506,14 +507,17 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - struct omap_overlay_manager *mgr = dpi->output.manager; + enum omap_channel channel = dpi->output.dispc_channel; int lck_div, pck_div; unsigned long fck; unsigned long pck; struct dpi_clk_calc_ctx ctx; bool ok; - if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) + if (timings->x_res % 8 != 0) + return -EINVAL; + + if (!dispc_mgr_timings_ok(channel, timings)) return -EINVAL; if (timings->pixelclock == 0) @@ -660,7 +664,7 @@ static int dpi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - struct omap_overlay_manager *mgr; + enum omap_channel channel = dpi->output.dispc_channel; int r; r = dpi_init_regulator(dpi); @@ -669,11 +673,7 @@ static int dpi_connect(struct omap_dss_device *dssdev, dpi_init_pll(dpi); - mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); - if (!mgr) - return -ENODEV; - - r = dss_mgr_connect(mgr, dssdev); + r = dss_mgr_connect(channel, dssdev); if (r) return r; @@ -681,7 +681,7 @@ static int dpi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(mgr, dssdev); + dss_mgr_disconnect(channel, dssdev); return r; } @@ -691,6 +691,9 @@ static int dpi_connect(struct omap_dss_device *dssdev, static void dpi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); + enum omap_channel channel = dpi->output.dispc_channel; + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -698,8 +701,7 @@ static void dpi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - if (dssdev->manager) - dss_mgr_disconnect(dssdev->manager, dssdev); + dss_mgr_disconnect(channel, dssdev); } static const struct omapdss_dpi_ops dpi_ops = { diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 43be4b2a7b05..8730646a0cbb 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -214,9 +214,9 @@ struct dsi_reg { u16 module; u16 idx; }; typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); static int dsi_display_init_dispc(struct platform_device *dsidev, - struct omap_overlay_manager *mgr); + enum omap_channel channel); static void dsi_display_uninit_dispc(struct platform_device *dsidev, - struct omap_overlay_manager *mgr); + enum omap_channel channel); static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); @@ -3826,19 +3826,19 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_overlay_manager *mgr = dsi->output.manager; + enum omap_channel dispc_channel = dssdev->dispc_channel; int bpp = dsi_get_pixel_size(dsi->pix_fmt); struct omap_dss_device *out = &dsi->output; u8 data_type; u16 word_count; int r; - if (out->manager == NULL) { + if (!out->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } - r = dsi_display_init_dispc(dsidev, mgr); + r = dsi_display_init_dispc(dsidev, dispc_channel); if (r) goto err_init_dispc; @@ -3876,7 +3876,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) dsi_if_enable(dsidev, true); } - r = dss_mgr_enable(mgr); + r = dss_mgr_enable(dispc_channel); if (r) goto err_mgr_enable; @@ -3888,7 +3888,7 @@ err_mgr_enable: dsi_vc_enable(dsidev, channel, false); } err_pix_fmt: - dsi_display_uninit_dispc(dsidev, mgr); + dsi_display_uninit_dispc(dsidev, dispc_channel); err_init_dispc: return r; } @@ -3897,7 +3897,7 @@ static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_overlay_manager *mgr = dsi->output.manager; + enum omap_channel dispc_channel = dssdev->dispc_channel; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); @@ -3910,15 +3910,15 @@ static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel dsi_if_enable(dsidev, true); } - dss_mgr_disable(mgr); + dss_mgr_disable(dispc_channel); - dsi_display_uninit_dispc(dsidev, mgr); + dsi_display_uninit_dispc(dsidev, dispc_channel); } static void dsi_update_screen_dispc(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_overlay_manager *mgr = dsi->output.manager; + enum omap_channel dispc_channel = dsi->output.dispc_channel; unsigned bytespp; unsigned bytespl; unsigned bytespf; @@ -3980,9 +3980,9 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) msecs_to_jiffies(250)); BUG_ON(r == 0); - dss_mgr_set_timings(mgr, &dsi->timings); + dss_mgr_set_timings(dispc_channel, &dsi->timings); - dss_mgr_start_update(mgr); + dss_mgr_start_update(dispc_channel); if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait @@ -4105,17 +4105,17 @@ static int dsi_configure_dispc_clocks(struct platform_device *dsidev) } static int dsi_display_init_dispc(struct platform_device *dsidev, - struct omap_overlay_manager *mgr) + enum omap_channel channel) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; - dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ? + dss_select_lcd_clk_source(channel, dsi->module_id == 0 ? OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC); if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { - r = dss_mgr_register_framedone_handler(mgr, + r = dss_mgr_register_framedone_handler(channel, dsi_framedone_irq_callback, dsidev); if (r) { DSSERR("can't register FRAMEDONE handler\n"); @@ -4140,7 +4140,7 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; - dss_mgr_set_timings(mgr, &dsi->timings); + dss_mgr_set_timings(channel, &dsi->timings); r = dsi_configure_dispc_clocks(dsidev); if (r) @@ -4151,28 +4151,28 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dsi_get_pixel_size(dsi->pix_fmt); dsi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(mgr, &dsi->mgr_config); + dss_mgr_set_lcd_config(channel, &dsi->mgr_config); return 0; err1: if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) - dss_mgr_unregister_framedone_handler(mgr, + dss_mgr_unregister_framedone_handler(channel, dsi_framedone_irq_callback, dsidev); err: - dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK); return r; } static void dsi_display_uninit_dispc(struct platform_device *dsidev, - struct omap_overlay_manager *mgr) + enum omap_channel channel) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) - dss_mgr_unregister_framedone_handler(mgr, + dss_mgr_unregister_framedone_handler(channel, dsi_framedone_irq_callback, dsidev); - dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK); } static int dsi_configure_dsi_clocks(struct platform_device *dsidev) @@ -4983,18 +4983,14 @@ static int dsi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct omap_overlay_manager *mgr; + enum omap_channel dispc_channel = dssdev->dispc_channel; int r; r = dsi_regulator_init(dsidev); if (r) return r; - mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); - if (!mgr) - return -ENODEV; - - r = dss_mgr_connect(mgr, dssdev); + r = dss_mgr_connect(dispc_channel, dssdev); if (r) return r; @@ -5002,7 +4998,7 @@ static int dsi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dssdev->name); - dss_mgr_disconnect(mgr, dssdev); + dss_mgr_disconnect(dispc_channel, dssdev); return r; } @@ -5012,6 +5008,8 @@ static int dsi_connect(struct omap_dss_device *dssdev, static void dsi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + enum omap_channel dispc_channel = dssdev->dispc_channel; + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -5019,8 +5017,7 @@ static void dsi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - if (dssdev->manager) - dss_mgr_disconnect(dssdev->manager, dssdev); + dss_mgr_disconnect(dispc_channel, dssdev); } static const struct omapdss_dsi_ops dsi_ops = { diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 9a6453235585..38e6ab50142d 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -25,6 +25,8 @@ #include <linux/interrupt.h> +#include "omapdss.h" + #ifdef pr_fmt #undef pr_fmt #endif @@ -205,29 +207,6 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); int dss_set_min_bus_tput(struct device *dev, unsigned long tput); int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); -/* display */ -int dss_suspend_all_devices(void); -int dss_resume_all_devices(void); -void dss_disable_all_devices(void); - -int display_init_sysfs(struct platform_device *pdev); -void display_uninit_sysfs(struct platform_device *pdev); - -/* manager */ -int dss_init_overlay_managers(void); -void dss_uninit_overlay_managers(void); -int dss_init_overlay_managers_sysfs(struct platform_device *pdev); -void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev); -int dss_mgr_simple_check(struct omap_overlay_manager *mgr, - const struct omap_overlay_manager_info *info); -int dss_mgr_check_timings(struct omap_overlay_manager *mgr, - const struct omap_video_timings *timings); -int dss_mgr_check(struct omap_overlay_manager *mgr, - struct omap_overlay_manager_info *info, - const struct omap_video_timings *mgr_timings, - const struct dss_lcd_mgr_config *config, - struct omap_overlay_info **overlay_infos); - static inline bool dss_mgr_is_lcd(enum omap_channel id) { if (id == OMAP_DSS_CHANNEL_LCD || id == OMAP_DSS_CHANNEL_LCD2 || @@ -237,24 +216,6 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) return false; } -int dss_manager_kobj_init(struct omap_overlay_manager *mgr, - struct platform_device *pdev); -void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr); - -/* overlay */ -void dss_init_overlays(struct platform_device *pdev); -void dss_uninit_overlays(struct platform_device *pdev); -void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); -int dss_ovl_simple_check(struct omap_overlay *ovl, - const struct omap_overlay_info *info); -int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, - const struct omap_video_timings *mgr_timings); -bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, - enum omap_color_mode mode); -int dss_overlay_kobj_init(struct omap_overlay *ovl, - struct platform_device *pdev); -void dss_overlay_kobj_uninit(struct omap_overlay *ovl); - /* DSS */ int dss_init_platform_driver(void) __init; void dss_uninit_platform_driver(void); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 7103c659a534..f892ae157ff3 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -165,9 +165,10 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) { int r; struct omap_video_timings *p; - struct omap_overlay_manager *mgr = hdmi.output.manager; + enum omap_channel channel = dssdev->dispc_channel; struct hdmi_wp_data *wp = &hdmi.wp; struct dss_pll_clock_info hdmi_cinfo = { 0 }; + unsigned pc; r = hdmi_power_on_core(dssdev); if (r) @@ -181,7 +182,11 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); - hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo); + pc = p->pixelclock; + if (p->double_pixel) + pc *= 2; + + hdmi_pll_compute(&hdmi.pll, pc, &hdmi_cinfo); r = dss_pll_enable(&hdmi.pll.pll); if (r) { @@ -212,24 +217,24 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) dispc_enable_gamma_table(0); /* tv size */ - dss_mgr_set_timings(mgr, p); + dss_mgr_set_timings(channel, p); - r = hdmi_wp_video_start(&hdmi.wp); + r = dss_mgr_enable(channel); if (r) - goto err_vid_enable; + goto err_mgr_enable; - r = dss_mgr_enable(mgr); + r = hdmi_wp_video_start(&hdmi.wp); if (r) - goto err_mgr_enable; + goto err_vid_enable; hdmi_wp_set_irqenable(wp, HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); return 0; -err_mgr_enable: - hdmi_wp_video_stop(&hdmi.wp); err_vid_enable: + dss_mgr_disable(channel); +err_mgr_enable: hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: err_phy_cfg: @@ -242,14 +247,14 @@ err_pll_enable: static void hdmi_power_off_full(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = hdmi.output.manager; + enum omap_channel channel = dssdev->dispc_channel; hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); - dss_mgr_disable(mgr); - hdmi_wp_video_stop(&hdmi.wp); + dss_mgr_disable(channel); + hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); dss_pll_disable(&hdmi.pll.pll); @@ -260,9 +265,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) static int hdmi_display_check_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - struct omap_dss_device *out = &hdmi.output; - - if (!dispc_mgr_timings_ok(out->dispc_channel, timings)) + if (!dispc_mgr_timings_ok(dssdev->dispc_channel, timings)) return -EINVAL; return 0; @@ -343,7 +346,7 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - if (out->manager == NULL) { + if (!out->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; @@ -433,18 +436,14 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev) static int hdmi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - struct omap_overlay_manager *mgr; + enum omap_channel channel = dssdev->dispc_channel; int r; r = hdmi_init_regulator(); if (r) return r; - mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); - if (!mgr) - return -ENODEV; - - r = dss_mgr_connect(mgr, dssdev); + r = dss_mgr_connect(channel, dssdev); if (r) return r; @@ -452,7 +451,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(mgr, dssdev); + dss_mgr_disconnect(channel, dssdev); return r; } @@ -462,6 +461,8 @@ static int hdmi_connect(struct omap_dss_device *dssdev, static void hdmi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + enum omap_channel channel = dssdev->dispc_channel; + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -469,8 +470,7 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - if (dssdev->manager) - dss_mgr_disconnect(dssdev->manager, dssdev); + dss_mgr_disconnect(channel, dssdev); } static int hdmi_read_edid(struct omap_dss_device *dssdev, diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index a955a2c4c061..a43f7b10e113 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -182,8 +182,9 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) { int r; struct omap_video_timings *p; - struct omap_overlay_manager *mgr = hdmi.output.manager; + enum omap_channel channel = dssdev->dispc_channel; struct dss_pll_clock_info hdmi_cinfo = { 0 }; + unsigned pc; r = hdmi_power_on_core(dssdev); if (r) @@ -193,7 +194,11 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); - hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo); + pc = p->pixelclock; + if (p->double_pixel) + pc *= 2; + + hdmi_pll_compute(&hdmi.pll, pc, &hdmi_cinfo); /* disable and clear irqs */ hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); @@ -229,24 +234,24 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) dispc_enable_gamma_table(0); /* tv size */ - dss_mgr_set_timings(mgr, p); + dss_mgr_set_timings(channel, p); - r = hdmi_wp_video_start(&hdmi.wp); + r = dss_mgr_enable(channel); if (r) - goto err_vid_enable; + goto err_mgr_enable; - r = dss_mgr_enable(mgr); + r = hdmi_wp_video_start(&hdmi.wp); if (r) - goto err_mgr_enable; + goto err_vid_enable; hdmi_wp_set_irqenable(&hdmi.wp, HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); return 0; -err_mgr_enable: - hdmi_wp_video_stop(&hdmi.wp); err_vid_enable: + dss_mgr_disable(channel); +err_mgr_enable: hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: err_phy_cfg: @@ -259,14 +264,14 @@ err_pll_enable: static void hdmi_power_off_full(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = hdmi.output.manager; + enum omap_channel channel = dssdev->dispc_channel; hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); - dss_mgr_disable(mgr); - hdmi_wp_video_stop(&hdmi.wp); + dss_mgr_disable(channel); + hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); dss_pll_disable(&hdmi.pll.pll); @@ -277,13 +282,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) static int hdmi_display_check_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - struct omap_dss_device *out = &hdmi.output; - - /* TODO: proper interlace support */ - if (timings->interlace) - return -EINVAL; - - if (!dispc_mgr_timings_ok(out->dispc_channel, timings)) + if (!dispc_mgr_timings_ok(dssdev->dispc_channel, timings)) return -EINVAL; return 0; @@ -373,7 +372,7 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - if (out->manager == NULL) { + if (!out->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; @@ -463,18 +462,14 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev) static int hdmi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - struct omap_overlay_manager *mgr; + enum omap_channel channel = dssdev->dispc_channel; int r; r = hdmi_init_regulator(); if (r) return r; - mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); - if (!mgr) - return -ENODEV; - - r = dss_mgr_connect(mgr, dssdev); + r = dss_mgr_connect(channel, dssdev); if (r) return r; @@ -482,7 +477,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(mgr, dssdev); + dss_mgr_disconnect(channel, dssdev); return r; } @@ -492,6 +487,8 @@ static int hdmi_connect(struct omap_dss_device *dssdev, static void hdmi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + enum omap_channel channel = dssdev->dispc_channel; + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -499,8 +496,7 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - if (dssdev->manager) - dss_mgr_disconnect(dssdev->manager, dssdev); + dss_mgr_disconnect(channel, dssdev); } static int hdmi_read_edid(struct omap_dss_device *dssdev, diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c index 8ea531d2652c..6a397520cae5 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -292,25 +292,36 @@ static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg, { DSSDBG("hdmi_core_init\n"); + video_cfg->v_fc_config.timings = cfg->timings; + /* video core */ video_cfg->data_enable_pol = 1; /* It is always 1*/ - video_cfg->v_fc_config.timings.hsync_level = cfg->timings.hsync_level; - video_cfg->v_fc_config.timings.x_res = cfg->timings.x_res; - video_cfg->v_fc_config.timings.hsw = cfg->timings.hsw - 1; - video_cfg->v_fc_config.timings.hbp = cfg->timings.hbp; - video_cfg->v_fc_config.timings.hfp = cfg->timings.hfp; video_cfg->hblank = cfg->timings.hfp + - cfg->timings.hbp + cfg->timings.hsw - 1; - video_cfg->v_fc_config.timings.vsync_level = cfg->timings.vsync_level; - video_cfg->v_fc_config.timings.y_res = cfg->timings.y_res; - video_cfg->v_fc_config.timings.vsw = cfg->timings.vsw; - video_cfg->v_fc_config.timings.vfp = cfg->timings.vfp; - video_cfg->v_fc_config.timings.vbp = cfg->timings.vbp; - video_cfg->vblank_osc = 0; /* Always 0 - need to confirm */ + cfg->timings.hbp + cfg->timings.hsw; + video_cfg->vblank_osc = 0; video_cfg->vblank = cfg->timings.vsw + cfg->timings.vfp + cfg->timings.vbp; video_cfg->v_fc_config.hdmi_dvi_mode = cfg->hdmi_dvi_mode; - video_cfg->v_fc_config.timings.interlace = cfg->timings.interlace; + + if (cfg->timings.interlace) { + /* set vblank_osc if vblank is fractional */ + if (video_cfg->vblank % 2 != 0) + video_cfg->vblank_osc = 1; + + video_cfg->v_fc_config.timings.y_res /= 2; + video_cfg->vblank /= 2; + video_cfg->v_fc_config.timings.vfp /= 2; + video_cfg->v_fc_config.timings.vsw /= 2; + video_cfg->v_fc_config.timings.vbp /= 2; + } + + if (cfg->timings.double_pixel) { + video_cfg->v_fc_config.timings.x_res *= 2; + video_cfg->hblank *= 2; + video_cfg->v_fc_config.timings.hfp *= 2; + video_cfg->v_fc_config.timings.hsw *= 2; + video_cfg->v_fc_config.timings.hbp *= 2; + } } /* DSS_HDMI_CORE_VIDEO_CONFIG */ @@ -377,6 +388,11 @@ static void hdmi_core_video_config(struct hdmi_core_data *core, /* select DVI mode */ REG_FLD_MOD(base, HDMI_CORE_FC_INVIDCONF, cfg->v_fc_config.hdmi_dvi_mode, 3, 3); + + if (cfg->v_fc_config.timings.double_pixel) + REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, 2, 7, 4); + else + REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, 1, 7, 4); } static void hdmi_core_config_video_packetizer(struct hdmi_core_data *core) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c index 7c544bc56fb5..13442b9052d1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c @@ -165,12 +165,24 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp, { u32 timing_h = 0; u32 timing_v = 0; + unsigned hsw_offset = 1; DSSDBG("Enter hdmi_wp_video_config_timing\n"); + /* + * On OMAP4 and OMAP5 ES1 the HSW field is programmed as is. On OMAP5 + * ES2+ (including DRA7/AM5 SoCs) HSW field is programmed to hsw-1. + * However, we don't support OMAP5 ES1 at all, so we can just check for + * OMAP4 here. + */ + if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 || + omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 || + omapdss_get_version() == OMAPDSS_VER_OMAP4) + hsw_offset = 0; + timing_h |= FLD_VAL(timings->hbp, 31, 20); timing_h |= FLD_VAL(timings->hfp, 19, 8); - timing_h |= FLD_VAL(timings->hsw, 7, 0); + timing_h |= FLD_VAL(timings->hsw - hsw_offset, 7, 0); hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h); timing_v |= FLD_VAL(timings->vbp, 31, 20); @@ -187,8 +199,6 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; video_fmt->y_res = param->timings.y_res; video_fmt->x_res = param->timings.x_res; - if (param->timings.interlace) - video_fmt->y_res /= 2; timings->hbp = param->timings.hbp; timings->hfp = param->timings.hfp; @@ -196,9 +206,25 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, timings->vbp = param->timings.vbp; timings->vfp = param->timings.vfp; timings->vsw = param->timings.vsw; + timings->vsync_level = param->timings.vsync_level; timings->hsync_level = param->timings.hsync_level; timings->interlace = param->timings.interlace; + timings->double_pixel = param->timings.double_pixel; + + if (param->timings.interlace) { + video_fmt->y_res /= 2; + timings->vbp /= 2; + timings->vfp /= 2; + timings->vsw /= 2; + } + + if (param->timings.double_pixel) { + video_fmt->x_res *= 2; + timings->hfp *= 2; + timings->hsw *= 2; + timings->hbp *= 2; + } } void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, diff --git a/drivers/gpu/drm/omapdrm/dss/manager-sysfs.c b/drivers/gpu/drm/omapdrm/dss/manager-sysfs.c deleted file mode 100644 index a7414fb12830..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/manager-sysfs.c +++ /dev/null @@ -1,531 +0,0 @@ -/* - * 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 "MANAGER" - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/jiffies.h> - -#include <video/omapdss.h> - -#include "dss.h" -#include "dss_features.h" - -static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); -} - -static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) -{ - struct omap_dss_device *dssdev = mgr->get_device(mgr); - - return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ? - dssdev->name : "<none>"); -} - -static int manager_display_match(struct omap_dss_device *dssdev, void *data) -{ - const char *str = data; - - return sysfs_streq(dssdev->name, str); -} - -static ssize_t manager_display_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - int r = 0; - size_t len = size; - struct omap_dss_device *dssdev = NULL; - struct omap_dss_device *old_dssdev; - - if (buf[size-1] == '\n') - --len; - - if (len > 0) - dssdev = omap_dss_find_device((void *)buf, - manager_display_match); - - if (len > 0 && dssdev == NULL) - return -EINVAL; - - if (dssdev) { - DSSDBG("display %s found\n", dssdev->name); - - if (omapdss_device_is_connected(dssdev)) { - DSSERR("new display is already connected\n"); - r = -EINVAL; - goto put_device; - } - - if (omapdss_device_is_enabled(dssdev)) { - DSSERR("new display is not disabled\n"); - r = -EINVAL; - goto put_device; - } - } - - old_dssdev = mgr->get_device(mgr); - if (old_dssdev) { - if (omapdss_device_is_enabled(old_dssdev)) { - DSSERR("old display is not disabled\n"); - r = -EINVAL; - goto put_device; - } - - old_dssdev->driver->disconnect(old_dssdev); - } - - if (dssdev) { - r = dssdev->driver->connect(dssdev); - if (r) { - DSSERR("failed to connect new device\n"); - goto put_device; - } - - old_dssdev = mgr->get_device(mgr); - if (old_dssdev != dssdev) { - DSSERR("failed to connect device to this manager\n"); - dssdev->driver->disconnect(dssdev); - goto put_device; - } - - r = mgr->apply(mgr); - if (r) { - DSSERR("failed to apply dispc config\n"); - goto put_device; - } - } - -put_device: - if (dssdev) - omap_dss_put_device(dssdev); - - return r ? r : size; -} - -static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); -} - -static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - u32 color; - int r; - - r = kstrtouint(buf, 0, &color); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.default_color = color; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static const char *trans_key_type_str[] = { - "gfx-destination", - "video-source", -}; - -static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, - char *buf) -{ - enum omap_dss_trans_key_type key_type; - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - key_type = info.trans_key_type; - BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); - - return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); -} - -static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - enum omap_dss_trans_key_type key_type; - struct omap_overlay_manager_info info; - int r; - - for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; - key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { - if (sysfs_streq(buf, trans_key_type_str[key_type])) - break; - } - - if (key_type == ARRAY_SIZE(trans_key_type_str)) - return -EINVAL; - - mgr->get_manager_info(mgr, &info); - - info.trans_key_type = key_type; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); -} - -static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - u32 key_value; - int r; - - r = kstrtouint(buf, 0, &key_value); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.trans_key = key_value; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); -} - -static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - bool enable; - int r; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.trans_enabled = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_alpha_blending_enabled_show( - struct omap_overlay_manager *mgr, char *buf) -{ - struct omap_overlay_manager_info info; - - if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) - return -ENODEV; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.partial_alpha_enabled); -} - -static ssize_t manager_alpha_blending_enabled_store( - struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - bool enable; - int r; - - if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) - return -ENODEV; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.partial_alpha_enabled = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); -} - -static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - int r; - bool enable; - - if (!dss_has_feature(FEAT_CPR)) - return -ENODEV; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - if (info.cpr_enable == enable) - return size; - - info.cpr_enable = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, - "%d %d %d %d %d %d %d %d %d\n", - info.cpr_coefs.rr, - info.cpr_coefs.rg, - info.cpr_coefs.rb, - info.cpr_coefs.gr, - info.cpr_coefs.gg, - info.cpr_coefs.gb, - info.cpr_coefs.br, - info.cpr_coefs.bg, - info.cpr_coefs.bb); -} - -static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - struct omap_dss_cpr_coefs coefs; - int r, i; - s16 *arr; - - if (!dss_has_feature(FEAT_CPR)) - return -ENODEV; - - if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", - &coefs.rr, &coefs.rg, &coefs.rb, - &coefs.gr, &coefs.gg, &coefs.gb, - &coefs.br, &coefs.bg, &coefs.bb) != 9) - return -EINVAL; - - arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, - coefs.gr, coefs.gg, coefs.gb, - coefs.br, coefs.bg, coefs.bb }; - - for (i = 0; i < 9; ++i) { - if (arr[i] < -512 || arr[i] > 511) - return -EINVAL; - } - - mgr->get_manager_info(mgr, &info); - - info.cpr_coefs = coefs; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -struct manager_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_overlay_manager *, char *); - ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); -}; - -#define MANAGER_ATTR(_name, _mode, _show, _store) \ - struct manager_attribute manager_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); -static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, - manager_display_show, manager_display_store); -static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, - manager_default_color_show, manager_default_color_store); -static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, - manager_trans_key_type_show, manager_trans_key_type_store); -static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, - manager_trans_key_value_show, manager_trans_key_value_store); -static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, - manager_trans_key_enabled_show, - manager_trans_key_enabled_store); -static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, - manager_alpha_blending_enabled_show, - manager_alpha_blending_enabled_store); -static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, - manager_cpr_enable_show, - manager_cpr_enable_store); -static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, - manager_cpr_coef_show, - manager_cpr_coef_store); - - -static struct attribute *manager_sysfs_attrs[] = { - &manager_attr_name.attr, - &manager_attr_display.attr, - &manager_attr_default_color.attr, - &manager_attr_trans_key_type.attr, - &manager_attr_trans_key_value.attr, - &manager_attr_trans_key_enabled.attr, - &manager_attr_alpha_blending_enabled.attr, - &manager_attr_cpr_enable.attr, - &manager_attr_cpr_coef.attr, - NULL -}; - -static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_overlay_manager *manager; - struct manager_attribute *manager_attr; - - manager = container_of(kobj, struct omap_overlay_manager, kobj); - manager_attr = container_of(attr, struct manager_attribute, attr); - - if (!manager_attr->show) - return -ENOENT; - - return manager_attr->show(manager, buf); -} - -static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_overlay_manager *manager; - struct manager_attribute *manager_attr; - - manager = container_of(kobj, struct omap_overlay_manager, kobj); - manager_attr = container_of(attr, struct manager_attribute, attr); - - if (!manager_attr->store) - return -ENOENT; - - return manager_attr->store(manager, buf, size); -} - -static const struct sysfs_ops manager_sysfs_ops = { - .show = manager_attr_show, - .store = manager_attr_store, -}; - -static struct kobj_type manager_ktype = { - .sysfs_ops = &manager_sysfs_ops, - .default_attrs = manager_sysfs_attrs, -}; - -int dss_manager_kobj_init(struct omap_overlay_manager *mgr, - struct platform_device *pdev) -{ - return kobject_init_and_add(&mgr->kobj, &manager_ktype, - &pdev->dev.kobj, "manager%d", mgr->id); -} - -void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) -{ - kobject_del(&mgr->kobj); - kobject_put(&mgr->kobj); - - memset(&mgr->kobj, 0, sizeof(mgr->kobj)); -} diff --git a/drivers/gpu/drm/omapdrm/dss/manager.c b/drivers/gpu/drm/omapdrm/dss/manager.c deleted file mode 100644 index 08a67f4f6a20..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/manager.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * linux/drivers/video/omap2/dss/manager.c - * - * 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 "MANAGER" - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/jiffies.h> - -#include <video/omapdss.h> - -#include "dss.h" -#include "dss_features.h" - -static int num_managers; -static struct omap_overlay_manager *managers; - -int dss_init_overlay_managers(void) -{ - int i; - - num_managers = dss_feat_get_num_mgrs(); - - managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, - GFP_KERNEL); - - BUG_ON(managers == NULL); - - for (i = 0; i < num_managers; ++i) { - struct omap_overlay_manager *mgr = &managers[i]; - - switch (i) { - case 0: - mgr->name = "lcd"; - mgr->id = OMAP_DSS_CHANNEL_LCD; - break; - case 1: - mgr->name = "tv"; - mgr->id = OMAP_DSS_CHANNEL_DIGIT; - break; - case 2: - mgr->name = "lcd2"; - mgr->id = OMAP_DSS_CHANNEL_LCD2; - break; - case 3: - mgr->name = "lcd3"; - mgr->id = OMAP_DSS_CHANNEL_LCD3; - break; - } - - mgr->caps = 0; - mgr->supported_displays = - dss_feat_get_supported_displays(mgr->id); - mgr->supported_outputs = - dss_feat_get_supported_outputs(mgr->id); - - INIT_LIST_HEAD(&mgr->overlays); - } - - return 0; -} - -int dss_init_overlay_managers_sysfs(struct platform_device *pdev) -{ - int i, r; - - for (i = 0; i < num_managers; ++i) { - struct omap_overlay_manager *mgr = &managers[i]; - - r = dss_manager_kobj_init(mgr, pdev); - if (r) - DSSERR("failed to create sysfs file\n"); - } - - return 0; -} - -void dss_uninit_overlay_managers(void) -{ - kfree(managers); - managers = NULL; - num_managers = 0; -} - -void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev) -{ - int i; - - for (i = 0; i < num_managers; ++i) { - struct omap_overlay_manager *mgr = &managers[i]; - - dss_manager_kobj_uninit(mgr); - } -} - -int omap_dss_get_num_overlay_managers(void) -{ - return num_managers; -} -EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); - -struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) -{ - if (num >= num_managers) - return NULL; - - return &managers[num]; -} -EXPORT_SYMBOL(omap_dss_get_overlay_manager); - -int dss_mgr_simple_check(struct omap_overlay_manager *mgr, - const struct omap_overlay_manager_info *info) -{ - if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { - /* - * OMAP3 supports only graphics source transparency color key - * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 - * Alpha Mode. - */ - if (info->partial_alpha_enabled && info->trans_enabled - && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { - DSSERR("check_manager: illegal transparency key\n"); - return -EINVAL; - } - } - - return 0; -} - -static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, - struct omap_overlay_info **overlay_infos) -{ - struct omap_overlay *ovl1, *ovl2; - struct omap_overlay_info *info1, *info2; - - list_for_each_entry(ovl1, &mgr->overlays, list) { - info1 = overlay_infos[ovl1->id]; - - if (info1 == NULL) - continue; - - list_for_each_entry(ovl2, &mgr->overlays, list) { - if (ovl1 == ovl2) - continue; - - info2 = overlay_infos[ovl2->id]; - - if (info2 == NULL) - continue; - - if (info1->zorder == info2->zorder) { - DSSERR("overlays %d and %d have the same " - "zorder %d\n", - ovl1->id, ovl2->id, info1->zorder); - return -EINVAL; - } - } - } - - return 0; -} - -int dss_mgr_check_timings(struct omap_overlay_manager *mgr, - const struct omap_video_timings *timings) -{ - if (!dispc_mgr_timings_ok(mgr->id, timings)) { - DSSERR("check_manager: invalid timings\n"); - return -EINVAL; - } - - return 0; -} - -static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr, - const struct dss_lcd_mgr_config *config) -{ - struct dispc_clock_info cinfo = config->clock_info; - int dl = config->video_port_width; - bool stallmode = config->stallmode; - bool fifohandcheck = config->fifohandcheck; - - if (cinfo.lck_div < 1 || cinfo.lck_div > 255) - return -EINVAL; - - if (cinfo.pck_div < 1 || cinfo.pck_div > 255) - return -EINVAL; - - if (dl != 12 && dl != 16 && dl != 18 && dl != 24) - return -EINVAL; - - /* fifohandcheck should be used only with stallmode */ - if (!stallmode && fifohandcheck) - return -EINVAL; - - /* - * io pad mode can be only checked by using dssdev connected to the - * manager. Ignore checking these for now, add checks when manager - * is capable of holding information related to the connected interface - */ - - return 0; -} - -int dss_mgr_check(struct omap_overlay_manager *mgr, - struct omap_overlay_manager_info *info, - const struct omap_video_timings *mgr_timings, - const struct dss_lcd_mgr_config *lcd_config, - struct omap_overlay_info **overlay_infos) -{ - struct omap_overlay *ovl; - int r; - - if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { - r = dss_mgr_check_zorder(mgr, overlay_infos); - if (r) - return r; - } - - r = dss_mgr_check_timings(mgr, mgr_timings); - if (r) - return r; - - r = dss_mgr_check_lcd_config(mgr, lcd_config); - if (r) - return r; - - list_for_each_entry(ovl, &mgr->overlays, list) { - struct omap_overlay_info *oi; - int r; - - oi = overlay_infos[ovl->id]; - - if (oi == NULL) - continue; - - r = dss_ovl_check(ovl, oi, mgr_timings); - if (r) - return r; - } - - return 0; -} diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h new file mode 100644 index 000000000000..d7e7c909bbc2 --- /dev/null +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 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 __OMAP_DRM_DSS_H +#define __OMAP_DRM_DSS_H + +#include <video/omapdss.h> + +u32 dispc_read_irqstatus(void); +void dispc_clear_irqstatus(u32 mask); +u32 dispc_read_irqenable(void); +void dispc_write_irqenable(u32 mask); + +int dispc_request_irq(irq_handler_t handler, void *dev_id); +void dispc_free_irq(void *dev_id); + +int dispc_runtime_get(void); +void dispc_runtime_put(void); + +void dispc_mgr_enable(enum omap_channel channel, bool enable); +bool dispc_mgr_is_enabled(enum omap_channel channel); +u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); +u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); +u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel); +bool dispc_mgr_go_busy(enum omap_channel channel); +void dispc_mgr_go(enum omap_channel channel); +void dispc_mgr_set_lcd_config(enum omap_channel channel, + const struct dss_lcd_mgr_config *config); +void dispc_mgr_set_timings(enum omap_channel channel, + const struct omap_video_timings *timings); +void dispc_mgr_setup(enum omap_channel channel, + const struct omap_overlay_manager_info *info); + +int dispc_ovl_enable(enum omap_plane plane, bool enable); +bool dispc_ovl_enabled(enum omap_plane plane); +void dispc_ovl_set_channel_out(enum omap_plane plane, + enum omap_channel channel); +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); + +enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel); + +struct dss_mgr_ops { + int (*connect)(enum omap_channel channel, + struct omap_dss_device *dst); + void (*disconnect)(enum omap_channel channel, + struct omap_dss_device *dst); + + void (*start_update)(enum omap_channel channel); + int (*enable)(enum omap_channel channel); + void (*disable)(enum omap_channel channel); + void (*set_timings)(enum omap_channel channel, + const struct omap_video_timings *timings); + void (*set_lcd_config)(enum omap_channel channel, + const struct dss_lcd_mgr_config *config); + int (*register_framedone_handler)(enum omap_channel channel, + void (*handler)(void *), void *data); + void (*unregister_framedone_handler)(enum omap_channel channel, + void (*handler)(void *), void *data); +}; + +int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops); +void dss_uninstall_mgr_ops(void); + +int dss_mgr_connect(enum omap_channel channel, + struct omap_dss_device *dst); +void dss_mgr_disconnect(enum omap_channel channel, + struct omap_dss_device *dst); +void dss_mgr_set_timings(enum omap_channel channel, + const struct omap_video_timings *timings); +void dss_mgr_set_lcd_config(enum omap_channel channel, + const struct dss_lcd_mgr_config *config); +int dss_mgr_enable(enum omap_channel channel); +void dss_mgr_disable(enum omap_channel channel); +void dss_mgr_start_update(enum omap_channel channel); +int dss_mgr_register_framedone_handler(enum omap_channel channel, + void (*handler)(void *), void *data); +void dss_mgr_unregister_framedone_handler(enum omap_channel channel, + void (*handler)(void *), void *data); + +#endif /* __OMAP_DRM_DSS_H */ diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 16072159bd24..829232ad8c81 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -169,24 +169,6 @@ struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device } EXPORT_SYMBOL(omapdss_find_output_from_display); -struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev) -{ - struct omap_dss_device *out; - struct omap_overlay_manager *mgr; - - out = omapdss_find_output_from_display(dssdev); - - if (out == NULL) - return NULL; - - mgr = out->manager; - - omap_dss_put_device(out); - - return mgr; -} -EXPORT_SYMBOL(omapdss_find_mgr_from_display); - static const struct dss_mgr_ops *dss_mgr_ops; int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) @@ -206,62 +188,62 @@ void dss_uninstall_mgr_ops(void) } EXPORT_SYMBOL(dss_uninstall_mgr_ops); -int dss_mgr_connect(struct omap_overlay_manager *mgr, +int dss_mgr_connect(enum omap_channel channel, struct omap_dss_device *dst) { - return dss_mgr_ops->connect(mgr, dst); + return dss_mgr_ops->connect(channel, dst); } EXPORT_SYMBOL(dss_mgr_connect); -void dss_mgr_disconnect(struct omap_overlay_manager *mgr, +void dss_mgr_disconnect(enum omap_channel channel, struct omap_dss_device *dst) { - dss_mgr_ops->disconnect(mgr, dst); + dss_mgr_ops->disconnect(channel, dst); } EXPORT_SYMBOL(dss_mgr_disconnect); -void dss_mgr_set_timings(struct omap_overlay_manager *mgr, +void dss_mgr_set_timings(enum omap_channel channel, const struct omap_video_timings *timings) { - dss_mgr_ops->set_timings(mgr, timings); + dss_mgr_ops->set_timings(channel, timings); } EXPORT_SYMBOL(dss_mgr_set_timings); -void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, +void dss_mgr_set_lcd_config(enum omap_channel channel, const struct dss_lcd_mgr_config *config) { - dss_mgr_ops->set_lcd_config(mgr, config); + dss_mgr_ops->set_lcd_config(channel, config); } EXPORT_SYMBOL(dss_mgr_set_lcd_config); -int dss_mgr_enable(struct omap_overlay_manager *mgr) +int dss_mgr_enable(enum omap_channel channel) { - return dss_mgr_ops->enable(mgr); + return dss_mgr_ops->enable(channel); } EXPORT_SYMBOL(dss_mgr_enable); -void dss_mgr_disable(struct omap_overlay_manager *mgr) +void dss_mgr_disable(enum omap_channel channel) { - dss_mgr_ops->disable(mgr); + dss_mgr_ops->disable(channel); } EXPORT_SYMBOL(dss_mgr_disable); -void dss_mgr_start_update(struct omap_overlay_manager *mgr) +void dss_mgr_start_update(enum omap_channel channel) { - dss_mgr_ops->start_update(mgr); + dss_mgr_ops->start_update(channel); } EXPORT_SYMBOL(dss_mgr_start_update); -int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr, +int dss_mgr_register_framedone_handler(enum omap_channel channel, void (*handler)(void *), void *data) { - return dss_mgr_ops->register_framedone_handler(mgr, handler, data); + return dss_mgr_ops->register_framedone_handler(channel, handler, data); } EXPORT_SYMBOL(dss_mgr_register_framedone_handler); -void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr, +void dss_mgr_unregister_framedone_handler(enum omap_channel channel, void (*handler)(void *), void *data) { - dss_mgr_ops->unregister_framedone_handler(mgr, handler, data); + dss_mgr_ops->unregister_framedone_handler(channel, handler, data); } EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); diff --git a/drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c b/drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c deleted file mode 100644 index 4cc5ddebfb34..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * 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 "OVERLAY" - -#include <linux/module.h> -#include <linux/err.h> -#include <linux/sysfs.h> -#include <linux/kobject.h> -#include <linux/platform_device.h> - -#include <video/omapdss.h> - -#include "dss.h" -#include "dss_features.h" - -static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); -} - -static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", - ovl->manager ? ovl->manager->name : "<none>"); -} - -static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, - size_t size) -{ - int i, r; - struct omap_overlay_manager *mgr = NULL; - struct omap_overlay_manager *old_mgr; - int len = size; - - if (buf[size-1] == '\n') - --len; - - if (len > 0) { - for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { - mgr = omap_dss_get_overlay_manager(i); - - if (sysfs_streq(buf, mgr->name)) - break; - - mgr = NULL; - } - } - - if (len > 0 && mgr == NULL) - return -EINVAL; - - if (mgr) - DSSDBG("manager %s found\n", mgr->name); - - if (mgr == ovl->manager) - return size; - - old_mgr = ovl->manager; - - r = dispc_runtime_get(); - if (r) - return r; - - /* detach old manager */ - if (old_mgr) { - r = ovl->unset_manager(ovl); - if (r) { - DSSERR("detach failed\n"); - goto err; - } - - r = old_mgr->apply(old_mgr); - if (r) - goto err; - } - - if (mgr) { - r = ovl->set_manager(ovl, mgr); - if (r) { - DSSERR("Failed to attach overlay\n"); - goto err; - } - - r = mgr->apply(mgr); - if (r) - goto err; - } - - dispc_runtime_put(); - - return size; - -err: - dispc_runtime_put(); - return r; -} - -static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.width, info.height); -} - -static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); -} - -static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.pos_x, info.pos_y); -} - -static ssize_t overlay_position_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - char *last; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - info.pos_x = simple_strtoul(buf, &last, 10); - ++last; - if (last - buf >= size) - return -EINVAL; - - info.pos_y = simple_strtoul(last, &last, 10); - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.out_width, info.out_height); -} - -static ssize_t overlay_output_size_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - char *last; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - info.out_width = simple_strtoul(buf, &last, 10); - ++last; - if (last - buf >= size) - return -EINVAL; - - info.out_height = simple_strtoul(last, &last, 10); - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); -} - -static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, - size_t size) -{ - int r; - bool enable; - - r = strtobool(buf, &enable); - if (r) - return r; - - if (enable) - r = ovl->enable(ovl); - else - r = ovl->disable(ovl); - - if (r) - return r; - - return size; -} - -static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.global_alpha); -} - -static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 alpha; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &alpha); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.global_alpha = alpha; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, - char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.pre_mult_alpha); -} - -static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 alpha; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &alpha); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.pre_mult_alpha = alpha; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); -} - -static ssize_t overlay_zorder_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 zorder; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &zorder); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.zorder = zorder; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -struct overlay_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_overlay *, char *); - ssize_t (*store)(struct omap_overlay *, const char *, size_t); -}; - -#define OVERLAY_ATTR(_name, _mode, _show, _store) \ - struct overlay_attribute overlay_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); -static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, - overlay_manager_show, overlay_manager_store); -static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); -static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); -static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, - overlay_position_show, overlay_position_store); -static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, - overlay_output_size_show, overlay_output_size_store); -static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, - overlay_enabled_show, overlay_enabled_store); -static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, - overlay_global_alpha_show, overlay_global_alpha_store); -static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, - overlay_pre_mult_alpha_show, - overlay_pre_mult_alpha_store); -static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, - overlay_zorder_show, overlay_zorder_store); - -static struct attribute *overlay_sysfs_attrs[] = { - &overlay_attr_name.attr, - &overlay_attr_manager.attr, - &overlay_attr_input_size.attr, - &overlay_attr_screen_width.attr, - &overlay_attr_position.attr, - &overlay_attr_output_size.attr, - &overlay_attr_enabled.attr, - &overlay_attr_global_alpha.attr, - &overlay_attr_pre_mult_alpha.attr, - &overlay_attr_zorder.attr, - NULL -}; - -static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_overlay *overlay; - struct overlay_attribute *overlay_attr; - - overlay = container_of(kobj, struct omap_overlay, kobj); - overlay_attr = container_of(attr, struct overlay_attribute, attr); - - if (!overlay_attr->show) - return -ENOENT; - - return overlay_attr->show(overlay, buf); -} - -static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_overlay *overlay; - struct overlay_attribute *overlay_attr; - - overlay = container_of(kobj, struct omap_overlay, kobj); - overlay_attr = container_of(attr, struct overlay_attribute, attr); - - if (!overlay_attr->store) - return -ENOENT; - - return overlay_attr->store(overlay, buf, size); -} - -static const struct sysfs_ops overlay_sysfs_ops = { - .show = overlay_attr_show, - .store = overlay_attr_store, -}; - -static struct kobj_type overlay_ktype = { - .sysfs_ops = &overlay_sysfs_ops, - .default_attrs = overlay_sysfs_attrs, -}; - -int dss_overlay_kobj_init(struct omap_overlay *ovl, - struct platform_device *pdev) -{ - return kobject_init_and_add(&ovl->kobj, &overlay_ktype, - &pdev->dev.kobj, "overlay%d", ovl->id); -} - -void dss_overlay_kobj_uninit(struct omap_overlay *ovl) -{ - kobject_del(&ovl->kobj); - kobject_put(&ovl->kobj); -} diff --git a/drivers/gpu/drm/omapdrm/dss/overlay.c b/drivers/gpu/drm/omapdrm/dss/overlay.c deleted file mode 100644 index 2f7cee985cdd..000000000000 --- a/drivers/gpu/drm/omapdrm/dss/overlay.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * linux/drivers/video/omap2/dss/overlay.c - * - * 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 "OVERLAY" - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/err.h> -#include <linux/sysfs.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/slab.h> - -#include <video/omapdss.h> - -#include "dss.h" -#include "dss_features.h" - -static int num_overlays; -static struct omap_overlay *overlays; - -int omap_dss_get_num_overlays(void) -{ - return num_overlays; -} -EXPORT_SYMBOL(omap_dss_get_num_overlays); - -struct omap_overlay *omap_dss_get_overlay(int num) -{ - if (num >= num_overlays) - return NULL; - - return &overlays[num]; -} -EXPORT_SYMBOL(omap_dss_get_overlay); - -void dss_init_overlays(struct platform_device *pdev) -{ - int i, r; - - num_overlays = dss_feat_get_num_ovls(); - - overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays, - GFP_KERNEL); - - BUG_ON(overlays == NULL); - - for (i = 0; i < num_overlays; ++i) { - struct omap_overlay *ovl = &overlays[i]; - - switch (i) { - case 0: - ovl->name = "gfx"; - ovl->id = OMAP_DSS_GFX; - break; - case 1: - ovl->name = "vid1"; - ovl->id = OMAP_DSS_VIDEO1; - break; - case 2: - ovl->name = "vid2"; - ovl->id = OMAP_DSS_VIDEO2; - break; - case 3: - ovl->name = "vid3"; - ovl->id = OMAP_DSS_VIDEO3; - break; - } - - ovl->caps = dss_feat_get_overlay_caps(ovl->id); - ovl->supported_modes = - dss_feat_get_supported_color_modes(ovl->id); - - r = dss_overlay_kobj_init(ovl, pdev); - if (r) - DSSERR("failed to create sysfs file\n"); - } -} - -void dss_uninit_overlays(struct platform_device *pdev) -{ - int i; - - for (i = 0; i < num_overlays; ++i) { - struct omap_overlay *ovl = &overlays[i]; - dss_overlay_kobj_uninit(ovl); - } - - kfree(overlays); - overlays = NULL; - num_overlays = 0; -} - -int dss_ovl_simple_check(struct omap_overlay *ovl, - const struct omap_overlay_info *info) -{ - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { - if (info->out_width != 0 && info->width != info->out_width) { - DSSERR("check_overlay: overlay %d doesn't support " - "scaling\n", ovl->id); - return -EINVAL; - } - - if (info->out_height != 0 && info->height != info->out_height) { - DSSERR("check_overlay: overlay %d doesn't support " - "scaling\n", ovl->id); - return -EINVAL; - } - } - - if ((ovl->supported_modes & info->color_mode) == 0) { - DSSERR("check_overlay: overlay %d doesn't support mode %d\n", - ovl->id, info->color_mode); - return -EINVAL; - } - - if (info->zorder >= omap_dss_get_num_overlays()) { - DSSERR("check_overlay: zorder %d too high\n", info->zorder); - return -EINVAL; - } - - if (dss_feat_rotation_type_supported(info->rotation_type) == 0) { - DSSERR("check_overlay: rotation type %d not supported\n", - info->rotation_type); - return -EINVAL; - } - - return 0; -} - -int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, - const struct omap_video_timings *mgr_timings) -{ - u16 outw, outh; - u16 dw, dh; - - dw = mgr_timings->x_res; - dh = mgr_timings->y_res; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { - outw = info->width; - outh = info->height; - } else { - if (info->out_width == 0) - outw = info->width; - else - outw = info->out_width; - - if (info->out_height == 0) - outh = info->height; - else - outh = info->out_height; - } - - if (dw < info->pos_x + outw) { - DSSERR("overlay %d horizontally not inside the display area " - "(%d + %d >= %d)\n", - ovl->id, info->pos_x, outw, dw); - return -EINVAL; - } - - if (dh < info->pos_y + outh) { - DSSERR("overlay %d vertically not inside the display area " - "(%d + %d >= %d)\n", - ovl->id, info->pos_y, outh, dh); - return -EINVAL; - } - - return 0; -} - -/* - * Checks if replication logic should be used. Only use when overlay is in - * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp - */ -bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, - enum omap_color_mode mode) -{ - if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) - return false; - - return config.video_port_width > 16; -} diff --git a/drivers/gpu/drm/omapdrm/dss/rfbi.c b/drivers/gpu/drm/omapdrm/dss/rfbi.c index aea6a1d0fb20..3796576dfadf 100644 --- a/drivers/gpu/drm/omapdrm/dss/rfbi.c +++ b/drivers/gpu/drm/omapdrm/dss/rfbi.c @@ -880,7 +880,7 @@ static int rfbi_display_enable(struct omap_dss_device *dssdev) struct omap_dss_device *out = &rfbi.output; int r; - if (out->manager == NULL) { + if (!out->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index d747cc6b59e1..cd6d3bfb041d 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -114,7 +114,7 @@ static int sdi_calc_clock_div(unsigned long pclk, static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = sdi.output.manager; + enum omap_channel channel = dssdev->dispc_channel; sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; @@ -124,19 +124,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) sdi.mgr_config.video_port_width = 24; sdi.mgr_config.lcden_sig_polarity = 1; - dss_mgr_set_lcd_config(mgr, &sdi.mgr_config); + dss_mgr_set_lcd_config(channel, &sdi.mgr_config); } static int sdi_display_enable(struct omap_dss_device *dssdev) { struct omap_dss_device *out = &sdi.output; + enum omap_channel channel = dssdev->dispc_channel; struct omap_video_timings *t = &sdi.timings; unsigned long fck; struct dispc_clock_info dispc_cinfo; unsigned long pck; int r; - if (out->manager == NULL) { + if (!out->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } @@ -169,7 +170,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) } - dss_mgr_set_timings(out->manager, t); + dss_mgr_set_timings(channel, t); r = dss_set_fck_rate(fck); if (r) @@ -188,7 +189,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) * need to care about the shadow register mechanism for pck-free. The * exact reason for this is unknown. */ - dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info); + dispc_mgr_set_clock_div(channel, &sdi.mgr_config.clock_info); dss_sdi_init(sdi.datapairs); r = dss_sdi_enable(); @@ -196,7 +197,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) goto err_sdi_enable; mdelay(2); - r = dss_mgr_enable(out->manager); + r = dss_mgr_enable(channel); if (r) goto err_mgr_enable; @@ -216,9 +217,9 @@ err_reg_enable: static void sdi_display_disable(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = sdi.output.manager; + enum omap_channel channel = dssdev->dispc_channel; - dss_mgr_disable(mgr); + dss_mgr_disable(channel); dss_sdi_disable(); @@ -242,9 +243,9 @@ static void sdi_get_timings(struct omap_dss_device *dssdev, static int sdi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - struct omap_overlay_manager *mgr = sdi.output.manager; + enum omap_channel channel = dssdev->dispc_channel; - if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) + if (!dispc_mgr_timings_ok(channel, timings)) return -EINVAL; if (timings->pixelclock == 0) @@ -280,18 +281,14 @@ static int sdi_init_regulator(void) static int sdi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - struct omap_overlay_manager *mgr; + enum omap_channel channel = dssdev->dispc_channel; int r; r = sdi_init_regulator(); if (r) return r; - mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); - if (!mgr) - return -ENODEV; - - r = dss_mgr_connect(mgr, dssdev); + r = dss_mgr_connect(channel, dssdev); if (r) return r; @@ -299,7 +296,7 @@ static int sdi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(mgr, dssdev); + dss_mgr_disconnect(channel, dssdev); return r; } @@ -309,6 +306,8 @@ static int sdi_connect(struct omap_dss_device *dssdev, static void sdi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + enum omap_channel channel = dssdev->dispc_channel; + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -316,8 +315,7 @@ static void sdi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - if (dssdev->manager) - dss_mgr_disconnect(dssdev->manager, dssdev); + dss_mgr_disconnect(channel, dssdev); } static const struct omapdss_sdi_ops sdi_ops = { diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 08f9def76e27..08a2cc778ba9 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -443,7 +443,7 @@ static const struct venc_config *venc_timings_to_config( static int venc_power_on(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = venc.output.manager; + enum omap_channel channel = dssdev->dispc_channel; u32 l; int r; @@ -469,13 +469,13 @@ static int venc_power_on(struct omap_dss_device *dssdev) venc_write_reg(VENC_OUTPUT_CONTROL, l); - dss_mgr_set_timings(mgr, &venc.timings); + dss_mgr_set_timings(channel, &venc.timings); r = regulator_enable(venc.vdda_dac_reg); if (r) goto err1; - r = dss_mgr_enable(mgr); + r = dss_mgr_enable(channel); if (r) goto err2; @@ -494,12 +494,12 @@ err0: static void venc_power_off(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = venc.output.manager; + enum omap_channel channel = dssdev->dispc_channel; venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - dss_mgr_disable(mgr); + dss_mgr_disable(channel); regulator_disable(venc.vdda_dac_reg); @@ -515,7 +515,7 @@ static int venc_display_enable(struct omap_dss_device *dssdev) mutex_lock(&venc.venc_lock); - if (out->manager == NULL) { + if (!out->dispc_channel_connected) { DSSERR("Failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; @@ -742,18 +742,14 @@ static int venc_get_clocks(struct platform_device *pdev) static int venc_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - struct omap_overlay_manager *mgr; + enum omap_channel channel = dssdev->dispc_channel; int r; r = venc_init_regulator(); if (r) return r; - mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); - if (!mgr) - return -ENODEV; - - r = dss_mgr_connect(mgr, dssdev); + r = dss_mgr_connect(channel, dssdev); if (r) return r; @@ -761,7 +757,7 @@ static int venc_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(mgr, dssdev); + dss_mgr_disconnect(channel, dssdev); return r; } @@ -771,6 +767,8 @@ static int venc_connect(struct omap_dss_device *dssdev, static void venc_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + enum omap_channel channel = dssdev->dispc_channel; + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -778,8 +776,7 @@ static void venc_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - if (dssdev->manager) - dss_mgr_disconnect(dssdev->manager, dssdev); + dss_mgr_disconnect(channel, dssdev); } static const struct omapdss_atv_ops venc_ops = { diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 83f2a9177c14..ce2d67b6a8c7 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -63,6 +63,9 @@ void copy_timings_omap_to_drm(struct drm_display_mode *mode, if (timings->interlace) mode->flags |= DRM_MODE_FLAG_INTERLACE; + if (timings->double_pixel) + mode->flags |= DRM_MODE_FLAG_DBLCLK; + if (timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH) mode->flags |= DRM_MODE_FLAG_PHSYNC; else @@ -90,6 +93,7 @@ void copy_timings_drm_to_omap(struct omap_video_timings *timings, timings->vbp = mode->vtotal - mode->vsync_end; timings->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + timings->double_pixel = !!(mode->flags & DRM_MODE_FLAG_DBLCLK); if (mode->flags & DRM_MODE_FLAG_PHSYNC) timings->hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 2ed0754ed19e..075f2bb44867 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -34,14 +34,6 @@ struct omap_crtc { const char *name; enum omap_channel channel; - /* - * Temporary: eventually this will go away, but it is needed - * for now to keep the output's happy. (They only need - * mgr->id.) Eventually this will be replaced w/ something - * more common-panel-framework-y - */ - struct omap_overlay_manager *mgr; - struct omap_video_timings timings; struct omap_drm_irq vblank_irq; @@ -80,9 +72,13 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + /* + * Timeout is set to a "sufficiently" high value, which should cover + * a single frame refresh even on slower displays. + */ return wait_event_timeout(omap_crtc->pending_wait, !omap_crtc->pending, - msecs_to_jiffies(50)); + msecs_to_jiffies(250)); } /* ----------------------------------------------------------------------------- @@ -100,31 +96,32 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc) /* ovl-mgr-id -> crtc */ static struct omap_crtc *omap_crtcs[8]; +static struct omap_dss_device *omap_crtc_output[8]; /* we can probably ignore these until we support command-mode panels: */ -static int omap_crtc_dss_connect(struct omap_overlay_manager *mgr, +static int omap_crtc_dss_connect(enum omap_channel channel, struct omap_dss_device *dst) { - if (mgr->output) + if (omap_crtc_output[channel]) return -EINVAL; - if ((mgr->supported_outputs & dst->id) == 0) + if ((dispc_mgr_get_supported_outputs(channel) & dst->id) == 0) return -EINVAL; - dst->manager = mgr; - mgr->output = dst; + omap_crtc_output[channel] = dst; + dst->dispc_channel_connected = true; return 0; } -static void omap_crtc_dss_disconnect(struct omap_overlay_manager *mgr, +static void omap_crtc_dss_disconnect(enum omap_channel channel, struct omap_dss_device *dst) { - mgr->output->manager = NULL; - mgr->output = NULL; + omap_crtc_output[channel] = NULL; + dst->dispc_channel_connected = false; } -static void omap_crtc_dss_start_update(struct omap_overlay_manager *mgr) +static void omap_crtc_dss_start_update(enum omap_channel channel) { } @@ -138,6 +135,11 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) u32 framedone_irq, vsync_irq; int ret; + if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) { + dispc_mgr_enable(channel, enable); + return; + } + if (dispc_mgr_is_enabled(channel) == enable) return; @@ -186,9 +188,9 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) } -static int omap_crtc_dss_enable(struct omap_overlay_manager *mgr) +static int omap_crtc_dss_enable(enum omap_channel channel) { - struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; + struct omap_crtc *omap_crtc = omap_crtcs[channel]; struct omap_overlay_manager_info info; memset(&info, 0, sizeof(info)); @@ -205,38 +207,38 @@ static int omap_crtc_dss_enable(struct omap_overlay_manager *mgr) return 0; } -static void omap_crtc_dss_disable(struct omap_overlay_manager *mgr) +static void omap_crtc_dss_disable(enum omap_channel channel) { - struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; + struct omap_crtc *omap_crtc = omap_crtcs[channel]; omap_crtc_set_enabled(&omap_crtc->base, false); } -static void omap_crtc_dss_set_timings(struct omap_overlay_manager *mgr, +static void omap_crtc_dss_set_timings(enum omap_channel channel, const struct omap_video_timings *timings) { - struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; + struct omap_crtc *omap_crtc = omap_crtcs[channel]; DBG("%s", omap_crtc->name); omap_crtc->timings = *timings; } -static void omap_crtc_dss_set_lcd_config(struct omap_overlay_manager *mgr, +static void omap_crtc_dss_set_lcd_config(enum omap_channel channel, const struct dss_lcd_mgr_config *config) { - struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; + struct omap_crtc *omap_crtc = omap_crtcs[channel]; DBG("%s", omap_crtc->name); dispc_mgr_set_lcd_config(omap_crtc->channel, config); } static int omap_crtc_dss_register_framedone( - struct omap_overlay_manager *mgr, + enum omap_channel channel, void (*handler)(void *), void *data) { return 0; } static void omap_crtc_dss_unregister_framedone( - struct omap_overlay_manager *mgr, + enum omap_channel channel, void (*handler)(void *), void *data) { } @@ -269,18 +271,7 @@ static void omap_crtc_complete_page_flip(struct drm_crtc *crtc) return; spin_lock_irqsave(&dev->event_lock, flags); - - list_del(&event->base.link); - - /* - * Queue the event for delivery if it's still linked to a file - * handle, otherwise just destroy it. - */ - if (event->base.file_priv) - drm_crtc_send_vblank_event(crtc, event); - else - event->base.destroy(&event->base); - + drm_crtc_send_vblank_event(crtc, event); spin_unlock_irqrestore(&dev->event_lock, flags); } @@ -341,13 +332,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc) kfree(omap_crtc); } -static bool omap_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static void omap_crtc_enable(struct drm_crtc *crtc) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); @@ -414,24 +398,40 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, } } +static bool omap_crtc_is_plane_prop(struct drm_device *dev, + struct drm_property *property) +{ + struct omap_drm_private *priv = dev->dev_private; + + return property == priv->zorder_prop || + property == dev->mode_config.rotation_property; +} + static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) { - struct drm_plane_state *plane_state; - struct drm_plane *plane = crtc->primary; + struct drm_device *dev = crtc->dev; - /* - * Delegate property set to the primary plane. Get the plane state and - * set the property directly. - */ + if (omap_crtc_is_plane_prop(dev, property)) { + struct drm_plane_state *plane_state; + struct drm_plane *plane = crtc->primary; - plane_state = drm_atomic_get_plane_state(state->state, plane); - if (!plane_state) - return -EINVAL; + /* + * Delegate property set to the primary plane. Get the plane + * state and set the property directly. + */ + + plane_state = drm_atomic_get_plane_state(state->state, plane); + if (IS_ERR(plane_state)) + return PTR_ERR(plane_state); + + return drm_atomic_plane_set_property(plane, plane_state, + property, val); + } - return drm_atomic_plane_set_property(plane, plane_state, property, val); + return -EINVAL; } static int omap_crtc_atomic_get_property(struct drm_crtc *crtc, @@ -439,14 +439,20 @@ static int omap_crtc_atomic_get_property(struct drm_crtc *crtc, struct drm_property *property, uint64_t *val) { - /* - * Delegate property get to the primary plane. The - * drm_atomic_plane_get_property() function isn't exported, but can be - * called through drm_object_property_get_value() as that will call - * drm_atomic_get_property() for atomic drivers. - */ - return drm_object_property_get_value(&crtc->primary->base, property, - val); + struct drm_device *dev = crtc->dev; + + if (omap_crtc_is_plane_prop(dev, property)) { + /* + * Delegate property get to the primary plane. The + * drm_atomic_plane_get_property() function isn't exported, but + * can be called through drm_object_property_get_value() as that + * will call drm_atomic_get_property() for atomic drivers. + */ + return drm_object_property_get_value(&crtc->primary->base, + property, val); + } + + return -EINVAL; } static const struct drm_crtc_funcs omap_crtc_funcs = { @@ -462,7 +468,6 @@ static const struct drm_crtc_funcs omap_crtc_funcs = { }; static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { - .mode_fixup = omap_crtc_mode_fixup, .mode_set_nofb = omap_crtc_mode_set_nofb, .disable = omap_crtc_disable, .enable = omap_crtc_enable, @@ -520,9 +525,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_crtc->error_irq.irq = omap_crtc_error_irq; omap_irq_register(dev, &omap_crtc->error_irq); - /* temporary: */ - omap_crtc->mgr = omap_dss_get_overlay_manager(channel); - ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, &omap_crtc_funcs, NULL); if (ret < 0) { diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 85dfe3674b41..de275a5be1db 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -79,6 +79,16 @@ static const uint32_t reg[][4] = { DMM_PAT_DESCR__2, DMM_PAT_DESCR__3}, }; +static u32 dmm_read(struct dmm *dmm, u32 reg) +{ + return readl(dmm->base + reg); +} + +static void dmm_write(struct dmm *dmm, u32 val, u32 reg) +{ + writel(val, dmm->base + reg); +} + /* simple allocator to grab next 16 byte aligned memory from txn */ static void *alloc_dma(struct dmm_txn *txn, size_t sz, dma_addr_t *pa) { @@ -108,7 +118,7 @@ static int wait_status(struct refill_engine *engine, uint32_t wait_mask) i = DMM_FIXED_RETRY_COUNT; while (true) { - r = readl(dmm->base + reg[PAT_STATUS][engine->id]); + r = dmm_read(dmm, reg[PAT_STATUS][engine->id]); err = r & DMM_PATSTATUS_ERR; if (err) return -EFAULT; @@ -140,11 +150,11 @@ static void release_engine(struct refill_engine *engine) static irqreturn_t omap_dmm_irq_handler(int irq, void *arg) { struct dmm *dmm = arg; - uint32_t status = readl(dmm->base + DMM_PAT_IRQSTATUS); + uint32_t status = dmm_read(dmm, DMM_PAT_IRQSTATUS); int i; /* ack IRQ */ - writel(status, dmm->base + DMM_PAT_IRQSTATUS); + dmm_write(dmm, status, DMM_PAT_IRQSTATUS); for (i = 0; i < dmm->num_engines; i++) { if (status & DMM_IRQSTAT_LST) { @@ -264,7 +274,7 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait) txn->last_pat->next_pa = 0; /* write to PAT_DESCR to clear out any pending transaction */ - writel(0x0, dmm->base + reg[PAT_DESCR][engine->id]); + dmm_write(dmm, 0x0, reg[PAT_DESCR][engine->id]); /* wait for engine ready: */ ret = wait_status(engine, DMM_PATSTATUS_READY); @@ -280,8 +290,7 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait) smp_mb(); /* kick reload */ - writel(engine->refill_pa, - dmm->base + reg[PAT_DESCR][engine->id]); + dmm_write(dmm, engine->refill_pa, reg[PAT_DESCR][engine->id]); if (wait) { if (!wait_for_completion_timeout(&engine->compl, @@ -309,6 +318,21 @@ static int fill(struct tcm_area *area, struct page **pages, struct tcm_area slice, area_s; struct dmm_txn *txn; + /* + * FIXME + * + * Asynchronous fill does not work reliably, as the driver does not + * handle errors in the async code paths. The fill operation may + * silently fail, leading to leaking DMM engines, which may eventually + * lead to deadlock if we run out of DMM engines. + * + * For now, always set 'wait' so that we only use sync fills. Async + * fills should be fixed, or alternatively we could decide to only + * support sync fills and so the whole async code path could be removed. + */ + + wait = true; + txn = dmm_txn_init(omap_dmm, area->tcm); if (IS_ERR_OR_NULL(txn)) return -ENOMEM; @@ -641,7 +665,7 @@ static int omap_dmm_probe(struct platform_device *dev) omap_dmm->dev = &dev->dev; - hwinfo = readl(omap_dmm->base + DMM_PAT_HWINFO); + hwinfo = dmm_read(omap_dmm, DMM_PAT_HWINFO); omap_dmm->num_engines = (hwinfo >> 24) & 0x1F; omap_dmm->num_lut = (hwinfo >> 16) & 0x1F; omap_dmm->container_width = 256; @@ -650,7 +674,7 @@ static int omap_dmm_probe(struct platform_device *dev) atomic_set(&omap_dmm->engine_counter, omap_dmm->num_engines); /* read out actual LUT width and height */ - pat_geom = readl(omap_dmm->base + DMM_PAT_GEOMETRY); + pat_geom = dmm_read(omap_dmm, DMM_PAT_GEOMETRY); omap_dmm->lut_width = ((pat_geom >> 16) & 0xF) << 5; omap_dmm->lut_height = ((pat_geom >> 24) & 0xF) << 5; @@ -660,12 +684,12 @@ static int omap_dmm_probe(struct platform_device *dev) omap_dmm->num_lut++; /* initialize DMM registers */ - writel(0x88888888, omap_dmm->base + DMM_PAT_VIEW__0); - writel(0x88888888, omap_dmm->base + DMM_PAT_VIEW__1); - writel(0x80808080, omap_dmm->base + DMM_PAT_VIEW_MAP__0); - writel(0x80000000, omap_dmm->base + DMM_PAT_VIEW_MAP_BASE); - writel(0x88888888, omap_dmm->base + DMM_TILER_OR__0); - writel(0x88888888, omap_dmm->base + DMM_TILER_OR__1); + dmm_write(omap_dmm, 0x88888888, DMM_PAT_VIEW__0); + dmm_write(omap_dmm, 0x88888888, DMM_PAT_VIEW__1); + dmm_write(omap_dmm, 0x80808080, DMM_PAT_VIEW_MAP__0); + dmm_write(omap_dmm, 0x80000000, DMM_PAT_VIEW_MAP_BASE); + dmm_write(omap_dmm, 0x88888888, DMM_TILER_OR__0); + dmm_write(omap_dmm, 0x88888888, DMM_TILER_OR__1); ret = request_irq(omap_dmm->irq, omap_dmm_irq_handler, IRQF_SHARED, "omap_dmm_irq_handler", omap_dmm); @@ -683,7 +707,7 @@ static int omap_dmm_probe(struct platform_device *dev) * buffers for accelerated pan/scroll) and FILL_DSC<n> which * we just generally don't care about. */ - writel(0x7e7e7e7e, omap_dmm->base + DMM_PAT_IRQENABLE_SET); + dmm_write(omap_dmm, 0x7e7e7e7e, DMM_PAT_IRQENABLE_SET); omap_dmm->dummy_page = alloc_page(GFP_KERNEL | __GFP_DMA32); if (!omap_dmm->dummy_page) { diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index dfafdb602ad2..80398a684cae 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -142,7 +142,6 @@ static int omap_atomic_commit(struct drm_device *dev, { struct omap_drm_private *priv = dev->dev_private; struct omap_atomic_state_commit *commit; - unsigned long flags; unsigned int i; int ret; @@ -175,17 +174,6 @@ static int omap_atomic_commit(struct drm_device *dev, priv->commit.pending |= commit->crtcs; spin_unlock(&priv->commit.lock); - /* Keep track of all CRTC events to unlink them in preclose(). */ - spin_lock_irqsave(&dev->event_lock, flags); - for (i = 0; i < dev->mode_config.num_crtc; ++i) { - struct drm_crtc_state *cstate = state->crtc_states[i]; - - if (cstate && cstate->event) - list_add_tail(&cstate->event->base.link, - &priv->commit.events); - } - spin_unlock_irqrestore(&dev->event_lock, flags); - /* Swap the state, this is the point of no return. */ drm_atomic_helper_swap_state(dev, state); @@ -352,7 +340,7 @@ static int omap_modeset_init(struct drm_device *dev) struct drm_connector *connector; struct drm_encoder *encoder; enum omap_channel channel; - struct omap_overlay_manager *mgr; + struct omap_dss_device *out; if (!omapdss_device_is_connected(dssdev)) continue; @@ -399,8 +387,10 @@ static int omap_modeset_init(struct drm_device *dev) * not considered. */ - mgr = omapdss_find_mgr_from_display(dssdev); - channel = mgr->id; + out = omapdss_find_output_from_display(dssdev); + channel = out->dispc_channel; + omap_dss_put_device(out); + /* * if this channel hasn't already been taken by a previously * allocated crtc, we create a new crtc for it @@ -673,7 +663,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) priv->wq = alloc_ordered_workqueue("omapdrm", 0); init_waitqueue_head(&priv->commit.wait); spin_lock_init(&priv->commit.lock); - INIT_LIST_HEAD(&priv->commit.events); spin_lock_init(&priv->list_lock); INIT_LIST_HEAD(&priv->obj_list); @@ -787,33 +776,6 @@ static void dev_lastclose(struct drm_device *dev) } } -static void dev_preclose(struct drm_device *dev, struct drm_file *file) -{ - struct omap_drm_private *priv = dev->dev_private; - struct drm_pending_event *event; - unsigned long flags; - - DBG("preclose: dev=%p", dev); - - /* - * Unlink all pending CRTC events to make sure they won't be queued up - * by a pending asynchronous commit. - */ - spin_lock_irqsave(&dev->event_lock, flags); - list_for_each_entry(event, &priv->commit.events, link) { - if (event->file_priv == file) { - file->event_space += event->event->length; - event->file_priv = NULL; - } - } - spin_unlock_irqrestore(&dev->event_lock, flags); -} - -static void dev_postclose(struct drm_device *dev, struct drm_file *file) -{ - DBG("postclose: dev=%p, file=%p", dev, file); -} - static const struct vm_operations_struct omap_gem_vm_ops = { .fault = omap_gem_fault, .open = drm_gem_vm_open, @@ -838,8 +800,6 @@ static struct drm_driver omap_drm_driver = { .unload = dev_unload, .open = dev_open, .lastclose = dev_lastclose, - .preclose = dev_preclose, - .postclose = dev_postclose, .set_busid = drm_platform_set_busid, .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = omap_irq_enable_vblank, @@ -900,12 +860,52 @@ static int pdev_remove(struct platform_device *device) } #ifdef CONFIG_PM_SLEEP +static int omap_drm_suspend_all_displays(void) +{ + struct omap_dss_device *dssdev = NULL; + + for_each_dss_dev(dssdev) { + if (!dssdev->driver) + continue; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + dssdev->driver->disable(dssdev); + dssdev->activate_after_resume = true; + } else { + dssdev->activate_after_resume = false; + } + } + + return 0; +} + +static int omap_drm_resume_all_displays(void) +{ + struct omap_dss_device *dssdev = NULL; + + for_each_dss_dev(dssdev) { + if (!dssdev->driver) + continue; + + if (dssdev->activate_after_resume) { + dssdev->driver->enable(dssdev); + dssdev->activate_after_resume = false; + } + } + + return 0; +} + static int omap_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); drm_kms_helper_poll_disable(drm_dev); + drm_modeset_lock_all(drm_dev); + omap_drm_suspend_all_displays(); + drm_modeset_unlock_all(drm_dev); + return 0; } @@ -913,6 +913,10 @@ static int omap_drm_resume(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); + drm_modeset_lock_all(drm_dev); + omap_drm_resume_all_displays(); + drm_modeset_unlock_all(drm_dev); + drm_kms_helper_poll_enable(drm_dev); return omap_gem_resume(dev); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 9e0030731c37..0fbe17d0ec6f 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -31,6 +31,8 @@ #include <drm/drm_gem.h> #include <drm/omap_drm.h> +#include "dss/omapdss.h" + #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ @@ -106,7 +108,6 @@ struct omap_drm_private { /* atomic commit */ struct { - struct list_head events; wait_queue_head_t wait; u32 pending; spinlock_t lock; /* Protects commit.pending */ @@ -189,12 +190,15 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, struct omap_drm_window *win, struct omap_overlay_info *info); struct drm_connector *omap_framebuffer_get_next_connector( struct drm_framebuffer *fb, struct drm_connector *from); +bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb); void omap_gem_init(struct drm_device *dev); void omap_gem_deinit(struct drm_device *dev); struct drm_gem_object *omap_gem_new(struct drm_device *dev, union omap_gem_size gsize, uint32_t flags); +struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, + struct sg_table *sgt); int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file, union omap_gem_size gsize, uint32_t flags, uint32_t *handle); void omap_gem_free_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 61714e9670ae..0bbb9c59622e 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -139,11 +139,16 @@ static void omap_encoder_enable(struct drm_encoder *encoder) struct omap_encoder *omap_encoder = to_omap_encoder(encoder); struct omap_dss_device *dssdev = omap_encoder->dssdev; struct omap_dss_driver *dssdrv = dssdev->driver; + int r; omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc), omap_crtc_timings(encoder->crtc)); - dssdrv->enable(dssdev); + r = dssdrv->enable(dssdev); + if (r) + dev_err(encoder->dev->dev, + "Failed to enable display '%s': %d\n", + dssdev->name, r); } static int omap_encoder_atomic_check(struct drm_encoder *encoder, diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index ad202dfc1a49..610962396eb0 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -145,6 +145,14 @@ static uint32_t get_linear_addr(struct plane *plane, return plane->paddr + offset; } +bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb) +{ + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + struct plane *plane = &omap_fb->planes[0]; + + return omap_gem_flags(plane->bo) & OMAP_BO_TILED; +} + /* update ovl info for scanout, handles cases of multi-planar fb's, etc. */ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, @@ -449,6 +457,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, goto fail; } + if (i > 0 && pitch != mode_cmd->pitches[i - 1]) { + dev_err(dev->dev, + "pitches are not the same between framebuffer planes %d != %d\n", + pitch, mode_cmd->pitches[i - 1]); + ret = -EINVAL; + goto fail; + } + plane->bo = bos[i]; plane->offset = mode_cmd->offsets[i]; plane->pitch = pitch; diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 359b0d7e8ef7..907154f5b67c 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -31,9 +31,9 @@ */ /* note: we use upper 8 bits of flags for driver-internal flags: */ -#define OMAP_BO_DMA 0x01000000 /* actually is physically contiguous */ -#define OMAP_BO_EXT_SYNC 0x02000000 /* externally allocated sync object */ -#define OMAP_BO_EXT_MEM 0x04000000 /* externally allocated memory */ +#define OMAP_BO_MEM_DMA_API 0x01000000 /* memory allocated with the dma_alloc_* API */ +#define OMAP_BO_MEM_SHMEM 0x02000000 /* memory allocated through shmem backing */ +#define OMAP_BO_MEM_DMABUF 0x08000000 /* memory imported from a dmabuf */ struct omap_gem_object { struct drm_gem_object base; @@ -49,17 +49,25 @@ struct omap_gem_object { uint32_t roll; /** - * If buffer is allocated physically contiguous, the OMAP_BO_DMA flag - * is set and the paddr is valid. Also if the buffer is remapped in - * TILER and paddr_cnt > 0, then paddr is valid. But if you are using - * the physical address and OMAP_BO_DMA is not set, then you should - * be going thru omap_gem_{get,put}_paddr() to ensure the mapping is - * not removed from under your feet. + * paddr contains the buffer DMA address. It is valid for * - * Note that OMAP_BO_SCANOUT is a hint from userspace that DMA capable - * buffer is requested, but doesn't mean that it is. Use the - * OMAP_BO_DMA flag to determine if the buffer has a DMA capable - * physical address. + * - buffers allocated through the DMA mapping API (with the + * OMAP_BO_MEM_DMA_API flag set) + * + * - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set) + * if they are physically contiguous (when sgt->orig_nents == 1) + * + * - buffers mapped through the TILER when paddr_cnt is not zero, in + * which case the DMA address points to the TILER aperture + * + * Physically contiguous buffers have their DMA address equal to the + * physical address as we don't remap those buffers through the TILER. + * + * Buffers mapped to the TILER have their DMA address pointing to the + * TILER aperture. As TILER mappings are refcounted (through paddr_cnt) + * the DMA address must be accessed through omap_get_get_paddr() to + * ensure that the mapping won't disappear unexpectedly. References must + * be released with omap_gem_put_paddr(). */ dma_addr_t paddr; @@ -69,6 +77,12 @@ struct omap_gem_object { uint32_t paddr_cnt; /** + * If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag + * is set and the sgt field is valid. + */ + struct sg_table *sgt; + + /** * tiler block used when buffer is remapped in DMM/TILER. */ struct tiler_block *block; @@ -91,17 +105,7 @@ struct omap_gem_object { * sync-object allocated on demand (if needed) * * Per-buffer sync-object for tracking pending and completed hw/dma - * read and write operations. The layout in memory is dictated by - * the SGX firmware, which uses this information to stall the command - * stream if a surface is not ready yet. - * - * Note that when buffer is used by SGX, the sync-object needs to be - * allocated from a special heap of sync-objects. This way many sync - * objects can be packed in a page, and not waste GPU virtual address - * space. Because of this we have to have a omap_gem_set_sync_object() - * API to allow replacement of the syncobj after it has (potentially) - * already been allocated. A bit ugly but I haven't thought of a - * better alternative. + * read and write operations. */ struct { uint32_t write_pending; @@ -166,16 +170,15 @@ static uint64_t mmap_offset(struct drm_gem_object *obj) return drm_vma_node_offset_addr(&obj->vma_node); } -/* GEM objects can either be allocated from contiguous memory (in which - * case obj->filp==NULL), or w/ shmem backing (obj->filp!=NULL). But non - * contiguous buffers can be remapped in TILER/DMM if they need to be - * contiguous... but we don't do this all the time to reduce pressure - * on TILER/DMM space when we know at allocation time that the buffer - * will need to be scanned out. - */ -static inline bool is_shmem(struct drm_gem_object *obj) +static bool is_contiguous(struct omap_gem_object *omap_obj) { - return obj->filp != NULL; + if (omap_obj->flags & OMAP_BO_MEM_DMA_API) + return true; + + if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && omap_obj->sgt->nents == 1) + return true; + + return false; } /* ----------------------------------------------------------------------------- @@ -264,6 +267,19 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) for (i = 0; i < npages; i++) { addrs[i] = dma_map_page(dev->dev, pages[i], 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + + if (dma_mapping_error(dev->dev, addrs[i])) { + dev_warn(dev->dev, + "%s: failed to map page\n", __func__); + + for (i = i - 1; i >= 0; --i) { + dma_unmap_page(dev->dev, addrs[i], + PAGE_SIZE, DMA_BIDIRECTIONAL); + } + + ret = -ENOMEM; + goto free_addrs; + } } } else { addrs = kzalloc(npages * sizeof(*addrs), GFP_KERNEL); @@ -278,6 +294,8 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) return 0; +free_addrs: + kfree(addrs); free_pages: drm_gem_put_pages(obj, pages, true, false); @@ -292,7 +310,7 @@ static int get_pages(struct drm_gem_object *obj, struct page ***pages) struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = 0; - if (is_shmem(obj) && !omap_obj->pages) { + if ((omap_obj->flags & OMAP_BO_MEM_SHMEM) && !omap_obj->pages) { ret = omap_gem_attach_pages(obj); if (ret) { dev_err(obj->dev->dev, "could not attach pages\n"); @@ -396,7 +414,7 @@ static int fault_1d(struct drm_gem_object *obj, omap_gem_cpu_sync(obj, pgoff); pfn = page_to_pfn(omap_obj->pages[pgoff]); } else { - BUG_ON(!(omap_obj->flags & OMAP_BO_DMA)); + BUG_ON(!is_contiguous(omap_obj)); pfn = (omap_obj->paddr >> PAGE_SHIFT) + pgoff; } @@ -560,6 +578,11 @@ fail: case 0: case -ERESTARTSYS: case -EINTR: + case -EBUSY: + /* + * EBUSY is ok: this just means that another thread + * already did the job. + */ return VM_FAULT_NOPAGE; case -ENOMEM: return VM_FAULT_OOM; @@ -728,7 +751,8 @@ fail: static inline bool is_cached_coherent(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - return is_shmem(obj) && + + return (omap_obj->flags & OMAP_BO_MEM_SHMEM) && ((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED); } @@ -761,9 +785,20 @@ void omap_gem_dma_sync(struct drm_gem_object *obj, for (i = 0; i < npages; i++) { if (!omap_obj->addrs[i]) { - omap_obj->addrs[i] = dma_map_page(dev->dev, pages[i], 0, + dma_addr_t addr; + + addr = dma_map_page(dev->dev, pages[i], 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + + if (dma_mapping_error(dev->dev, addr)) { + dev_warn(dev->dev, + "%s: failed to map page\n", + __func__); + break; + } + dirty = true; + omap_obj->addrs[i] = addr; } } @@ -787,7 +822,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj, mutex_lock(&obj->dev->struct_mutex); - if (remap && is_shmem(obj) && priv->has_dmm) { + if (!is_contiguous(omap_obj) && remap && priv->has_dmm) { if (omap_obj->paddr_cnt == 0) { struct page **pages; uint32_t npages = obj->size >> PAGE_SHIFT; @@ -834,7 +869,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj, omap_obj->paddr_cnt++; *paddr = omap_obj->paddr; - } else if (omap_obj->flags & OMAP_BO_DMA) { + } else if (is_contiguous(omap_obj)) { *paddr = omap_obj->paddr; } else { ret = -EINVAL; @@ -1138,20 +1173,6 @@ unlock: return ret; } -/* it is a bit lame to handle updates in this sort of polling way, but - * in case of PVR, the GPU can directly update read/write complete - * values, and not really tell us which ones it updated.. this also - * means that sync_lock is not quite sufficient. So we'll need to - * do something a bit better when it comes time to add support for - * separate 2d hw.. - */ -void omap_gem_op_update(void) -{ - spin_lock(&sync_lock); - sync_op_update(); - spin_unlock(&sync_lock); -} - /* mark the start of read and/or write operation */ int omap_gem_op_start(struct drm_gem_object *obj, enum omap_gem_op op) { @@ -1219,7 +1240,7 @@ int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op) * is currently blocked.. fxn() can be called from any context * * (TODO for now fxn is called back from whichever context calls - * omap_gem_op_update().. but this could be better defined later + * omap_gem_op_finish().. but this could be better defined later * if needed) * * TODO more code in common w/ _sync().. @@ -1261,50 +1282,10 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op, return 0; } -/* special API so PVR can update the buffer to use a sync-object allocated - * from it's sync-obj heap. Only used for a newly allocated (from PVR's - * perspective) sync-object, so we overwrite the new syncobj w/ values - * from the already allocated syncobj (if there is one) - */ -int omap_gem_set_sync_object(struct drm_gem_object *obj, void *syncobj) -{ - struct omap_gem_object *omap_obj = to_omap_bo(obj); - int ret = 0; - - spin_lock(&sync_lock); - - if ((omap_obj->flags & OMAP_BO_EXT_SYNC) && !syncobj) { - /* clearing a previously set syncobj */ - syncobj = kmemdup(omap_obj->sync, sizeof(*omap_obj->sync), - GFP_ATOMIC); - if (!syncobj) { - ret = -ENOMEM; - goto unlock; - } - omap_obj->flags &= ~OMAP_BO_EXT_SYNC; - omap_obj->sync = syncobj; - } else if (syncobj && !(omap_obj->flags & OMAP_BO_EXT_SYNC)) { - /* replacing an existing syncobj */ - if (omap_obj->sync) { - memcpy(syncobj, omap_obj->sync, sizeof(*omap_obj->sync)); - kfree(omap_obj->sync); - } - omap_obj->flags |= OMAP_BO_EXT_SYNC; - omap_obj->sync = syncobj; - } - -unlock: - spin_unlock(&sync_lock); - return ret; -} - /* ----------------------------------------------------------------------------- * Constructor & Destructor */ -/* don't call directly.. called from GEM core when it is time to actually - * free the object.. - */ void omap_gem_free_object(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; @@ -1324,22 +1305,23 @@ void omap_gem_free_object(struct drm_gem_object *obj) */ WARN_ON(omap_obj->paddr_cnt > 0); - /* don't free externally allocated backing memory */ - if (!(omap_obj->flags & OMAP_BO_EXT_MEM)) { - if (omap_obj->pages) + if (omap_obj->pages) { + if (omap_obj->flags & OMAP_BO_MEM_DMABUF) + kfree(omap_obj->pages); + else omap_gem_detach_pages(obj); + } - if (!is_shmem(obj)) { - dma_free_wc(dev->dev, obj->size, omap_obj->vaddr, - omap_obj->paddr); - } else if (omap_obj->vaddr) { - vunmap(omap_obj->vaddr); - } + if (omap_obj->flags & OMAP_BO_MEM_DMA_API) { + dma_free_wc(dev->dev, obj->size, omap_obj->vaddr, + omap_obj->paddr); + } else if (omap_obj->vaddr) { + vunmap(omap_obj->vaddr); + } else if (obj->import_attach) { + drm_prime_gem_destroy(obj, omap_obj->sgt); } - /* don't free externally allocated syncobj */ - if (!(omap_obj->flags & OMAP_BO_EXT_SYNC)) - kfree(omap_obj->sync); + kfree(omap_obj->sync); drm_gem_object_release(obj); @@ -1357,84 +1339,160 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, size_t size; int ret; + /* Validate the flags and compute the memory and cache flags. */ if (flags & OMAP_BO_TILED) { if (!priv->usergart) { dev_err(dev->dev, "Tiled buffers require DMM\n"); return NULL; } - /* tiled buffers are always shmem paged backed.. when they are - * scanned out, they are remapped into DMM/TILER + /* + * Tiled buffers are always shmem paged backed. When they are + * scanned out, they are remapped into DMM/TILER. */ flags &= ~OMAP_BO_SCANOUT; + flags |= OMAP_BO_MEM_SHMEM; - /* currently don't allow cached buffers.. there is some caching - * stuff that needs to be handled better + /* + * Currently don't allow cached buffers. There is some caching + * stuff that needs to be handled better. */ flags &= ~(OMAP_BO_CACHED|OMAP_BO_WC|OMAP_BO_UNCACHED); flags |= tiler_get_cpu_cache_flags(); - - /* align dimensions to slot boundaries... */ - tiler_align(gem2fmt(flags), - &gsize.tiled.width, &gsize.tiled.height); - - /* ...and calculate size based on aligned dimensions */ - size = tiler_size(gem2fmt(flags), - gsize.tiled.width, gsize.tiled.height); - } else { - size = PAGE_ALIGN(gsize.bytes); + } else if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) { + /* + * OMAP_BO_SCANOUT hints that the buffer doesn't need to be + * tiled. However, to lower the pressure on memory allocation, + * use contiguous memory only if no TILER is available. + */ + flags |= OMAP_BO_MEM_DMA_API; + } else if (!(flags & OMAP_BO_MEM_DMABUF)) { + /* + * All other buffers not backed by dma_buf are shmem-backed. + */ + flags |= OMAP_BO_MEM_SHMEM; } + /* Allocate the initialize the OMAP GEM object. */ omap_obj = kzalloc(sizeof(*omap_obj), GFP_KERNEL); if (!omap_obj) return NULL; obj = &omap_obj->base; + omap_obj->flags = flags; - if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) { - /* attempt to allocate contiguous memory if we don't - * have DMM for remappign discontiguous buffers + if (flags & OMAP_BO_TILED) { + /* + * For tiled buffers align dimensions to slot boundaries and + * calculate size based on aligned dimensions. */ - omap_obj->vaddr = dma_alloc_wc(dev->dev, size, - &omap_obj->paddr, GFP_KERNEL); - if (!omap_obj->vaddr) { - kfree(omap_obj); + tiler_align(gem2fmt(flags), &gsize.tiled.width, + &gsize.tiled.height); - return NULL; - } - - flags |= OMAP_BO_DMA; - } + size = tiler_size(gem2fmt(flags), gsize.tiled.width, + gsize.tiled.height); - spin_lock(&priv->list_lock); - list_add(&omap_obj->mm_list, &priv->obj_list); - spin_unlock(&priv->list_lock); - - omap_obj->flags = flags; - - if (flags & OMAP_BO_TILED) { omap_obj->width = gsize.tiled.width; omap_obj->height = gsize.tiled.height; + } else { + size = PAGE_ALIGN(gsize.bytes); } - if (flags & (OMAP_BO_DMA|OMAP_BO_EXT_MEM)) { + /* Initialize the GEM object. */ + if (!(flags & OMAP_BO_MEM_SHMEM)) { drm_gem_private_object_init(dev, obj, size); } else { ret = drm_gem_object_init(dev, obj, size); if (ret) - goto fail; + goto err_free; mapping = file_inode(obj->filp)->i_mapping; mapping_set_gfp_mask(mapping, GFP_USER | __GFP_DMA32); } + /* Allocate memory if needed. */ + if (flags & OMAP_BO_MEM_DMA_API) { + omap_obj->vaddr = dma_alloc_wc(dev->dev, size, + &omap_obj->paddr, + GFP_KERNEL); + if (!omap_obj->vaddr) + goto err_release; + } + + spin_lock(&priv->list_lock); + list_add(&omap_obj->mm_list, &priv->obj_list); + spin_unlock(&priv->list_lock); + return obj; -fail: - omap_gem_free_object(obj); +err_release: + drm_gem_object_release(obj); +err_free: + kfree(omap_obj); return NULL; } +struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, + struct sg_table *sgt) +{ + struct omap_drm_private *priv = dev->dev_private; + struct omap_gem_object *omap_obj; + struct drm_gem_object *obj; + union omap_gem_size gsize; + + /* Without a DMM only physically contiguous buffers can be supported. */ + if (sgt->orig_nents != 1 && !priv->has_dmm) + return ERR_PTR(-EINVAL); + + mutex_lock(&dev->struct_mutex); + + gsize.bytes = PAGE_ALIGN(size); + obj = omap_gem_new(dev, gsize, OMAP_BO_MEM_DMABUF | OMAP_BO_WC); + if (!obj) { + obj = ERR_PTR(-ENOMEM); + goto done; + } + + omap_obj = to_omap_bo(obj); + omap_obj->sgt = sgt; + + if (sgt->orig_nents == 1) { + omap_obj->paddr = sg_dma_address(sgt->sgl); + } else { + /* Create pages list from sgt */ + struct sg_page_iter iter; + struct page **pages; + unsigned int npages; + unsigned int i = 0; + + npages = DIV_ROUND_UP(size, PAGE_SIZE); + pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL); + if (!pages) { + omap_gem_free_object(obj); + obj = ERR_PTR(-ENOMEM); + goto done; + } + + omap_obj->pages = pages; + + for_each_sg_page(sgt->sgl, &iter, sgt->orig_nents, 0) { + pages[i++] = sg_page_iter_page(&iter); + if (i > npages) + break; + } + + if (WARN_ON(i != npages)) { + omap_gem_free_object(obj); + obj = ERR_PTR(-ENOMEM); + goto done; + } + } + +done: + mutex_unlock(&dev->struct_mutex); + return obj; +} + /* convenience method to construct a GEM buffer object, and userspace handle */ int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file, union omap_gem_size gsize, uint32_t flags, uint32_t *handle) diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 27c297672076..3cf8aab23a39 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -21,6 +21,10 @@ #include "omap_drv.h" +/* ----------------------------------------------------------------------------- + * DMABUF Export + */ + static struct sg_table *omap_gem_map_dma_buf( struct dma_buf_attachment *attachment, enum dma_data_direction dir) @@ -79,7 +83,7 @@ static void omap_gem_dmabuf_release(struct dma_buf *buffer) static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, - size_t start, size_t len, enum dma_data_direction dir) + enum dma_data_direction dir) { struct drm_gem_object *obj = buffer->priv; struct page **pages; @@ -94,7 +98,7 @@ static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, } static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, - size_t start, size_t len, enum dma_data_direction dir) + enum dma_data_direction dir) { struct drm_gem_object *obj = buffer->priv; omap_gem_put_pages(obj); @@ -178,15 +182,20 @@ struct dma_buf *omap_gem_prime_export(struct drm_device *dev, return dma_buf_export(&exp_info); } +/* ----------------------------------------------------------------------------- + * DMABUF Import + */ + struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, - struct dma_buf *buffer) + struct dma_buf *dma_buf) { + struct dma_buf_attachment *attach; struct drm_gem_object *obj; + struct sg_table *sgt; + int ret; - /* is this one of own objects? */ - if (buffer->ops == &omap_dmabuf_ops) { - obj = buffer->priv; - /* is it from our device? */ + if (dma_buf->ops == &omap_dmabuf_ops) { + obj = dma_buf->priv; if (obj->dev == dev) { /* * Importing dmabuf exported from out own gem increases @@ -197,9 +206,33 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, } } - /* - * TODO add support for importing buffers from other devices.. - * for now we don't need this but would be nice to add eventually - */ - return ERR_PTR(-EINVAL); + attach = dma_buf_attach(dma_buf, dev->dev); + if (IS_ERR(attach)) + return ERR_CAST(attach); + + get_dma_buf(dma_buf); + + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto fail_detach; + } + + obj = omap_gem_new_dmabuf(dev, dma_buf->size, sgt); + if (IS_ERR(obj)) { + ret = PTR_ERR(obj); + goto fail_unmap; + } + + obj->import_attach = attach; + + return obj; + +fail_unmap: + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); +fail_detach: + dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + + return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index d75b197eff46..93ee538a99f5 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -177,6 +177,12 @@ static int omap_plane_atomic_check(struct drm_plane *plane, if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay) return -EINVAL; + if (state->fb) { + if (state->rotation != BIT(DRM_ROTATE_0) && + !omap_framebuffer_supports_rotation(state->fb)) + return -EINVAL; + } + return 0; } |