Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.19-rc5 293 lines 6.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2024 NXP 4 */ 5 6#include <linux/clk.h> 7#include <linux/component.h> 8#include <linux/device.h> 9#include <linux/dma-mapping.h> 10#include <linux/mod_devicetable.h> 11#include <linux/module.h> 12#include <linux/of.h> 13#include <linux/of_platform.h> 14#include <linux/platform_device.h> 15#include <linux/pm.h> 16#include <linux/pm_runtime.h> 17 18#include <drm/clients/drm_client_setup.h> 19#include <drm/drm_atomic_helper.h> 20#include <drm/drm_drv.h> 21#include <drm/drm_fbdev_dma.h> 22#include <drm/drm_fourcc.h> 23#include <drm/drm_gem_dma_helper.h> 24#include <drm/drm_managed.h> 25#include <drm/drm_modeset_helper.h> 26#include <drm/drm_of.h> 27 28#include "dc-de.h" 29#include "dc-drv.h" 30#include "dc-pe.h" 31 32struct dc_priv { 33 struct drm_device *drm; 34 struct clk *clk_cfg; 35}; 36 37DEFINE_DRM_GEM_DMA_FOPS(dc_drm_driver_fops); 38 39static struct drm_driver dc_drm_driver = { 40 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, 41 DRM_GEM_DMA_DRIVER_OPS, 42 DRM_FBDEV_DMA_DRIVER_OPS, 43 .fops = &dc_drm_driver_fops, 44 .name = "imx8-dc", 45 .desc = "i.MX8 DC DRM graphics", 46 .major = 1, 47 .minor = 0, 48 .patchlevel = 0, 49}; 50 51static void 52dc_add_components(struct device *dev, struct component_match **matchptr) 53{ 54 struct device_node *child, *grandchild; 55 56 for_each_available_child_of_node(dev->of_node, child) { 57 /* The interrupt controller is not a component. */ 58 if (of_device_is_compatible(child, "fsl,imx8qxp-dc-intc")) 59 continue; 60 61 drm_of_component_match_add(dev, matchptr, component_compare_of, 62 child); 63 64 for_each_available_child_of_node(child, grandchild) 65 drm_of_component_match_add(dev, matchptr, 66 component_compare_of, 67 grandchild); 68 } 69} 70 71static int dc_drm_component_bind_all(struct dc_drm_device *dc_drm) 72{ 73 struct drm_device *drm = &dc_drm->base; 74 int ret; 75 76 ret = component_bind_all(drm->dev, dc_drm); 77 if (ret) 78 return ret; 79 80 dc_de_post_bind(dc_drm); 81 dc_pe_post_bind(dc_drm); 82 83 return 0; 84} 85 86static void dc_drm_component_unbind_all(void *ptr) 87{ 88 struct dc_drm_device *dc_drm = ptr; 89 struct drm_device *drm = &dc_drm->base; 90 91 component_unbind_all(drm->dev, dc_drm); 92} 93 94static int dc_drm_bind(struct device *dev) 95{ 96 struct dc_priv *priv = dev_get_drvdata(dev); 97 struct dc_drm_device *dc_drm; 98 struct drm_device *drm; 99 int ret; 100 101 dc_drm = devm_drm_dev_alloc(dev, &dc_drm_driver, struct dc_drm_device, 102 base); 103 if (IS_ERR(dc_drm)) 104 return PTR_ERR(dc_drm); 105 106 drm = &dc_drm->base; 107 108 ret = dc_drm_component_bind_all(dc_drm); 109 if (ret) 110 return ret; 111 112 ret = devm_add_action_or_reset(dev, dc_drm_component_unbind_all, 113 dc_drm); 114 if (ret) 115 return ret; 116 117 ret = dc_kms_init(dc_drm); 118 if (ret) 119 return ret; 120 121 ret = drm_dev_register(drm, 0); 122 if (ret) { 123 dev_err(dev, "failed to register drm device: %d\n", ret); 124 goto err; 125 } 126 127 drm_client_setup_with_fourcc(drm, DRM_FORMAT_XRGB8888); 128 129 priv->drm = drm; 130 131 return 0; 132 133err: 134 dc_kms_uninit(dc_drm); 135 136 return ret; 137} 138 139static void dc_drm_unbind(struct device *dev) 140{ 141 struct dc_priv *priv = dev_get_drvdata(dev); 142 struct dc_drm_device *dc_drm = to_dc_drm_device(priv->drm); 143 struct drm_device *drm = &dc_drm->base; 144 145 priv->drm = NULL; 146 drm_dev_unplug(drm); 147 dc_kms_uninit(dc_drm); 148 drm_atomic_helper_shutdown(drm); 149} 150 151static const struct component_master_ops dc_drm_ops = { 152 .bind = dc_drm_bind, 153 .unbind = dc_drm_unbind, 154}; 155 156static int dc_probe(struct platform_device *pdev) 157{ 158 struct component_match *match = NULL; 159 struct dc_priv *priv; 160 int ret; 161 162 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 163 if (!priv) 164 return -ENOMEM; 165 166 priv->clk_cfg = devm_clk_get(&pdev->dev, NULL); 167 if (IS_ERR(priv->clk_cfg)) 168 return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk_cfg), 169 "failed to get cfg clock\n"); 170 171 dev_set_drvdata(&pdev->dev, priv); 172 173 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 174 if (ret) 175 return ret; 176 177 ret = devm_pm_runtime_enable(&pdev->dev); 178 if (ret) 179 return ret; 180 181 ret = devm_of_platform_populate(&pdev->dev); 182 if (ret) 183 return ret; 184 185 dc_add_components(&pdev->dev, &match); 186 187 ret = component_master_add_with_match(&pdev->dev, &dc_drm_ops, match); 188 if (ret) 189 return dev_err_probe(&pdev->dev, ret, 190 "failed to add component master\n"); 191 192 return 0; 193} 194 195static void dc_remove(struct platform_device *pdev) 196{ 197 component_master_del(&pdev->dev, &dc_drm_ops); 198} 199 200static int dc_runtime_suspend(struct device *dev) 201{ 202 struct dc_priv *priv = dev_get_drvdata(dev); 203 204 clk_disable_unprepare(priv->clk_cfg); 205 206 return 0; 207} 208 209static int dc_runtime_resume(struct device *dev) 210{ 211 struct dc_priv *priv = dev_get_drvdata(dev); 212 int ret; 213 214 ret = clk_prepare_enable(priv->clk_cfg); 215 if (ret) 216 dev_err(dev, "failed to enable cfg clock: %d\n", ret); 217 218 return ret; 219} 220 221static int dc_suspend(struct device *dev) 222{ 223 struct dc_priv *priv = dev_get_drvdata(dev); 224 225 return drm_mode_config_helper_suspend(priv->drm); 226} 227 228static int dc_resume(struct device *dev) 229{ 230 struct dc_priv *priv = dev_get_drvdata(dev); 231 232 return drm_mode_config_helper_resume(priv->drm); 233} 234 235static void dc_shutdown(struct platform_device *pdev) 236{ 237 struct dc_priv *priv = dev_get_drvdata(&pdev->dev); 238 239 drm_atomic_helper_shutdown(priv->drm); 240} 241 242static const struct dev_pm_ops dc_pm_ops = { 243 RUNTIME_PM_OPS(dc_runtime_suspend, dc_runtime_resume, NULL) 244 SYSTEM_SLEEP_PM_OPS(dc_suspend, dc_resume) 245}; 246 247static const struct of_device_id dc_dt_ids[] = { 248 { .compatible = "fsl,imx8qxp-dc", }, 249 { /* sentinel */ } 250}; 251MODULE_DEVICE_TABLE(of, dc_dt_ids); 252 253static struct platform_driver dc_driver = { 254 .probe = dc_probe, 255 .remove = dc_remove, 256 .shutdown = dc_shutdown, 257 .driver = { 258 .name = "imx8-dc", 259 .of_match_table = dc_dt_ids, 260 .pm = pm_sleep_ptr(&dc_pm_ops), 261 }, 262}; 263 264static struct platform_driver * const dc_drivers[] = { 265 &dc_cf_driver, 266 &dc_de_driver, 267 &dc_ed_driver, 268 &dc_fg_driver, 269 &dc_fl_driver, 270 &dc_fw_driver, 271 &dc_ic_driver, 272 &dc_lb_driver, 273 &dc_pe_driver, 274 &dc_tc_driver, 275 &dc_driver, 276}; 277 278static int __init dc_drm_init(void) 279{ 280 return platform_register_drivers(dc_drivers, ARRAY_SIZE(dc_drivers)); 281} 282 283static void __exit dc_drm_exit(void) 284{ 285 platform_unregister_drivers(dc_drivers, ARRAY_SIZE(dc_drivers)); 286} 287 288module_init(dc_drm_init); 289module_exit(dc_drm_exit); 290 291MODULE_DESCRIPTION("i.MX8 Display Controller DRM Driver"); 292MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); 293MODULE_LICENSE("GPL");