summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_crtc.c')
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c72
1 files changed, 43 insertions, 29 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index f80bf9385e41..d524ed0d5146 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -23,6 +23,7 @@
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/dma-mapping.h>
+#include <linux/of_graph.h>
#include "tilcdc_drv.h"
#include "tilcdc_regs.h"
@@ -464,6 +465,7 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
+ unsigned long flags;
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
mutex_lock(&tilcdc_crtc->enable_lock);
@@ -484,7 +486,17 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc)
tilcdc_write_mask(dev, LCDC_RASTER_CTRL_REG,
LCDC_PALETTE_LOAD_MODE(DATA_ONLY),
LCDC_PALETTE_LOAD_MODE_MASK);
+
+ /* There is no real chance for a race here as the time stamp
+ * is taken before the raster DMA is started. The spin-lock is
+ * taken to have a memory barrier after taking the time-stamp
+ * and to avoid a context switch between taking the stamp and
+ * enabling the raster.
+ */
+ spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
+ tilcdc_crtc->last_vblank = ktime_get();
tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
+ spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags);
drm_crtc_vblank_on(crtc);
@@ -539,7 +551,6 @@ static void tilcdc_crtc_off(struct drm_crtc *crtc, bool shutdown)
}
drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
- tilcdc_crtc->last_vblank = 0;
tilcdc_crtc->enabled = false;
mutex_unlock(&tilcdc_crtc->enable_lock);
@@ -569,7 +580,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work)
dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__);
- drm_modeset_lock_crtc(crtc, NULL);
+ drm_modeset_lock(&crtc->mutex, NULL);
if (!tilcdc_crtc_is_on(crtc))
goto out;
@@ -577,7 +588,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work)
tilcdc_crtc_disable(crtc);
tilcdc_crtc_enable(crtc);
out:
- drm_modeset_unlock_crtc(crtc);
+ drm_modeset_unlock(&crtc->mutex);
}
static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
@@ -585,9 +596,9 @@ static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
struct tilcdc_drm_private *priv = crtc->dev->dev_private;
- drm_modeset_lock_crtc(crtc, NULL);
+ drm_modeset_lock(&crtc->mutex, NULL);
tilcdc_crtc_disable(crtc);
- drm_modeset_unlock_crtc(crtc);
+ drm_modeset_unlock(&crtc->mutex);
flush_workqueue(priv->wq);
@@ -602,7 +613,6 @@ int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
{
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
struct drm_device *dev = crtc->dev;
- unsigned long flags;
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
@@ -614,28 +624,30 @@ int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
drm_framebuffer_reference(fb);
crtc->primary->fb = fb;
+ tilcdc_crtc->event = event;
- spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
+ mutex_lock(&tilcdc_crtc->enable_lock);
- if (crtc->hwmode.vrefresh && ktime_to_ns(tilcdc_crtc->last_vblank)) {
+ if (tilcdc_crtc->enabled) {
+ unsigned long flags;
ktime_t next_vblank;
s64 tdiff;
- next_vblank = ktime_add_us(tilcdc_crtc->last_vblank,
- 1000000 / crtc->hwmode.vrefresh);
+ spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
+ next_vblank = ktime_add_us(tilcdc_crtc->last_vblank,
+ 1000000 / crtc->hwmode.vrefresh);
tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get()));
if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US)
tilcdc_crtc->next_fb = fb;
- }
-
- if (tilcdc_crtc->next_fb != fb)
- set_scanout(crtc, fb);
+ else
+ set_scanout(crtc, fb);
- tilcdc_crtc->event = event;
+ spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags);
+ }
- spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags);
+ mutex_unlock(&tilcdc_crtc->enable_lock);
return 0;
}
@@ -695,6 +707,15 @@ static int tilcdc_crtc_atomic_check(struct drm_crtc *crtc,
return 0;
}
+static int tilcdc_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+ return 0;
+}
+
+static void tilcdc_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+}
+
static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
.destroy = tilcdc_crtc_destroy,
.set_config = drm_atomic_helper_set_config,
@@ -702,6 +723,8 @@ static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = tilcdc_crtc_enable_vblank,
+ .disable_vblank = tilcdc_crtc_disable_vblank,
};
static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = {
@@ -834,7 +857,7 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc)
struct tilcdc_drm_private *priv = dev->dev_private;
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
- drm_modeset_lock_crtc(crtc, NULL);
+ drm_modeset_lock(&crtc->mutex, NULL);
if (tilcdc_crtc->lcd_fck_rate != clk_get_rate(priv->clk)) {
if (tilcdc_crtc_is_on(crtc)) {
pm_runtime_get_sync(dev->dev);
@@ -846,7 +869,7 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc)
pm_runtime_put_sync(dev->dev);
}
}
- drm_modeset_unlock_crtc(crtc);
+ drm_modeset_unlock(&crtc->mutex);
}
#define SYNC_LOST_COUNT_LIMIT 50
@@ -1013,16 +1036,7 @@ int tilcdc_crtc_create(struct drm_device *dev)
drm_crtc_helper_add(crtc, &tilcdc_crtc_helper_funcs);
if (priv->is_componentized) {
- struct device_node *ports =
- of_get_child_by_name(dev->dev->of_node, "ports");
-
- if (ports) {
- crtc->port = of_get_child_by_name(ports, "port");
- of_node_put(ports);
- } else {
- crtc->port =
- of_get_child_by_name(dev->dev->of_node, "port");
- }
+ crtc->port = of_graph_get_port_by_id(dev->dev->of_node, 0);
if (!crtc->port) { /* This should never happen */
dev_err(dev->dev, "Port node not found in %s\n",
dev->dev->of_node->full_name);
@@ -1036,5 +1050,5 @@ int tilcdc_crtc_create(struct drm_device *dev)
fail:
tilcdc_crtc_destroy(crtc);
- return -ENOMEM;
+ return ret;
}
OpenPOWER on IntegriCloud