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