From 4e4b53ceb59301b2a1dbf3a9f74ce5e17f64287d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 24 Mar 2015 15:46:35 +0200 Subject: [PATCH 01/76] drm/omap: HDMI: change enable/disable to avoid sync-losts We occasionally see DISPC sync-lost errors when enabling and disabling HDMI. Sometimes we get only a few, which get handled (ignored) by the driver, but sometimes there's a flood of the errors which doesn't seem to stop. The HW team has root caused this to the order in which HDMI and DISPC are enabled/disabled. Currently we enable HDMI first, and then DISPC, and vice versa when disabling. HW team's suggestion is to do it the other way around. This patch changes the order, but this has two side effects as the pixel clock is produced by HDMI, and the clock is not running when we enable/disable DISPC: * When enabling DISPC first, we don't get vertical sync events * When disabling DISPC last, we don't get FRAMEDONE event At the moment we use both of those to verify that DISPC has been enabled/disabled properly. Thus this patch also needs to change the omapdrm and omapdss which handle the DISPC side. Signed-off-by: Tomi Valkeinen Acked-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 16 ++++++++-------- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 16 ++++++++-------- drivers/gpu/drm/omapdrm/omap_crtc.c | 5 +++++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 7103c659a534..b09ce9ee82fa 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -214,22 +214,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) /* tv size */ dss_mgr_set_timings(mgr, p); - r = hdmi_wp_video_start(&hdmi.wp); - if (r) - goto err_vid_enable; - r = dss_mgr_enable(mgr); if (r) goto err_mgr_enable; + r = hdmi_wp_video_start(&hdmi.wp); + if (r) + 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(mgr); +err_mgr_enable: hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: err_phy_cfg: @@ -246,10 +246,10 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); - dss_mgr_disable(mgr); - hdmi_wp_video_stop(&hdmi.wp); + dss_mgr_disable(mgr); + hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); dss_pll_disable(&hdmi.pll.pll); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index a955a2c4c061..4485a1c37bd8 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -231,22 +231,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) /* tv size */ dss_mgr_set_timings(mgr, p); - r = hdmi_wp_video_start(&hdmi.wp); - if (r) - goto err_vid_enable; - r = dss_mgr_enable(mgr); if (r) goto err_mgr_enable; + r = hdmi_wp_video_start(&hdmi.wp); + if (r) + 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(mgr); +err_mgr_enable: hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: err_phy_cfg: @@ -263,10 +263,10 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); - dss_mgr_disable(mgr); - hdmi_wp_video_stop(&hdmi.wp); + dss_mgr_disable(mgr); + hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); dss_pll_disable(&hdmi.pll.pll); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 2ed0754ed19e..7dd3d44a93e5 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -138,6 +138,11 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) u32 framedone_irq, vsync_irq; int ret; + if (omap_crtc->mgr->output->output_type == OMAP_DISPLAY_TYPE_HDMI) { + dispc_mgr_enable(channel, enable); + return; + } + if (dispc_mgr_is_enabled(channel) == enable) return; From 2bb2daf3fa8a97e09d3006be003343ae717b3213 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 28 Apr 2015 14:01:34 +0300 Subject: [PATCH 02/76] HACK: drm/omap: always use blocking DMM fill The current driver uses non-blocking DMM fill when releasing memory. This gives us a small performance increase as we don't have to wait for the fill operation to finish. However, the driver does not have any error handling for non-blocking fill. In case of an error, the fill operation may silently fail, leading to leaking DMM engines, which may eventually lead to deadlock if we run out of DMM engines. This patch makes the DMM driver always use blocking fills, so that we can catch the errors. A more complex option would be to allow non-blocking fills, and implement proper error handling, but that is left for the future. This patch is a HACK, as the proper fix is to either decide to always use sync fills and remove all the async related code, or fix the async code. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_dmm_tiler.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index dfebdc4aa0f2..67edf839dce3 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -309,6 +309,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; From 8e54adfd9ccda87bb3d1c7e164029c8ebfa2c255 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 7 Aug 2015 14:31:28 +0300 Subject: [PATCH 03/76] drm/omap: add dmm_read() and dmm_write() wrappers This patch adds wrapper functions for readl() and writel(), dmm_read() and dmm_write(), so that we can implement workaround for DRA7 errata i878. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_dmm_tiler.c | 39 +++++++++++++++--------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 67edf839dce3..9f94576c435d 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, @@ -657,7 +666,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; @@ -666,7 +675,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; @@ -676,12 +685,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); @@ -699,7 +708,7 @@ static int omap_dmm_probe(struct platform_device *dev) * buffers for accelerated pan/scroll) and FILL_DSC 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) { From a7696ea7402fc8140f2023821e60adcf406679fe Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 28 Oct 2015 14:00:42 +0200 Subject: [PATCH 04/76] drm/omap: drm_atomic_get_plane_state() may return ERR_PTR drm_atomic_get_plane_state() may return ERR_PTR. Handle drm_atomic_get_plane_state() return values right in omap_crtc_atomic_set_property(). Signed-off-by: Jyri Sarha Acked-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 7dd3d44a93e5..f5b19d18fa8b 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -433,8 +433,8 @@ static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, */ plane_state = drm_atomic_get_plane_state(state->state, plane); - if (!plane_state) - return -EINVAL; + if (IS_ERR(plane_state)) + return PTR_ERR(plane_state); return drm_atomic_plane_set_property(plane, plane_state, property, val); } From 45dd63c4798b734bea4e38fb4e5ad06e4b33167e Mon Sep 17 00:00:00 2001 From: Manisha Agrawal Date: Tue, 3 Nov 2015 15:22:48 -0600 Subject: [PATCH 05/76] drm/omap: tpd12s015: remove platform data support All devices using tpd12s015 driver are doing DT boot. No need of further supporting the platform data. This patch removes support for platform data. Signed-off-by: Manisha Agrawal [tomi.valkeinen@ti.com: minor adjustments] Acked-by: Tomi Valkeinen Acked-by: Laurent Pinchart --- .../drm/omapdrm/displays/encoder-tpd12s015.c | 41 +++---------------- include/video/omap-panel-data.h | 15 ------- 2 files changed, 5 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index 990af6baeb0f..49fbad03a814 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -201,32 +201,6 @@ 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); @@ -282,17 +256,12 @@ 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 = tpd_probe_of(pdev); + if (r) + return r; r = devm_gpio_request_one(&pdev->dev, ddata->ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd"); diff --git a/include/video/omap-panel-data.h b/include/video/omap-panel-data.h index 69279c013ac4..56830d1dc762 100644 --- a/include/video/omap-panel-data.h +++ b/include/video/omap-panel-data.h @@ -45,21 +45,6 @@ struct encoder_tfp410_platform_data { int data_lines; }; -/** - * encoder_tpd12s015 platform data - * @name: name for this display entity - * @ct_cp_hpd_gpio: CT_CP_HPD gpio number - * @ls_oe_gpio: LS_OE gpio number - * @hpd_gpio: HPD gpio number - */ -struct encoder_tpd12s015_platform_data { - const char *name; - const char *source; - - int ct_cp_hpd_gpio; - int ls_oe_gpio; - int hpd_gpio; -}; /** * connector_dvi platform data From 460543ba2937283ca810f2f544e1bb5b5da3cd9d Mon Sep 17 00:00:00 2001 From: Manisha Agrawal Date: Tue, 3 Nov 2015 15:22:49 -0600 Subject: [PATCH 06/76] drm/omap: tpd12s015: gpio descriptor API Migrated the gpio APIs to descriptor-interface based. Signed-off-by: Manisha Agrawal Acked-by: Tomi Valkeinen Acked-by: Laurent Pinchart --- .../drm/omapdrm/displays/encoder-tpd12s015.c | 79 +++++++------------ 1 file changed, 28 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index 49fbad03a814..7fa80f5b4c6b 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -13,9 +13,8 @@ #include #include #include -#include #include -#include +#include #include