summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c120
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c52
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h3
4 files changed, 103 insertions, 74 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 24183fb..aefc8a0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -69,6 +69,30 @@ static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg,
rcar_du_write(rcdu, rcrtc->mmio_offset + reg, (value & ~clr) | set);
}
+static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+ int ret;
+
+ ret = clk_prepare_enable(rcrtc->clock);
+ if (ret < 0)
+ return ret;
+
+ ret = rcar_du_get(rcdu);
+ if (ret < 0)
+ clk_disable_unprepare(rcrtc->clock);
+
+ return ret;
+}
+
+static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+
+ rcar_du_put(rcdu);
+ clk_disable_unprepare(rcrtc->clock);
+}
+
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
{
struct drm_crtc *crtc = &rcrtc->crtc;
@@ -79,7 +103,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
u32 div;
/* Dot clock */
- clk = clk_get_rate(rcdu->clock);
+ clk = clk_get_rate(rcrtc->clock);
div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000);
div = clamp(div, 1U, 64U) - 1;
@@ -313,20 +337,16 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
{
- struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
-
rcar_du_crtc_stop(rcrtc);
- rcar_du_put(rcdu);
+ rcar_du_crtc_put(rcrtc);
}
void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
{
- struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
-
if (rcrtc->dpms != DRM_MODE_DPMS_ON)
return;
- rcar_du_get(rcdu);
+ rcar_du_crtc_get(rcrtc);
rcar_du_crtc_start(rcrtc);
}
@@ -340,18 +360,17 @@ static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc)
static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode)
{
- struct rcar_du_device *rcdu = crtc->dev->dev_private;
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
if (rcrtc->dpms == mode)
return;
if (mode == DRM_MODE_DPMS_ON) {
- rcar_du_get(rcdu);
+ rcar_du_crtc_get(rcrtc);
rcar_du_crtc_start(rcrtc);
} else {
rcar_du_crtc_stop(rcrtc);
- rcar_du_put(rcdu);
+ rcar_du_crtc_put(rcrtc);
}
rcrtc->dpms = mode;
@@ -367,13 +386,12 @@ static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc,
static void rcar_du_crtc_mode_prepare(struct drm_crtc *crtc)
{
- struct rcar_du_device *rcdu = crtc->dev->dev_private;
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
/* We need to access the hardware during mode set, acquire a reference
- * to the DU.
+ * to the CRTC.
*/
- rcar_du_get(rcdu);
+ rcar_du_crtc_get(rcrtc);
/* Stop the CRTC and release the plane. Force the DPMS mode to off as a
* result.
@@ -423,10 +441,10 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
error:
/* There's no rollback/abort operation to clean up in case of error. We
- * thus need to release the reference to the DU acquired in prepare()
+ * thus need to release the reference to the CRTC acquired in prepare()
* here.
*/
- rcar_du_put(rcdu);
+ rcar_du_crtc_put(rcrtc);
return ret;
}
@@ -514,6 +532,24 @@ static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
drm_vblank_put(dev, rcrtc->index);
}
+static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
+{
+ struct rcar_du_crtc *rcrtc = arg;
+ irqreturn_t ret = IRQ_NONE;
+ u32 status;
+
+ status = rcar_du_crtc_read(rcrtc, DSSR);
+ rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
+
+ if (status & DSSR_VBK) {
+ drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
+ rcar_du_crtc_finish_page_flip(rcrtc);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event)
@@ -551,10 +587,29 @@ static const struct drm_crtc_funcs crtc_funcs = {
int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index)
{
+ struct platform_device *pdev = to_platform_device(rcdu->dev);
struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
struct drm_crtc *crtc = &rcrtc->crtc;
+ unsigned int irqflags;
+ char clk_name[5];
+ char *name;
+ int irq;
int ret;
+ /* Get the CRTC clock. */
+ if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) {
+ sprintf(clk_name, "du.%u", index);
+ name = clk_name;
+ } else {
+ name = NULL;
+ }
+
+ rcrtc->clock = devm_clk_get(rcdu->dev, name);
+ if (IS_ERR(rcrtc->clock)) {
+ dev_err(rcdu->dev, "no clock for CRTC %u\n", index);
+ return PTR_ERR(rcrtc->clock);
+ }
+
rcrtc->mmio_offset = index ? DISP2_REG_OFFSET : 0;
rcrtc->index = index;
rcrtc->dpms = DRM_MODE_DPMS_OFF;
@@ -568,6 +623,28 @@ int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index)
drm_crtc_helper_add(crtc, &crtc_helper_funcs);
+ /* Register the interrupt handler. */
+ if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) {
+ irq = platform_get_irq(pdev, index);
+ irqflags = 0;
+ } else {
+ irq = platform_get_irq(pdev, 0);
+ irqflags = IRQF_SHARED;
+ }
+
+ if (irq < 0) {
+ dev_err(rcdu->dev, "no IRQ for CRTC %u\n", index);
+ return ret;
+ }
+
+ ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags,
+ dev_name(rcdu->dev), rcrtc);
+ if (ret < 0) {
+ dev_err(rcdu->dev,
+ "failed to register IRQ for CRTC %u\n", index);
+ return ret;
+ }
+
return 0;
}
@@ -580,16 +657,3 @@ void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable)
rcar_du_crtc_clr(rcrtc, DIER, DIER_VBE);
}
}
-
-void rcar_du_crtc_irq(struct rcar_du_crtc *rcrtc)
-{
- u32 status;
-
- status = rcar_du_crtc_read(rcrtc, DSSR);
- rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
-
- if (status & DSSR_VBK) {
- drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
- rcar_du_crtc_finish_page_flip(rcrtc);
- }
-}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 2a0365b..5b69e98 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -25,6 +25,7 @@ struct rcar_du_plane;
struct rcar_du_crtc {
struct drm_crtc crtc;
+ struct clk *clock;
unsigned int mmio_offset;
unsigned int index;
bool started;
@@ -38,7 +39,6 @@ struct rcar_du_crtc {
int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index);
void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable);
-void rcar_du_crtc_irq(struct rcar_du_crtc *rcrtc);
void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
struct drm_file *file);
void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index bb7193d..5f82e04 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -35,8 +35,8 @@
/*
* rcar_du_get - Acquire a reference to the DU
*
- * Acquiring a reference enables the device clock and setup core registers. A
- * reference must be held before accessing any hardware registers.
+ * Acquiring the first reference setups core registers. A reference must be
+ * held before accessing any hardware registers.
*
* This function must be called with the DRM mode_config lock held.
*
@@ -44,16 +44,9 @@
*/
int rcar_du_get(struct rcar_du_device *rcdu)
{
- int ret;
-
if (rcdu->use_count)
goto done;
- /* Enable clocks before accessing the hardware. */
- ret = clk_prepare_enable(rcdu->clock);
- if (ret < 0)
- return ret;
-
/* Enable extended features */
rcar_du_write(rcdu, DEFR, DEFR_CODE | DEFR_DEFE);
rcar_du_write(rcdu, DEFR2, DEFR2_CODE | DEFR2_DEFE2G);
@@ -74,16 +67,11 @@ done:
/*
* rcar_du_put - Release a reference to the DU
*
- * Releasing the last reference disables the device clock.
- *
* This function must be called with the DRM mode_config lock held.
*/
void rcar_du_put(struct rcar_du_device *rcdu)
{
- if (--rcdu->use_count)
- return;
-
- clk_disable_unprepare(rcdu->clock);
+ --rcdu->use_count;
}
/* -----------------------------------------------------------------------------
@@ -95,8 +83,8 @@ static int rcar_du_unload(struct drm_device *dev)
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
drm_vblank_cleanup(dev);
- drm_irq_uninstall(dev);
+ dev->irq_enabled = 0;
dev->dev_private = NULL;
return 0;
@@ -127,18 +115,12 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
rcdu->ddev = dev;
dev->dev_private = rcdu;
- /* I/O resources and clocks */
+ /* I/O resources */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(rcdu->mmio))
return PTR_ERR(rcdu->mmio);
- rcdu->clock = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(rcdu->clock)) {
- dev_err(&pdev->dev, "failed to get clock\n");
- return -ENOENT;
- }
-
/* DRM/KMS objects */
ret = rcar_du_modeset_init(rcdu);
if (ret < 0) {
@@ -146,18 +128,14 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
goto done;
}
- /* IRQ and vblank handling */
+ /* vblank handling */
ret = drm_vblank_init(dev, (1 << rcdu->num_crtcs) - 1);
if (ret < 0) {
dev_err(&pdev->dev, "failed to initialize vblank\n");
goto done;
}
- ret = drm_irq_install(dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to install IRQ handler\n");
- goto done;
- }
+ dev->irq_enabled = 1;
platform_set_drvdata(pdev, rcdu);
@@ -177,18 +155,6 @@ static void rcar_du_preclose(struct drm_device *dev, struct drm_file *file)
rcar_du_crtc_cancel_page_flip(&rcdu->crtcs[i], file);
}
-static irqreturn_t rcar_du_irq(int irq, void *arg)
-{
- struct drm_device *dev = arg;
- struct rcar_du_device *rcdu = dev->dev_private;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i)
- rcar_du_crtc_irq(&rcdu->crtcs[i]);
-
- return IRQ_HANDLED;
-}
-
static int rcar_du_enable_vblank(struct drm_device *dev, int crtc)
{
struct rcar_du_device *rcdu = dev->dev_private;
@@ -221,12 +187,10 @@ static const struct file_operations rcar_du_fops = {
};
static struct drm_driver rcar_du_driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
- | DRIVER_PRIME,
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME,
.load = rcar_du_load,
.unload = rcar_du_unload,
.preclose = rcar_du_preclose,
- .irq_handler = rcar_du_irq,
.get_vblank_counter = drm_vblank_count,
.enable_vblank = rcar_du_enable_vblank,
.disable_vblank = rcar_du_disable_vblank,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 06dbf4f..7d2320f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -25,6 +25,8 @@ struct clk;
struct device;
struct drm_device;
+#define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */
+
/*
* struct rcar_du_device_info - DU model-specific information
* @features: device features (RCAR_DU_FEATURE_*)
@@ -39,7 +41,6 @@ struct rcar_du_device {
const struct rcar_du_device_info *info;
void __iomem *mmio;
- struct clk *clock;
unsigned int use_count;
struct drm_device *ddev;
OpenPOWER on IntegriCloud