1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Hisilicon Kirin SoCs drm master driver 4 * 5 * Copyright (c) 2016 Linaro Limited. 6 * Copyright (c) 2014-2016 HiSilicon Limited. 7 * 8 * Author: 9 * Xinliang Liu <z.liuxinliang@hisilicon.com> 10 * Xinliang Liu <xinliang.liu@linaro.org> 11 * Xinwei Kong <kong.kongxinwei@hisilicon.com> 12 */ 13 14 #include <linux/component.h> 15 #include <linux/module.h> 16 #include <linux/of.h> 17 #include <linux/of_graph.h> 18 #include <linux/platform_device.h> 19 20 #include <drm/drm_atomic_helper.h> 21 #include <drm/drm_client_setup.h> 22 #include <drm/drm_drv.h> 23 #include <drm/drm_gem_dma_helper.h> 24 #include <drm/drm_gem_framebuffer_helper.h> 25 #include <drm/drm_module.h> 26 #include <drm/drm_of.h> 27 #include <drm/drm_probe_helper.h> 28 #include <drm/drm_vblank.h> 29 30 #include "kirin_drm_drv.h" 31 32 #define KIRIN_MAX_PLANE 2 33 34 struct kirin_drm_private { 35 struct kirin_crtc crtc; 36 struct kirin_plane planes[KIRIN_MAX_PLANE]; 37 void *hw_ctx; 38 }; 39 40 static int kirin_drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 41 struct drm_plane *plane, 42 const struct kirin_drm_data *driver_data) 43 { 44 struct device_node *port; 45 int ret; 46 47 /* set crtc port so that 48 * drm_of_find_possible_crtcs call works 49 */ 50 port = of_get_child_by_name(dev->dev->of_node, "port"); 51 if (!port) { 52 DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node); 53 return -EINVAL; 54 } 55 of_node_put(port); 56 crtc->port = port; 57 58 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 59 driver_data->crtc_funcs, NULL); 60 if (ret) { 61 DRM_ERROR("failed to init crtc.\n"); 62 return ret; 63 } 64 65 drm_crtc_helper_add(crtc, driver_data->crtc_helper_funcs); 66 67 return 0; 68 } 69 70 static int kirin_drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 71 enum drm_plane_type type, 72 const struct kirin_drm_data *data) 73 { 74 int ret = 0; 75 76 ret = drm_universal_plane_init(dev, plane, 1, data->plane_funcs, 77 data->channel_formats, 78 data->channel_formats_cnt, 79 NULL, type, NULL); 80 if (ret) { 81 DRM_ERROR("fail to init plane, ch=%d\n", 0); 82 return ret; 83 } 84 85 drm_plane_helper_add(plane, data->plane_helper_funcs); 86 87 return 0; 88 } 89 90 static void kirin_drm_private_cleanup(struct drm_device *dev) 91 { 92 struct kirin_drm_private *kirin_priv = dev->dev_private; 93 struct kirin_drm_data *data; 94 95 data = (struct kirin_drm_data *)of_device_get_match_data(dev->dev); 96 if (data->cleanup_hw_ctx) 97 data->cleanup_hw_ctx(kirin_priv->hw_ctx); 98 99 devm_kfree(dev->dev, kirin_priv); 100 dev->dev_private = NULL; 101 } 102 103 static int kirin_drm_private_init(struct drm_device *dev, 104 const struct kirin_drm_data *driver_data) 105 { 106 struct platform_device *pdev = to_platform_device(dev->dev); 107 struct kirin_drm_private *kirin_priv; 108 struct drm_plane *prim_plane; 109 enum drm_plane_type type; 110 void *ctx; 111 int ret; 112 u32 ch; 113 114 kirin_priv = devm_kzalloc(dev->dev, sizeof(*kirin_priv), GFP_KERNEL); 115 if (!kirin_priv) { 116 DRM_ERROR("failed to alloc kirin_drm_private\n"); 117 return -ENOMEM; 118 } 119 120 ctx = driver_data->alloc_hw_ctx(pdev, &kirin_priv->crtc.base); 121 if (IS_ERR(ctx)) { 122 DRM_ERROR("failed to initialize kirin_priv hw ctx\n"); 123 return -EINVAL; 124 } 125 kirin_priv->hw_ctx = ctx; 126 127 /* 128 * plane init 129 * TODO: Now only support primary plane, overlay planes 130 * need to do. 131 */ 132 for (ch = 0; ch < driver_data->num_planes; ch++) { 133 if (ch == driver_data->prim_plane) 134 type = DRM_PLANE_TYPE_PRIMARY; 135 else 136 type = DRM_PLANE_TYPE_OVERLAY; 137 ret = kirin_drm_plane_init(dev, &kirin_priv->planes[ch].base, 138 type, driver_data); 139 if (ret) 140 return ret; 141 kirin_priv->planes[ch].ch = ch; 142 kirin_priv->planes[ch].hw_ctx = ctx; 143 } 144 145 /* crtc init */ 146 prim_plane = &kirin_priv->planes[driver_data->prim_plane].base; 147 ret = kirin_drm_crtc_init(dev, &kirin_priv->crtc.base, 148 prim_plane, driver_data); 149 if (ret) 150 return ret; 151 kirin_priv->crtc.hw_ctx = ctx; 152 dev->dev_private = kirin_priv; 153 154 return 0; 155 } 156 157 static int kirin_drm_kms_init(struct drm_device *dev, 158 const struct kirin_drm_data *driver_data) 159 { 160 int ret; 161 162 /* dev->mode_config initialization */ 163 drm_mode_config_init(dev); 164 dev->mode_config.min_width = 0; 165 dev->mode_config.min_height = 0; 166 dev->mode_config.max_width = driver_data->config_max_width; 167 dev->mode_config.max_height = driver_data->config_max_width; 168 dev->mode_config.funcs = driver_data->mode_config_funcs; 169 170 /* display controller init */ 171 ret = kirin_drm_private_init(dev, driver_data); 172 if (ret) 173 goto err_mode_config_cleanup; 174 175 /* bind and init sub drivers */ 176 ret = component_bind_all(dev->dev, dev); 177 if (ret) { 178 DRM_ERROR("failed to bind all component.\n"); 179 goto err_private_cleanup; 180 } 181 182 /* vblank init */ 183 ret = drm_vblank_init(dev, dev->mode_config.num_crtc); 184 if (ret) { 185 DRM_ERROR("failed to initialize vblank.\n"); 186 goto err_unbind_all; 187 } 188 189 /* reset all the states of crtc/plane/encoder/connector */ 190 drm_mode_config_reset(dev); 191 192 /* init kms poll for handling hpd */ 193 drm_kms_helper_poll_init(dev); 194 195 return 0; 196 197 err_unbind_all: 198 component_unbind_all(dev->dev, dev); 199 err_private_cleanup: 200 kirin_drm_private_cleanup(dev); 201 err_mode_config_cleanup: 202 drm_mode_config_cleanup(dev); 203 return ret; 204 } 205 206 static int kirin_drm_kms_cleanup(struct drm_device *dev) 207 { 208 drm_kms_helper_poll_fini(dev); 209 drm_atomic_helper_shutdown(dev); 210 kirin_drm_private_cleanup(dev); 211 drm_mode_config_cleanup(dev); 212 213 return 0; 214 } 215 216 static int kirin_drm_bind(struct device *dev) 217 { 218 struct kirin_drm_data *driver_data; 219 struct drm_device *drm_dev; 220 int ret; 221 222 driver_data = (struct kirin_drm_data *)of_device_get_match_data(dev); 223 if (!driver_data) 224 return -EINVAL; 225 226 drm_dev = drm_dev_alloc(driver_data->driver, dev); 227 if (IS_ERR(drm_dev)) 228 return PTR_ERR(drm_dev); 229 dev_set_drvdata(dev, drm_dev); 230 231 /* display controller init */ 232 ret = kirin_drm_kms_init(drm_dev, driver_data); 233 if (ret) 234 goto err_drm_dev_put; 235 236 ret = drm_dev_register(drm_dev, 0); 237 if (ret) 238 goto err_kms_cleanup; 239 240 drm_client_setup(drm_dev, NULL); 241 242 return 0; 243 244 err_kms_cleanup: 245 kirin_drm_kms_cleanup(drm_dev); 246 err_drm_dev_put: 247 drm_dev_put(drm_dev); 248 dev_set_drvdata(dev, NULL); 249 250 return ret; 251 } 252 253 static void kirin_drm_unbind(struct device *dev) 254 { 255 struct drm_device *drm_dev = dev_get_drvdata(dev); 256 257 drm_dev_unregister(drm_dev); 258 kirin_drm_kms_cleanup(drm_dev); 259 drm_dev_put(drm_dev); 260 dev_set_drvdata(dev, NULL); 261 } 262 263 static const struct component_master_ops kirin_drm_ops = { 264 .bind = kirin_drm_bind, 265 .unbind = kirin_drm_unbind, 266 }; 267 268 static int kirin_drm_platform_probe(struct platform_device *pdev) 269 { 270 struct device *dev = &pdev->dev; 271 struct device_node *np = dev->of_node; 272 struct component_match *match = NULL; 273 struct device_node *remote; 274 275 remote = of_graph_get_remote_node(np, 0, 0); 276 if (!remote) 277 return -ENODEV; 278 279 drm_of_component_match_add(dev, &match, component_compare_of, remote); 280 of_node_put(remote); 281 282 return component_master_add_with_match(dev, &kirin_drm_ops, match); 283 } 284 285 static void kirin_drm_platform_remove(struct platform_device *pdev) 286 { 287 component_master_del(&pdev->dev, &kirin_drm_ops); 288 } 289 290 static void kirin_drm_platform_shutdown(struct platform_device *pdev) 291 { 292 drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); 293 } 294 295 static const struct of_device_id kirin_drm_dt_ids[] = { 296 { .compatible = "hisilicon,hi6220-ade", 297 .data = &ade_driver_data, 298 }, 299 { /* end node */ }, 300 }; 301 MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids); 302 303 static struct platform_driver kirin_drm_platform_driver = { 304 .probe = kirin_drm_platform_probe, 305 .remove_new = kirin_drm_platform_remove, 306 .shutdown = kirin_drm_platform_shutdown, 307 .driver = { 308 .name = "kirin-drm", 309 .of_match_table = kirin_drm_dt_ids, 310 }, 311 }; 312 313 drm_module_platform_driver(kirin_drm_platform_driver); 314 315 MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>"); 316 MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>"); 317 MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); 318 MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver"); 319 MODULE_LICENSE("GPL v2"); 320