1 /* 2 * Copyright (C) STMicroelectronics SA 2014 3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 4 * License terms: GNU General Public License (GPL), version 2 5 */ 6 7 #include <drm/drmP.h> 8 9 #include <linux/component.h> 10 #include <linux/debugfs.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/of_platform.h> 14 15 #include <drm/drm_atomic.h> 16 #include <drm/drm_atomic_helper.h> 17 #include <drm/drm_crtc_helper.h> 18 #include <drm/drm_gem_cma_helper.h> 19 #include <drm/drm_gem_framebuffer_helper.h> 20 #include <drm/drm_fb_cma_helper.h> 21 #include <drm/drm_of.h> 22 23 #include "sti_crtc.h" 24 #include "sti_drv.h" 25 #include "sti_plane.h" 26 27 #define DRIVER_NAME "sti" 28 #define DRIVER_DESC "STMicroelectronics SoC DRM" 29 #define DRIVER_DATE "20140601" 30 #define DRIVER_MAJOR 1 31 #define DRIVER_MINOR 0 32 33 #define STI_MAX_FB_HEIGHT 4096 34 #define STI_MAX_FB_WIDTH 4096 35 36 static int sti_drm_fps_get(void *data, u64 *val) 37 { 38 struct drm_device *drm_dev = data; 39 struct drm_plane *p; 40 unsigned int i = 0; 41 42 *val = 0; 43 list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { 44 struct sti_plane *plane = to_sti_plane(p); 45 46 *val |= plane->fps_info.output << i; 47 i++; 48 } 49 50 return 0; 51 } 52 53 static int sti_drm_fps_set(void *data, u64 val) 54 { 55 struct drm_device *drm_dev = data; 56 struct drm_plane *p; 57 unsigned int i = 0; 58 59 list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { 60 struct sti_plane *plane = to_sti_plane(p); 61 62 memset(&plane->fps_info, 0, sizeof(plane->fps_info)); 63 plane->fps_info.output = (val >> i) & 1; 64 65 i++; 66 } 67 68 return 0; 69 } 70 71 DEFINE_SIMPLE_ATTRIBUTE(sti_drm_fps_fops, 72 sti_drm_fps_get, sti_drm_fps_set, "%llu\n"); 73 74 static int sti_drm_fps_dbg_show(struct seq_file *s, void *data) 75 { 76 struct drm_info_node *node = s->private; 77 struct drm_device *dev = node->minor->dev; 78 struct drm_plane *p; 79 80 list_for_each_entry(p, &dev->mode_config.plane_list, head) { 81 struct sti_plane *plane = to_sti_plane(p); 82 83 seq_printf(s, "%s%s\n", 84 plane->fps_info.fps_str, 85 plane->fps_info.fips_str); 86 } 87 88 return 0; 89 } 90 91 static struct drm_info_list sti_drm_dbg_list[] = { 92 {"fps_get", sti_drm_fps_dbg_show, 0}, 93 }; 94 95 static int sti_drm_dbg_init(struct drm_minor *minor) 96 { 97 struct dentry *dentry; 98 int ret; 99 100 ret = drm_debugfs_create_files(sti_drm_dbg_list, 101 ARRAY_SIZE(sti_drm_dbg_list), 102 minor->debugfs_root, minor); 103 if (ret) 104 goto err; 105 106 dentry = debugfs_create_file("fps_show", S_IRUGO | S_IWUSR, 107 minor->debugfs_root, minor->dev, 108 &sti_drm_fps_fops); 109 if (!dentry) { 110 ret = -ENOMEM; 111 goto err; 112 } 113 114 DRM_INFO("%s: debugfs installed\n", DRIVER_NAME); 115 return 0; 116 err: 117 DRM_ERROR("%s: cannot install debugfs\n", DRIVER_NAME); 118 return ret; 119 } 120 121 static int sti_atomic_check(struct drm_device *dev, 122 struct drm_atomic_state *state) 123 { 124 int ret; 125 126 ret = drm_atomic_helper_check_modeset(dev, state); 127 if (ret) 128 return ret; 129 130 ret = drm_atomic_normalize_zpos(dev, state); 131 if (ret) 132 return ret; 133 134 ret = drm_atomic_helper_check_planes(dev, state); 135 if (ret) 136 return ret; 137 138 return ret; 139 } 140 141 static void sti_output_poll_changed(struct drm_device *ddev) 142 { 143 struct sti_private *private = ddev->dev_private; 144 145 drm_fbdev_cma_hotplug_event(private->fbdev); 146 } 147 148 static const struct drm_mode_config_funcs sti_mode_config_funcs = { 149 .fb_create = drm_gem_fb_create, 150 .output_poll_changed = sti_output_poll_changed, 151 .atomic_check = sti_atomic_check, 152 .atomic_commit = drm_atomic_helper_commit, 153 }; 154 155 static void sti_mode_config_init(struct drm_device *dev) 156 { 157 dev->mode_config.min_width = 0; 158 dev->mode_config.min_height = 0; 159 160 /* 161 * set max width and height as default value. 162 * this value would be used to check framebuffer size limitation 163 * at drm_mode_addfb(). 164 */ 165 dev->mode_config.max_width = STI_MAX_FB_WIDTH; 166 dev->mode_config.max_height = STI_MAX_FB_HEIGHT; 167 168 dev->mode_config.funcs = &sti_mode_config_funcs; 169 } 170 171 DEFINE_DRM_GEM_CMA_FOPS(sti_driver_fops); 172 173 static struct drm_driver sti_driver = { 174 .driver_features = DRIVER_MODESET | 175 DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, 176 .gem_free_object_unlocked = drm_gem_cma_free_object, 177 .gem_vm_ops = &drm_gem_cma_vm_ops, 178 .dumb_create = drm_gem_cma_dumb_create, 179 .fops = &sti_driver_fops, 180 181 .enable_vblank = sti_crtc_enable_vblank, 182 .disable_vblank = sti_crtc_disable_vblank, 183 184 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 185 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 186 .gem_prime_export = drm_gem_prime_export, 187 .gem_prime_import = drm_gem_prime_import, 188 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 189 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 190 .gem_prime_vmap = drm_gem_cma_prime_vmap, 191 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 192 .gem_prime_mmap = drm_gem_cma_prime_mmap, 193 194 .debugfs_init = sti_drm_dbg_init, 195 196 .name = DRIVER_NAME, 197 .desc = DRIVER_DESC, 198 .date = DRIVER_DATE, 199 .major = DRIVER_MAJOR, 200 .minor = DRIVER_MINOR, 201 }; 202 203 static int compare_of(struct device *dev, void *data) 204 { 205 return dev->of_node == data; 206 } 207 208 static int sti_init(struct drm_device *ddev) 209 { 210 struct sti_private *private; 211 212 private = kzalloc(sizeof(*private), GFP_KERNEL); 213 if (!private) 214 return -ENOMEM; 215 216 ddev->dev_private = (void *)private; 217 dev_set_drvdata(ddev->dev, ddev); 218 private->drm_dev = ddev; 219 220 drm_mode_config_init(ddev); 221 222 sti_mode_config_init(ddev); 223 224 drm_kms_helper_poll_init(ddev); 225 226 return 0; 227 } 228 229 static void sti_cleanup(struct drm_device *ddev) 230 { 231 struct sti_private *private = ddev->dev_private; 232 233 if (private->fbdev) { 234 drm_fbdev_cma_fini(private->fbdev); 235 private->fbdev = NULL; 236 } 237 238 drm_kms_helper_poll_fini(ddev); 239 component_unbind_all(ddev->dev, ddev); 240 kfree(private); 241 ddev->dev_private = NULL; 242 } 243 244 static int sti_bind(struct device *dev) 245 { 246 struct drm_device *ddev; 247 struct sti_private *private; 248 struct drm_fbdev_cma *fbdev; 249 int ret; 250 251 ddev = drm_dev_alloc(&sti_driver, dev); 252 if (IS_ERR(ddev)) 253 return PTR_ERR(ddev); 254 255 ret = sti_init(ddev); 256 if (ret) 257 goto err_drm_dev_unref; 258 259 ret = component_bind_all(ddev->dev, ddev); 260 if (ret) 261 goto err_cleanup; 262 263 ret = drm_dev_register(ddev, 0); 264 if (ret) 265 goto err_register; 266 267 drm_mode_config_reset(ddev); 268 269 private = ddev->dev_private; 270 if (ddev->mode_config.num_connector) { 271 fbdev = drm_fbdev_cma_init(ddev, 32, 272 ddev->mode_config.num_connector); 273 if (IS_ERR(fbdev)) { 274 DRM_DEBUG_DRIVER("Warning: fails to create fbdev\n"); 275 fbdev = NULL; 276 } 277 private->fbdev = fbdev; 278 } 279 280 return 0; 281 282 err_register: 283 drm_mode_config_cleanup(ddev); 284 err_cleanup: 285 sti_cleanup(ddev); 286 err_drm_dev_unref: 287 drm_dev_unref(ddev); 288 return ret; 289 } 290 291 static void sti_unbind(struct device *dev) 292 { 293 struct drm_device *ddev = dev_get_drvdata(dev); 294 295 drm_dev_unregister(ddev); 296 sti_cleanup(ddev); 297 drm_dev_unref(ddev); 298 } 299 300 static const struct component_master_ops sti_ops = { 301 .bind = sti_bind, 302 .unbind = sti_unbind, 303 }; 304 305 static int sti_platform_probe(struct platform_device *pdev) 306 { 307 struct device *dev = &pdev->dev; 308 struct device_node *node = dev->of_node; 309 struct device_node *child_np; 310 struct component_match *match = NULL; 311 312 dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 313 314 devm_of_platform_populate(dev); 315 316 child_np = of_get_next_available_child(node, NULL); 317 318 while (child_np) { 319 drm_of_component_match_add(dev, &match, compare_of, 320 child_np); 321 child_np = of_get_next_available_child(node, child_np); 322 } 323 324 return component_master_add_with_match(dev, &sti_ops, match); 325 } 326 327 static int sti_platform_remove(struct platform_device *pdev) 328 { 329 component_master_del(&pdev->dev, &sti_ops); 330 331 return 0; 332 } 333 334 static const struct of_device_id sti_dt_ids[] = { 335 { .compatible = "st,sti-display-subsystem", }, 336 { /* end node */ }, 337 }; 338 MODULE_DEVICE_TABLE(of, sti_dt_ids); 339 340 static struct platform_driver sti_platform_driver = { 341 .probe = sti_platform_probe, 342 .remove = sti_platform_remove, 343 .driver = { 344 .name = DRIVER_NAME, 345 .of_match_table = sti_dt_ids, 346 }, 347 }; 348 349 static struct platform_driver * const drivers[] = { 350 &sti_tvout_driver, 351 &sti_hqvdp_driver, 352 &sti_hdmi_driver, 353 &sti_hda_driver, 354 &sti_dvo_driver, 355 &sti_vtg_driver, 356 &sti_compositor_driver, 357 &sti_platform_driver, 358 }; 359 360 static int sti_drm_init(void) 361 { 362 return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); 363 } 364 module_init(sti_drm_init); 365 366 static void sti_drm_exit(void) 367 { 368 platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); 369 } 370 module_exit(sti_drm_exit); 371 372 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 373 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 374 MODULE_LICENSE("GPL"); 375