summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c')
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c132
1 files changed, 81 insertions, 51 deletions
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
index 7528e8a2d359..3bbfc1b56a65 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -18,13 +18,13 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_irq.h>
+#include <drm/drm_fbdev_dma.h>
+#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_modeset_helper.h>
+#include <drm/drm_module.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
@@ -51,7 +51,7 @@ static const struct regmap_config fsl_dcu_regmap_config = {
.volatile_reg = fsl_dcu_drm_is_volatile_reg,
};
-static void fsl_dcu_irq_uninstall(struct drm_device *dev)
+static void fsl_dcu_irq_reset(struct drm_device *dev)
{
struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
@@ -59,27 +59,79 @@ static void fsl_dcu_irq_uninstall(struct drm_device *dev)
regmap_write(fsl_dev->regmap, DCU_INT_MASK, ~0);
}
+static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
+{
+ struct drm_device *dev = arg;
+ struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
+ unsigned int int_status;
+ int ret;
+
+ ret = regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
+ if (ret) {
+ dev_err(dev->dev, "read DCU_INT_STATUS failed\n");
+ return IRQ_NONE;
+ }
+
+ if (int_status & DCU_INT_STATUS_VBLANK)
+ drm_handle_vblank(dev, 0);
+
+ regmap_write(fsl_dev->regmap, DCU_INT_STATUS, int_status);
+
+ return IRQ_HANDLED;
+}
+
+static int fsl_dcu_irq_install(struct drm_device *dev, unsigned int irq)
+{
+ if (irq == IRQ_NOTCONNECTED)
+ return -ENOTCONN;
+
+ fsl_dcu_irq_reset(dev);
+
+ return request_irq(irq, fsl_dcu_drm_irq, 0, dev->driver->name, dev);
+}
+
+static void fsl_dcu_irq_uninstall(struct drm_device *dev)
+{
+ struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
+
+ fsl_dcu_irq_reset(dev);
+ free_irq(fsl_dev->irq, dev);
+}
+
static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
{
struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
+ struct regmap *scfg;
int ret;
ret = fsl_dcu_drm_modeset_init(fsl_dev);
- if (ret < 0) {
- dev_err(dev->dev, "failed to initialize mode setting\n");
- return ret;
+ if (ret < 0)
+ return dev_err_probe(dev->dev, ret, "failed to initialize mode setting\n");
+
+ scfg = syscon_regmap_lookup_by_compatible("fsl,ls1021a-scfg");
+ if (PTR_ERR(scfg) != -ENODEV) {
+ /*
+ * For simplicity, enable the PIXCLK unconditionally,
+ * resulting in increased power consumption. Disabling
+ * the clock in PM or on unload could be implemented as
+ * a future improvement.
+ */
+ ret = regmap_update_bits(scfg, SCFG_PIXCLKCR, SCFG_PIXCLKCR_PXCEN,
+ SCFG_PIXCLKCR_PXCEN);
+ if (ret < 0)
+ return dev_err_probe(dev->dev, ret, "failed to enable pixclk\n");
}
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n");
- goto done;
+ goto done_vblank;
}
- ret = drm_irq_install(dev, fsl_dev->irq);
+ ret = fsl_dcu_irq_install(dev, fsl_dev->irq);
if (ret < 0) {
dev_err(dev->dev, "failed to install IRQ handler\n");
- goto done;
+ goto done_irq;
}
if (legacyfb_depth != 16 && legacyfb_depth != 24 &&
@@ -90,11 +142,11 @@ static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
}
return 0;
-done:
+done_irq:
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
- drm_irq_uninstall(dev);
+done_vblank:
dev->dev_private = NULL;
return ret;
@@ -106,46 +158,22 @@ static void fsl_dcu_unload(struct drm_device *dev)
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
- drm_irq_uninstall(dev);
+ fsl_dcu_irq_uninstall(dev);
dev->dev_private = NULL;
}
-static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
-{
- struct drm_device *dev = arg;
- struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
- unsigned int int_status;
- int ret;
-
- ret = regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
- if (ret) {
- dev_err(dev->dev, "read DCU_INT_STATUS failed\n");
- return IRQ_NONE;
- }
-
- if (int_status & DCU_INT_STATUS_VBLANK)
- drm_handle_vblank(dev, 0);
-
- regmap_write(fsl_dev->regmap, DCU_INT_STATUS, int_status);
-
- return IRQ_HANDLED;
-}
-
-DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops);
+DEFINE_DRM_GEM_DMA_FOPS(fsl_dcu_drm_fops);
static const struct drm_driver fsl_dcu_drm_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.load = fsl_dcu_load,
.unload = fsl_dcu_unload,
- .irq_handler = fsl_dcu_drm_irq,
- .irq_preinstall = fsl_dcu_irq_uninstall,
- .irq_uninstall = fsl_dcu_irq_uninstall,
- DRM_GEM_CMA_DRIVER_OPS,
+ DRM_GEM_DMA_DRIVER_OPS,
+ DRM_FBDEV_DMA_DRIVER_OPS,
.fops = &fsl_dcu_drm_fops,
.name = "fsl-dcu-drm",
.desc = "Freescale DCU DRM",
- .date = "20160425",
.major = 1,
.minor = 1,
};
@@ -232,7 +260,6 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
struct fsl_dcu_drm_device *fsl_dev;
struct drm_device *drm;
struct device *dev = &pdev->dev;
- struct resource *res;
void __iomem *base;
struct clk *pix_clk_in;
char pix_clk_name[32];
@@ -250,18 +277,15 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
return -ENODEV;
fsl_dev->soc = id->data;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
+ base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
ret = PTR_ERR(base);
return ret;
}
fsl_dev->irq = platform_get_irq(pdev, 0);
- if (fsl_dev->irq < 0) {
- dev_err(dev, "failed to get irq\n");
+ if (fsl_dev->irq < 0)
return fsl_dev->irq;
- }
fsl_dev->regmap = devm_regmap_init_mmio(dev, base,
&fsl_dcu_regmap_config);
@@ -319,7 +343,7 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
if (ret < 0)
goto put;
- drm_fbdev_generic_setup(drm, legacyfb_depth);
+ drm_client_setup_with_color_mode(drm, legacyfb_depth);
return 0;
@@ -332,7 +356,7 @@ disable_clk:
return ret;
}
-static int fsl_dcu_drm_remove(struct platform_device *pdev)
+static void fsl_dcu_drm_remove(struct platform_device *pdev)
{
struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
@@ -340,13 +364,19 @@ static int fsl_dcu_drm_remove(struct platform_device *pdev)
drm_dev_put(fsl_dev->drm);
clk_disable_unprepare(fsl_dev->clk);
clk_unregister(fsl_dev->pix_clk);
+}
- return 0;
+static void fsl_dcu_drm_shutdown(struct platform_device *pdev)
+{
+ struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
+
+ drm_atomic_helper_shutdown(fsl_dev->drm);
}
static struct platform_driver fsl_dcu_drm_platform_driver = {
.probe = fsl_dcu_drm_probe,
.remove = fsl_dcu_drm_remove,
+ .shutdown = fsl_dcu_drm_shutdown,
.driver = {
.name = "fsl-dcu",
.pm = &fsl_dcu_drm_pm_ops,
@@ -354,7 +384,7 @@ static struct platform_driver fsl_dcu_drm_platform_driver = {
},
};
-module_platform_driver(fsl_dcu_drm_platform_driver);
+drm_module_platform_driver(fsl_dcu_drm_platform_driver);
MODULE_DESCRIPTION("Freescale DCU DRM Driver");
MODULE_LICENSE("GPL");