xref: /openbmc/linux/drivers/gpu/drm/mxsfb/lcdif_drv.c (revision e71399aa)
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