From e5d9ddfbb79667fb4b16db07c3282a2304fbf3ff Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 26 Apr 2014 15:19:38 +0100 Subject: drm/armada: move IRQ handling into CRTC Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/armada/armada_crtc.c') diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 81c34f949dfc..9341a94cc906 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -349,7 +349,7 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) +static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) { struct armada_vbl_event *e, *n; void __iomem *base = dcrtc->base; @@ -410,6 +410,27 @@ void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) } } +static irqreturn_t armada_drm_irq(int irq, void *arg) +{ + struct armada_crtc *dcrtc = arg; + u32 v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR); + + /* + * This is rediculous - rather than writing bits to clear, we + * have to set the actual status register value. This is racy. + */ + writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); + + /* Mask out those interrupts we haven't enabled */ + v = stat & dcrtc->irq_ena; + + if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) { + armada_drm_crtc_irq(dcrtc, stat); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + /* These are locked by dev->vbl_lock */ void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask) { @@ -888,6 +909,8 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) if (!IS_ERR(dcrtc->clk)) clk_disable_unprepare(dcrtc->clk); + writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA); + kfree(dcrtc); } @@ -1028,7 +1051,7 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev) } int armada_drm_crtc_create(struct drm_device *dev, unsigned num, - struct resource *res) + struct resource *res, int irq) { struct armada_private *priv = dev->dev_private; struct armada_crtc *dcrtc; @@ -1074,6 +1097,15 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num, CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1); writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN); + writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); + writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); + + ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc", + dcrtc); + if (ret < 0) { + kfree(dcrtc); + return ret; + } if (priv->variant->crtc_init) { ret = priv->variant->crtc_init(dcrtc); -- cgit v1.2.3 From d016540722bb412ffa8376a9db0de757ce915bfb Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 22 Apr 2014 11:02:23 +0100 Subject: drm/armada: use number of CRTCs registered Use the number of CRTCs registered to size the vblank arrays rather than our own count. Number CRTCs using this as well. This permits us to register CRTCs as components in the near future rather than as part of a single device. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/armada/armada_crtc.c') diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 9341a94cc906..4336dfd3585d 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1050,8 +1050,8 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev) return 0; } -int armada_drm_crtc_create(struct drm_device *dev, unsigned num, - struct resource *res, int irq) +int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, + int irq) { struct armada_private *priv = dev->dev_private; struct armada_crtc *dcrtc; @@ -1075,7 +1075,7 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num, } dcrtc->base = base; - dcrtc->num = num; + dcrtc->num = dev->mode_config.num_crtc; dcrtc->clk = ERR_PTR(-EINVAL); dcrtc->csc_yuv_mode = CSC_AUTO; dcrtc->csc_rgb_mode = CSC_AUTO; -- cgit v1.2.3 From 3ecea269959afaae50b001deb294cfb9539dbea3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 22 Apr 2014 15:21:30 +0100 Subject: drm/armada: move variant initialisation to CRTC init Move the variant initialisation entirely to the CRTC init function - the variant support is really about the CRTC properties than the whole system, and we want to treat each CRTC individually when we support DT. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/armada/armada_crtc.c') diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 4336dfd3585d..3adddabc3626 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1108,7 +1108,7 @@ int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, } if (priv->variant->crtc_init) { - ret = priv->variant->crtc_init(dcrtc); + ret = priv->variant->crtc_init(dcrtc, dev->dev); if (ret) { kfree(dcrtc); return ret; -- cgit v1.2.3 From 42e62ba7a484e12a77b9e330a29bbf7c99d3e60e Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 22 Apr 2014 15:24:03 +0100 Subject: drm/armada: make variant a CRTC thing Move the variant pointer into the armada_crtc structure, and update for the resulting changes. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/armada/armada_crtc.c') diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 3adddabc3626..afa497489000 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -332,17 +332,16 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adj) { - struct armada_private *priv = crtc->dev->dev_private; struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); int ret; /* We can't do interlaced modes if we don't have the SPU_ADV_REG */ - if (!priv->variant->has_spu_adv_reg && + if (!dcrtc->variant->has_spu_adv_reg && adj->flags & DRM_MODE_FLAG_INTERLACE) return false; /* Check whether the display mode is possible */ - ret = priv->variant->crtc_compute_clock(dcrtc, adj, NULL); + ret = dcrtc->variant->compute_clock(dcrtc, adj, NULL); if (ret) return false; @@ -491,7 +490,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adj, int x, int y, struct drm_framebuffer *old_fb) { - struct armada_private *priv = crtc->dev->dev_private; struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct armada_regs regs[17]; uint32_t lm, rm, tm, bm, val, sclk; @@ -536,7 +534,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, } /* Now compute the divider for real */ - priv->variant->crtc_compute_clock(dcrtc, adj, &sclk); + dcrtc->variant->compute_clock(dcrtc, adj, &sclk); /* Ensure graphic fifo is enabled */ armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); @@ -558,7 +556,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, dcrtc->v[1].spu_v_porch = tm << 16 | bm; val = adj->crtc_hsync_start; dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | - priv->variant->spu_adv_reg; + dcrtc->variant->spu_adv_reg; if (interlaced) { /* Odd interlaced frame */ @@ -567,7 +565,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; val = adj->crtc_hsync_start - adj->crtc_htotal / 2; dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | - priv->variant->spu_adv_reg; + dcrtc->variant->spu_adv_reg; } else { dcrtc->v[0] = dcrtc->v[1]; } @@ -582,7 +580,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, LCD_SPUT_V_H_TOTAL); - if (priv->variant->has_spu_adv_reg) { + if (dcrtc->variant->has_spu_adv_reg) { armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); @@ -826,12 +824,11 @@ static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct armada_private *priv = crtc->dev->dev_private; struct armada_gem_object *obj = NULL; int ret; /* If no cursor support, replicate drm's return value */ - if (!priv->variant->has_spu_adv_reg) + if (!dcrtc->variant->has_spu_adv_reg) return -ENXIO; if (handle && w > 0 && h > 0) { @@ -879,11 +876,10 @@ static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) { struct drm_device *dev = crtc->dev; struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct armada_private *priv = crtc->dev->dev_private; int ret; /* If no cursor support, replicate drm's return value */ - if (!priv->variant->has_spu_adv_reg) + if (!dcrtc->variant->has_spu_adv_reg) return -EFAULT; mutex_lock(&dev->struct_mutex); @@ -1051,7 +1047,7 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev) } int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, - int irq) + int irq, const struct armada_variant *variant) { struct armada_private *priv = dev->dev_private; struct armada_crtc *dcrtc; @@ -1074,6 +1070,7 @@ int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, return -ENOMEM; } + dcrtc->variant = variant; dcrtc->base = base; dcrtc->num = dev->mode_config.num_crtc; dcrtc->clk = ERR_PTR(-EINVAL); @@ -1107,8 +1104,8 @@ int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, return ret; } - if (priv->variant->crtc_init) { - ret = priv->variant->crtc_init(dcrtc, dev->dev); + if (dcrtc->variant->init) { + ret = dcrtc->variant->init(dcrtc, dev->dev); if (ret) { kfree(dcrtc); return ret; -- cgit v1.2.3 From d8c96083cf5e4a910c20836414e8a06ebcf07317 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 22 Apr 2014 11:10:15 +0100 Subject: drm/armada: permit CRTCs to be registered as separate devices Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 113 ++++++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/armada/armada_crtc.c') diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index afa497489000..0642b5cfa563 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -7,6 +7,9 @@ * published by the Free Software Foundation. */ #include +#include +#include +#include #include #include #include "armada_crtc.h" @@ -1046,19 +1049,19 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev) return 0; } -int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, - int irq, const struct armada_variant *variant) +int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, + struct resource *res, int irq, const struct armada_variant *variant) { - struct armada_private *priv = dev->dev_private; + struct armada_private *priv = drm->dev_private; struct armada_crtc *dcrtc; void __iomem *base; int ret; - ret = armada_drm_crtc_create_properties(dev); + ret = armada_drm_crtc_create_properties(drm); if (ret) return ret; - base = devm_request_and_ioremap(dev->dev, res); + base = devm_request_and_ioremap(dev, res); if (!base) { DRM_ERROR("failed to ioremap register\n"); return -ENOMEM; @@ -1070,9 +1073,12 @@ int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, return -ENOMEM; } + if (dev != drm->dev) + dev_set_drvdata(dev, dcrtc); + dcrtc->variant = variant; dcrtc->base = base; - dcrtc->num = dev->mode_config.num_crtc; + dcrtc->num = drm->mode_config.num_crtc; dcrtc->clk = ERR_PTR(-EINVAL); dcrtc->csc_yuv_mode = CSC_AUTO; dcrtc->csc_rgb_mode = CSC_AUTO; @@ -1105,7 +1111,7 @@ int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, } if (dcrtc->variant->init) { - ret = dcrtc->variant->init(dcrtc, dev->dev); + ret = dcrtc->variant->init(dcrtc, dev); if (ret) { kfree(dcrtc); return ret; @@ -1117,7 +1123,7 @@ int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, priv->dcrtc[dcrtc->num] = dcrtc; - drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs); + drm_crtc_init(drm, &dcrtc->crtc, &armada_crtc_funcs); drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop, @@ -1125,5 +1131,94 @@ int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop, dcrtc->csc_rgb_mode); - return armada_overlay_plane_create(dev, 1 << dcrtc->num); + return armada_overlay_plane_create(drm, 1 << dcrtc->num); +} + +static int +armada_lcd_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = data; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int irq = platform_get_irq(pdev, 0); + const struct armada_variant *variant; + + if (irq < 0) + return irq; + + if (!dev->of_node) { + const struct platform_device_id *id; + + id = platform_get_device_id(pdev); + if (!id) + return -ENXIO; + + variant = (const struct armada_variant *)id->driver_data; + } else { + const struct of_device_id *match; + + match = of_match_device(dev->driver->of_match_table, dev); + if (!match) + return -ENXIO; + + variant = match->data; + } + + return armada_drm_crtc_create(drm, dev, res, irq, variant); +} + +static void +armada_lcd_unbind(struct device *dev, struct device *master, void *data) +{ + struct armada_crtc *dcrtc = dev_get_drvdata(dev); + + armada_drm_crtc_destroy(&dcrtc->crtc); +} + +static const struct component_ops armada_lcd_ops = { + .bind = armada_lcd_bind, + .unbind = armada_lcd_unbind, +}; + +static int armada_lcd_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &armada_lcd_ops); +} + +static int armada_lcd_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &armada_lcd_ops); + return 0; } + +static struct of_device_id armada_lcd_of_match[] = { + { + .compatible = "marvell,dove-lcd", + .data = &armada510_ops, + }, + {} +}; +MODULE_DEVICE_TABLE(of, armada_lcd_of_match); + +static const struct platform_device_id armada_lcd_platform_ids[] = { + { + .name = "armada-lcd", + .driver_data = (unsigned long)&armada510_ops, + }, { + .name = "armada-510-lcd", + .driver_data = (unsigned long)&armada510_ops, + }, + { }, +}; +MODULE_DEVICE_TABLE(platform, armada_lcd_platform_ids); + +struct platform_driver armada_lcd_platform_driver = { + .probe = armada_lcd_probe, + .remove = armada_lcd_remove, + .driver = { + .name = "armada-lcd", + .owner = THIS_MODULE, + .of_match_table = armada_lcd_of_match, + }, + .id_table = armada_lcd_platform_ids, +}; -- cgit v1.2.3 From 9611cb93fa65dde199f4f888bd034ffc80c7adf0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 15 Jun 2014 11:21:23 +0100 Subject: drm/armada: register crtc with port Register the CRTC with the port node so that the DRM OF helpers can find the appropriate CRTC. This is important so that encoders can identify their corresponding possible CRTCs. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/armada/armada_crtc.c') diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 0642b5cfa563..3f620e21e06b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -910,6 +910,8 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA); + of_node_put(dcrtc->crtc.port); + kfree(dcrtc); } @@ -1050,7 +1052,8 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev) } int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, - struct resource *res, int irq, const struct armada_variant *variant) + struct resource *res, int irq, const struct armada_variant *variant, + struct device_node *port) { struct armada_private *priv = drm->dev_private; struct armada_crtc *dcrtc; @@ -1123,6 +1126,7 @@ int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, priv->dcrtc[dcrtc->num] = dcrtc; + dcrtc->crtc.port = port; drm_crtc_init(drm, &dcrtc->crtc, &armada_crtc_funcs); drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); @@ -1142,6 +1146,7 @@ armada_lcd_bind(struct device *dev, struct device *master, void *data) struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); const struct armada_variant *variant; + struct device_node *port = NULL; if (irq < 0) return irq; @@ -1156,15 +1161,27 @@ armada_lcd_bind(struct device *dev, struct device *master, void *data) variant = (const struct armada_variant *)id->driver_data; } else { const struct of_device_id *match; + struct device_node *np, *parent = dev->of_node; match = of_match_device(dev->driver->of_match_table, dev); if (!match) return -ENXIO; + np = of_get_child_by_name(parent, "ports"); + if (np) + parent = np; + port = of_get_child_by_name(parent, "port"); + of_node_put(np); + if (!port) { + dev_err(dev, "no port node found in %s\n", + parent->full_name); + return -ENXIO; + } + variant = match->data; } - return armada_drm_crtc_create(drm, dev, res, irq, variant); + return armada_drm_crtc_create(drm, dev, res, irq, variant, port); } static void -- cgit v1.2.3