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_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 /* with irq_enabled = true, we can use the vblank feature. */ 189 dev->irq_enabled = true; 190 191 /* reset all the states of crtc/plane/encoder/connector */ 192 drm_mode_config_reset(dev); 193 194 /* init kms poll for handling hpd */ 195 drm_kms_helper_poll_init(dev); 196 197 return 0; 198 199 err_unbind_all: 200 component_unbind_all(dev->dev, dev); 201 err_private_cleanup: 202 kirin_drm_private_cleanup(dev); 203 err_mode_config_cleanup: 204 drm_mode_config_cleanup(dev); 205 return ret; 206 } 207 208 static int compare_of(struct device *dev, void *data) 209 { 210 return dev->of_node == data; 211 } 212 213 static int kirin_drm_kms_cleanup(struct drm_device *dev) 214 { 215 drm_kms_helper_poll_fini(dev); 216 kirin_drm_private_cleanup(dev); 217 drm_mode_config_cleanup(dev); 218 219 return 0; 220 } 221 222 static int kirin_drm_bind(struct device *dev) 223 { 224 struct kirin_drm_data *driver_data; 225 struct drm_device *drm_dev; 226 int ret; 227 228 driver_data = (struct kirin_drm_data *)of_device_get_match_data(dev); 229 if (!driver_data) 230 return -EINVAL; 231 232 drm_dev = drm_dev_alloc(driver_data->driver, dev); 233 if (IS_ERR(drm_dev)) 234 return PTR_ERR(drm_dev); 235 dev_set_drvdata(dev, drm_dev); 236 237 /* display controller init */ 238 ret = kirin_drm_kms_init(drm_dev, driver_data); 239 if (ret) 240 goto err_drm_dev_put; 241 242 ret = drm_dev_register(drm_dev, 0); 243 if (ret) 244 goto err_kms_cleanup; 245 246 drm_fbdev_generic_setup(drm_dev, 32); 247 248 return 0; 249 250 err_kms_cleanup: 251 kirin_drm_kms_cleanup(drm_dev); 252 err_drm_dev_put: 253 drm_dev_put(drm_dev); 254 255 return ret; 256 } 257 258 static void kirin_drm_unbind(struct device *dev) 259 { 260 struct drm_device *drm_dev = dev_get_drvdata(dev); 261 262 drm_dev_unregister(drm_dev); 263 kirin_drm_kms_cleanup(drm_dev); 264 drm_dev_put(drm_dev); 265 } 266 267 static const struct component_master_ops kirin_drm_ops = { 268 .bind = kirin_drm_bind, 269 .unbind = kirin_drm_unbind, 270 }; 271 272 static int kirin_drm_platform_probe(struct platform_device *pdev) 273 { 274 struct device *dev = &pdev->dev; 275 struct device_node *np = dev->of_node; 276 struct component_match *match = NULL; 277 struct device_node *remote; 278 279 remote = of_graph_get_remote_node(np, 0, 0); 280 if (!remote) 281 return -ENODEV; 282 283 drm_of_component_match_add(dev, &match, compare_of, remote); 284 of_node_put(remote); 285 286 return component_master_add_with_match(dev, &kirin_drm_ops, match); 287 } 288 289 static int kirin_drm_platform_remove(struct platform_device *pdev) 290 { 291 component_master_del(&pdev->dev, &kirin_drm_ops); 292 return 0; 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 = kirin_drm_platform_remove, 306 .driver = { 307 .name = "kirin-drm", 308 .of_match_table = kirin_drm_dt_ids, 309 }, 310 }; 311 312 module_platform_driver(kirin_drm_platform_driver); 313 314 MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>"); 315 MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>"); 316 MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); 317 MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver"); 318 MODULE_LICENSE("GPL v2"); 319