19db35bb3SMarek Vasut // SPDX-License-Identifier: GPL-2.0-or-later
29db35bb3SMarek Vasut /*
39db35bb3SMarek Vasut * Copyright (C) 2022 Marek Vasut <marex@denx.de>
49db35bb3SMarek Vasut *
59db35bb3SMarek Vasut * This code is based on drivers/gpu/drm/mxsfb/mxsfb*
69db35bb3SMarek Vasut */
79db35bb3SMarek Vasut
89db35bb3SMarek Vasut #include <linux/clk.h>
99db35bb3SMarek Vasut #include <linux/dma-mapping.h>
109db35bb3SMarek Vasut #include <linux/io.h>
119db35bb3SMarek Vasut #include <linux/module.h>
12dbb32d85SLiu Ying #include <linux/of.h>
13dbb32d85SLiu Ying #include <linux/of_graph.h>
149db35bb3SMarek Vasut #include <linux/platform_device.h>
159db35bb3SMarek Vasut #include <linux/pm_runtime.h>
169db35bb3SMarek Vasut
179db35bb3SMarek Vasut #include <drm/drm_atomic_helper.h>
189db35bb3SMarek Vasut #include <drm/drm_bridge.h>
199db35bb3SMarek Vasut #include <drm/drm_drv.h>
20dbb32d85SLiu Ying #include <drm/drm_encoder.h>
2155c7cd97SThomas Zimmermann #include <drm/drm_fbdev_dma.h>
224a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
239db35bb3SMarek Vasut #include <drm/drm_gem_framebuffer_helper.h>
249db35bb3SMarek Vasut #include <drm/drm_mode_config.h>
259db35bb3SMarek Vasut #include <drm/drm_module.h>
269db35bb3SMarek Vasut #include <drm/drm_of.h>
279db35bb3SMarek Vasut #include <drm/drm_probe_helper.h>
289db35bb3SMarek Vasut #include <drm/drm_vblank.h>
299db35bb3SMarek Vasut
309db35bb3SMarek Vasut #include "lcdif_drv.h"
319db35bb3SMarek Vasut #include "lcdif_regs.h"
329db35bb3SMarek Vasut
339db35bb3SMarek Vasut static const struct drm_mode_config_funcs lcdif_mode_config_funcs = {
349db35bb3SMarek Vasut .fb_create = drm_gem_fb_create,
359db35bb3SMarek Vasut .atomic_check = drm_atomic_helper_check,
369db35bb3SMarek Vasut .atomic_commit = drm_atomic_helper_commit,
379db35bb3SMarek Vasut };
389db35bb3SMarek Vasut
399db35bb3SMarek Vasut static const struct drm_mode_config_helper_funcs lcdif_mode_config_helpers = {
409db35bb3SMarek Vasut .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
419db35bb3SMarek Vasut };
429db35bb3SMarek Vasut
43dbb32d85SLiu Ying static const struct drm_encoder_funcs lcdif_encoder_funcs = {
44dbb32d85SLiu Ying .destroy = drm_encoder_cleanup,
45dbb32d85SLiu Ying };
46dbb32d85SLiu Ying
lcdif_attach_bridge(struct lcdif_drm_private * lcdif)479db35bb3SMarek Vasut static int lcdif_attach_bridge(struct lcdif_drm_private *lcdif)
489db35bb3SMarek Vasut {
49dbb32d85SLiu Ying struct device *dev = lcdif->drm->dev;
50dbb32d85SLiu Ying struct device_node *ep;
519db35bb3SMarek Vasut struct drm_bridge *bridge;
529db35bb3SMarek Vasut int ret;
539db35bb3SMarek Vasut
54dbb32d85SLiu Ying for_each_endpoint_of_node(dev->of_node, ep) {
55dbb32d85SLiu Ying struct device_node *remote;
56dbb32d85SLiu Ying struct of_endpoint of_ep;
57dbb32d85SLiu Ying struct drm_encoder *encoder;
589db35bb3SMarek Vasut
59dbb32d85SLiu Ying remote = of_graph_get_remote_port_parent(ep);
60dbb32d85SLiu Ying if (!of_device_is_available(remote)) {
61dbb32d85SLiu Ying of_node_put(remote);
62dbb32d85SLiu Ying continue;
63dbb32d85SLiu Ying }
64dbb32d85SLiu Ying of_node_put(remote);
65dbb32d85SLiu Ying
66dbb32d85SLiu Ying ret = of_graph_parse_endpoint(ep, &of_ep);
67dbb32d85SLiu Ying if (ret < 0) {
68dbb32d85SLiu Ying dev_err(dev, "Failed to parse endpoint %pOF\n", ep);
69dbb32d85SLiu Ying of_node_put(ep);
70dbb32d85SLiu Ying return ret;
71dbb32d85SLiu Ying }
72dbb32d85SLiu Ying
73dbb32d85SLiu Ying bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, of_ep.id);
74dbb32d85SLiu Ying if (IS_ERR(bridge)) {
75dbb32d85SLiu Ying of_node_put(ep);
76dbb32d85SLiu Ying return dev_err_probe(dev, PTR_ERR(bridge),
77dbb32d85SLiu Ying "Failed to get bridge for endpoint%u\n",
78dbb32d85SLiu Ying of_ep.id);
79dbb32d85SLiu Ying }
80dbb32d85SLiu Ying
81dbb32d85SLiu Ying encoder = devm_kzalloc(dev, sizeof(*encoder), GFP_KERNEL);
82dbb32d85SLiu Ying if (!encoder) {
83dbb32d85SLiu Ying dev_err(dev, "Failed to allocate encoder for endpoint%u\n",
84dbb32d85SLiu Ying of_ep.id);
85dbb32d85SLiu Ying of_node_put(ep);
86dbb32d85SLiu Ying return -ENOMEM;
87dbb32d85SLiu Ying }
88dbb32d85SLiu Ying
89dbb32d85SLiu Ying encoder->possible_crtcs = drm_crtc_mask(&lcdif->crtc);
90dbb32d85SLiu Ying ret = drm_encoder_init(lcdif->drm, encoder, &lcdif_encoder_funcs,
91dbb32d85SLiu Ying DRM_MODE_ENCODER_NONE, NULL);
92dbb32d85SLiu Ying if (ret) {
93dbb32d85SLiu Ying dev_err(dev, "Failed to initialize encoder for endpoint%u: %d\n",
94dbb32d85SLiu Ying of_ep.id, ret);
95dbb32d85SLiu Ying of_node_put(ep);
96dbb32d85SLiu Ying return ret;
97dbb32d85SLiu Ying }
98dbb32d85SLiu Ying
99dbb32d85SLiu Ying ret = drm_bridge_attach(encoder, bridge, NULL, 0);
100dbb32d85SLiu Ying if (ret) {
101dbb32d85SLiu Ying of_node_put(ep);
102dbb32d85SLiu Ying return dev_err_probe(dev, ret,
103dbb32d85SLiu Ying "Failed to attach bridge for endpoint%u\n",
104dbb32d85SLiu Ying of_ep.id);
105dbb32d85SLiu Ying }
106dbb32d85SLiu Ying }
1079db35bb3SMarek Vasut
1089db35bb3SMarek Vasut return 0;
1099db35bb3SMarek Vasut }
1109db35bb3SMarek Vasut
lcdif_irq_handler(int irq,void * data)1119db35bb3SMarek Vasut static irqreturn_t lcdif_irq_handler(int irq, void *data)
1129db35bb3SMarek Vasut {
1139db35bb3SMarek Vasut struct drm_device *drm = data;
1149db35bb3SMarek Vasut struct lcdif_drm_private *lcdif = drm->dev_private;
1159db35bb3SMarek Vasut u32 reg, stat;
1169db35bb3SMarek Vasut
1179db35bb3SMarek Vasut stat = readl(lcdif->base + LCDC_V8_INT_STATUS_D0);
1189db35bb3SMarek Vasut if (!stat)
1199db35bb3SMarek Vasut return IRQ_NONE;
1209db35bb3SMarek Vasut
1219db35bb3SMarek Vasut if (stat & INT_STATUS_D0_VS_BLANK) {
1229db35bb3SMarek Vasut reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
1239db35bb3SMarek Vasut if (!(reg & CTRLDESCL0_5_SHADOW_LOAD_EN))
1249db35bb3SMarek Vasut drm_crtc_handle_vblank(&lcdif->crtc);
1259db35bb3SMarek Vasut }
1269db35bb3SMarek Vasut
1279db35bb3SMarek Vasut writel(stat, lcdif->base + LCDC_V8_INT_STATUS_D0);
1289db35bb3SMarek Vasut
1299db35bb3SMarek Vasut return IRQ_HANDLED;
1309db35bb3SMarek Vasut }
1319db35bb3SMarek Vasut
lcdif_load(struct drm_device * drm)1329db35bb3SMarek Vasut static int lcdif_load(struct drm_device *drm)
1339db35bb3SMarek Vasut {
1349db35bb3SMarek Vasut struct platform_device *pdev = to_platform_device(drm->dev);
1359db35bb3SMarek Vasut struct lcdif_drm_private *lcdif;
1369db35bb3SMarek Vasut struct resource *res;
1379db35bb3SMarek Vasut int ret;
1389db35bb3SMarek Vasut
1399db35bb3SMarek Vasut lcdif = devm_kzalloc(&pdev->dev, sizeof(*lcdif), GFP_KERNEL);
1409db35bb3SMarek Vasut if (!lcdif)
1419db35bb3SMarek Vasut return -ENOMEM;
1429db35bb3SMarek Vasut
1439db35bb3SMarek Vasut lcdif->drm = drm;
1449db35bb3SMarek Vasut drm->dev_private = lcdif;
1459db35bb3SMarek Vasut
1469db35bb3SMarek Vasut res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1479db35bb3SMarek Vasut lcdif->base = devm_ioremap_resource(drm->dev, res);
1489db35bb3SMarek Vasut if (IS_ERR(lcdif->base))
1499db35bb3SMarek Vasut return PTR_ERR(lcdif->base);
1509db35bb3SMarek Vasut
1519db35bb3SMarek Vasut lcdif->clk = devm_clk_get(drm->dev, "pix");
1529db35bb3SMarek Vasut if (IS_ERR(lcdif->clk))
1539db35bb3SMarek Vasut return PTR_ERR(lcdif->clk);
1549db35bb3SMarek Vasut
1559db35bb3SMarek Vasut lcdif->clk_axi = devm_clk_get(drm->dev, "axi");
1569db35bb3SMarek Vasut if (IS_ERR(lcdif->clk_axi))
1579db35bb3SMarek Vasut return PTR_ERR(lcdif->clk_axi);
1589db35bb3SMarek Vasut
1599db35bb3SMarek Vasut lcdif->clk_disp_axi = devm_clk_get(drm->dev, "disp_axi");
1609db35bb3SMarek Vasut if (IS_ERR(lcdif->clk_disp_axi))
1619db35bb3SMarek Vasut return PTR_ERR(lcdif->clk_disp_axi);
1629db35bb3SMarek Vasut
1639db35bb3SMarek Vasut platform_set_drvdata(pdev, drm);
1649db35bb3SMarek Vasut
1659db35bb3SMarek Vasut ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(36));
1669db35bb3SMarek Vasut if (ret)
1679db35bb3SMarek Vasut return ret;
1689db35bb3SMarek Vasut
1699db35bb3SMarek Vasut /* Modeset init */
1709db35bb3SMarek Vasut drm_mode_config_init(drm);
1719db35bb3SMarek Vasut
1729db35bb3SMarek Vasut ret = lcdif_kms_init(lcdif);
1739db35bb3SMarek Vasut if (ret < 0) {
1749db35bb3SMarek Vasut dev_err(drm->dev, "Failed to initialize KMS pipeline\n");
1759db35bb3SMarek Vasut return ret;
1769db35bb3SMarek Vasut }
1779db35bb3SMarek Vasut
1789db35bb3SMarek Vasut ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
1799db35bb3SMarek Vasut if (ret < 0) {
1809db35bb3SMarek Vasut dev_err(drm->dev, "Failed to initialise vblank\n");
1819db35bb3SMarek Vasut return ret;
1829db35bb3SMarek Vasut }
1839db35bb3SMarek Vasut
1849db35bb3SMarek Vasut /* Start with vertical blanking interrupt reporting disabled. */
1859db35bb3SMarek Vasut drm_crtc_vblank_off(&lcdif->crtc);
1869db35bb3SMarek Vasut
1879db35bb3SMarek Vasut ret = lcdif_attach_bridge(lcdif);
1889db35bb3SMarek Vasut if (ret)
1899db35bb3SMarek Vasut return dev_err_probe(drm->dev, ret, "Cannot connect bridge\n");
1909db35bb3SMarek Vasut
1919db35bb3SMarek Vasut drm->mode_config.min_width = LCDIF_MIN_XRES;
1929db35bb3SMarek Vasut drm->mode_config.min_height = LCDIF_MIN_YRES;
1939db35bb3SMarek Vasut drm->mode_config.max_width = LCDIF_MAX_XRES;
1949db35bb3SMarek Vasut drm->mode_config.max_height = LCDIF_MAX_YRES;
1959db35bb3SMarek Vasut drm->mode_config.funcs = &lcdif_mode_config_funcs;
1969db35bb3SMarek Vasut drm->mode_config.helper_private = &lcdif_mode_config_helpers;
1979db35bb3SMarek Vasut
1989db35bb3SMarek Vasut drm_mode_config_reset(drm);
1999db35bb3SMarek Vasut
2009db35bb3SMarek Vasut ret = platform_get_irq(pdev, 0);
2019db35bb3SMarek Vasut if (ret < 0)
2029db35bb3SMarek Vasut return ret;
2039db35bb3SMarek Vasut lcdif->irq = ret;
2049db35bb3SMarek Vasut
2059db35bb3SMarek Vasut ret = devm_request_irq(drm->dev, lcdif->irq, lcdif_irq_handler, 0,
2069db35bb3SMarek Vasut drm->driver->name, drm);
2079db35bb3SMarek Vasut if (ret < 0) {
2089db35bb3SMarek Vasut dev_err(drm->dev, "Failed to install IRQ handler\n");
2099db35bb3SMarek Vasut return ret;
2109db35bb3SMarek Vasut }
2119db35bb3SMarek Vasut
2129db35bb3SMarek Vasut drm_kms_helper_poll_init(drm);
2139db35bb3SMarek Vasut
2149db35bb3SMarek Vasut drm_helper_hpd_irq_event(drm);
2159db35bb3SMarek Vasut
2169db35bb3SMarek Vasut pm_runtime_enable(drm->dev);
2179db35bb3SMarek Vasut
2189db35bb3SMarek Vasut return 0;
2199db35bb3SMarek Vasut }
2209db35bb3SMarek Vasut
lcdif_unload(struct drm_device * drm)2219db35bb3SMarek Vasut static void lcdif_unload(struct drm_device *drm)
2229db35bb3SMarek Vasut {
2239db35bb3SMarek Vasut struct lcdif_drm_private *lcdif = drm->dev_private;
2249db35bb3SMarek Vasut
2259db35bb3SMarek Vasut pm_runtime_get_sync(drm->dev);
2269db35bb3SMarek Vasut
2279db35bb3SMarek Vasut drm_crtc_vblank_off(&lcdif->crtc);
2289db35bb3SMarek Vasut
2299db35bb3SMarek Vasut drm_kms_helper_poll_fini(drm);
2309db35bb3SMarek Vasut drm_mode_config_cleanup(drm);
2319db35bb3SMarek Vasut
2329db35bb3SMarek Vasut pm_runtime_put_sync(drm->dev);
2339db35bb3SMarek Vasut pm_runtime_disable(drm->dev);
2349db35bb3SMarek Vasut
2359db35bb3SMarek Vasut drm->dev_private = NULL;
2369db35bb3SMarek Vasut }
2379db35bb3SMarek Vasut
2384a83c26aSDanilo Krummrich DEFINE_DRM_GEM_DMA_FOPS(fops);
2399db35bb3SMarek Vasut
2409db35bb3SMarek Vasut static const struct drm_driver lcdif_driver = {
2419db35bb3SMarek Vasut .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
2424a83c26aSDanilo Krummrich DRM_GEM_DMA_DRIVER_OPS,
2439db35bb3SMarek Vasut .fops = &fops,
2449db35bb3SMarek Vasut .name = "imx-lcdif",
2459db35bb3SMarek Vasut .desc = "i.MX LCDIF Controller DRM",
2469db35bb3SMarek Vasut .date = "20220417",
2479db35bb3SMarek Vasut .major = 1,
2489db35bb3SMarek Vasut .minor = 0,
2499db35bb3SMarek Vasut };
2509db35bb3SMarek Vasut
2519db35bb3SMarek Vasut static const struct of_device_id lcdif_dt_ids[] = {
2529db35bb3SMarek Vasut { .compatible = "fsl,imx8mp-lcdif" },
25367d0109fSLiu Ying { .compatible = "fsl,imx93-lcdif" },
2549db35bb3SMarek Vasut { /* sentinel */ }
2559db35bb3SMarek Vasut };
2569db35bb3SMarek Vasut MODULE_DEVICE_TABLE(of, lcdif_dt_ids);
2579db35bb3SMarek Vasut
lcdif_probe(struct platform_device * pdev)2589db35bb3SMarek Vasut static int lcdif_probe(struct platform_device *pdev)
2599db35bb3SMarek Vasut {
2609db35bb3SMarek Vasut struct drm_device *drm;
2619db35bb3SMarek Vasut int ret;
2629db35bb3SMarek Vasut
2639db35bb3SMarek Vasut drm = drm_dev_alloc(&lcdif_driver, &pdev->dev);
2649db35bb3SMarek Vasut if (IS_ERR(drm))
2659db35bb3SMarek Vasut return PTR_ERR(drm);
2669db35bb3SMarek Vasut
2679db35bb3SMarek Vasut ret = lcdif_load(drm);
2689db35bb3SMarek Vasut if (ret)
2699db35bb3SMarek Vasut goto err_free;
2709db35bb3SMarek Vasut
2719db35bb3SMarek Vasut ret = drm_dev_register(drm, 0);
2729db35bb3SMarek Vasut if (ret)
2739db35bb3SMarek Vasut goto err_unload;
2749db35bb3SMarek Vasut
27555c7cd97SThomas Zimmermann drm_fbdev_dma_setup(drm, 32);
2769db35bb3SMarek Vasut
2779db35bb3SMarek Vasut return 0;
2789db35bb3SMarek Vasut
2799db35bb3SMarek Vasut err_unload:
2809db35bb3SMarek Vasut lcdif_unload(drm);
2819db35bb3SMarek Vasut err_free:
2829db35bb3SMarek Vasut drm_dev_put(drm);
2839db35bb3SMarek Vasut
2849db35bb3SMarek Vasut return ret;
2859db35bb3SMarek Vasut }
2869db35bb3SMarek Vasut
lcdif_remove(struct platform_device * pdev)287bd296a59SUwe Kleine-König static void lcdif_remove(struct platform_device *pdev)
2889db35bb3SMarek Vasut {
2899db35bb3SMarek Vasut struct drm_device *drm = platform_get_drvdata(pdev);
2909db35bb3SMarek Vasut
2919db35bb3SMarek Vasut drm_dev_unregister(drm);
2929db35bb3SMarek Vasut drm_atomic_helper_shutdown(drm);
2939db35bb3SMarek Vasut lcdif_unload(drm);
2949db35bb3SMarek Vasut drm_dev_put(drm);
2959db35bb3SMarek Vasut }
2969db35bb3SMarek Vasut
lcdif_shutdown(struct platform_device * pdev)2979db35bb3SMarek Vasut static void lcdif_shutdown(struct platform_device *pdev)
2989db35bb3SMarek Vasut {
2999db35bb3SMarek Vasut struct drm_device *drm = platform_get_drvdata(pdev);
3009db35bb3SMarek Vasut
3019db35bb3SMarek Vasut drm_atomic_helper_shutdown(drm);
3029db35bb3SMarek Vasut }
3039db35bb3SMarek Vasut
lcdif_rpm_suspend(struct device * dev)3049db35bb3SMarek Vasut static int __maybe_unused lcdif_rpm_suspend(struct device *dev)
3059db35bb3SMarek Vasut {
3069db35bb3SMarek Vasut struct drm_device *drm = dev_get_drvdata(dev);
3079db35bb3SMarek Vasut struct lcdif_drm_private *lcdif = drm->dev_private;
3089db35bb3SMarek Vasut
3099db35bb3SMarek Vasut /* These clock supply the DISPLAY CLOCK Domain */
3109db35bb3SMarek Vasut clk_disable_unprepare(lcdif->clk);
3119db35bb3SMarek Vasut /* These clock supply the System Bus, AXI, Write Path, LFIFO */
3129db35bb3SMarek Vasut clk_disable_unprepare(lcdif->clk_disp_axi);
3139db35bb3SMarek Vasut /* These clock supply the Control Bus, APB, APBH Ctrl Registers */
3149db35bb3SMarek Vasut clk_disable_unprepare(lcdif->clk_axi);
3159db35bb3SMarek Vasut
3169db35bb3SMarek Vasut return 0;
3179db35bb3SMarek Vasut }
3189db35bb3SMarek Vasut
lcdif_rpm_resume(struct device * dev)3199db35bb3SMarek Vasut static int __maybe_unused lcdif_rpm_resume(struct device *dev)
3209db35bb3SMarek Vasut {
3219db35bb3SMarek Vasut struct drm_device *drm = dev_get_drvdata(dev);
3229db35bb3SMarek Vasut struct lcdif_drm_private *lcdif = drm->dev_private;
3239db35bb3SMarek Vasut
3249db35bb3SMarek Vasut /* These clock supply the Control Bus, APB, APBH Ctrl Registers */
3259db35bb3SMarek Vasut clk_prepare_enable(lcdif->clk_axi);
3269db35bb3SMarek Vasut /* These clock supply the System Bus, AXI, Write Path, LFIFO */
3279db35bb3SMarek Vasut clk_prepare_enable(lcdif->clk_disp_axi);
3289db35bb3SMarek Vasut /* These clock supply the DISPLAY CLOCK Domain */
3299db35bb3SMarek Vasut clk_prepare_enable(lcdif->clk);
3309db35bb3SMarek Vasut
3319db35bb3SMarek Vasut return 0;
3329db35bb3SMarek Vasut }
3339db35bb3SMarek Vasut
lcdif_suspend(struct device * dev)3349db35bb3SMarek Vasut static int __maybe_unused lcdif_suspend(struct device *dev)
3359db35bb3SMarek Vasut {
3369db35bb3SMarek Vasut struct drm_device *drm = dev_get_drvdata(dev);
3379db35bb3SMarek Vasut int ret;
3389db35bb3SMarek Vasut
3399db35bb3SMarek Vasut ret = drm_mode_config_helper_suspend(drm);
3409db35bb3SMarek Vasut if (ret)
3419db35bb3SMarek Vasut return ret;
3429db35bb3SMarek Vasut
343e71399aaSMarek Vasut if (pm_runtime_suspended(dev))
344e71399aaSMarek Vasut return 0;
345e71399aaSMarek Vasut
3469db35bb3SMarek Vasut return lcdif_rpm_suspend(dev);
3479db35bb3SMarek Vasut }
3489db35bb3SMarek Vasut
lcdif_resume(struct device * dev)3499db35bb3SMarek Vasut static int __maybe_unused lcdif_resume(struct device *dev)
3509db35bb3SMarek Vasut {
3519db35bb3SMarek Vasut struct drm_device *drm = dev_get_drvdata(dev);
3529db35bb3SMarek Vasut
353e71399aaSMarek Vasut if (!pm_runtime_suspended(dev))
3549db35bb3SMarek Vasut lcdif_rpm_resume(dev);
3559db35bb3SMarek Vasut
3569db35bb3SMarek Vasut return drm_mode_config_helper_resume(drm);
3579db35bb3SMarek Vasut }
3589db35bb3SMarek Vasut
3599db35bb3SMarek Vasut static const struct dev_pm_ops lcdif_pm_ops = {
3609db35bb3SMarek Vasut SET_SYSTEM_SLEEP_PM_OPS(lcdif_suspend, lcdif_resume)
3619db35bb3SMarek Vasut SET_RUNTIME_PM_OPS(lcdif_rpm_suspend, lcdif_rpm_resume, NULL)
3629db35bb3SMarek Vasut };
3639db35bb3SMarek Vasut
3649db35bb3SMarek Vasut static struct platform_driver lcdif_platform_driver = {
3659db35bb3SMarek Vasut .probe = lcdif_probe,
366bd296a59SUwe Kleine-König .remove_new = lcdif_remove,
3679db35bb3SMarek Vasut .shutdown = lcdif_shutdown,
3689db35bb3SMarek Vasut .driver = {
3699db35bb3SMarek Vasut .name = "imx-lcdif",
3709db35bb3SMarek Vasut .of_match_table = lcdif_dt_ids,
3719db35bb3SMarek Vasut .pm = &lcdif_pm_ops,
3729db35bb3SMarek Vasut },
3739db35bb3SMarek Vasut };
3749db35bb3SMarek Vasut
3759db35bb3SMarek Vasut drm_module_platform_driver(lcdif_platform_driver);
3769db35bb3SMarek Vasut
3779db35bb3SMarek Vasut MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
3789db35bb3SMarek Vasut MODULE_DESCRIPTION("Freescale LCDIF DRM/KMS driver");
3799db35bb3SMarek Vasut MODULE_LICENSE("GPL");
380