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 v4.15-rc9 255 lines 6.5 kB view raw
1/* 2 * ARC PGU DRM driver. 3 * 4 * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16 17#include <linux/clk.h> 18#include <drm/drm_crtc_helper.h> 19#include <drm/drm_fb_cma_helper.h> 20#include <drm/drm_gem_cma_helper.h> 21#include <drm/drm_gem_framebuffer_helper.h> 22#include <drm/drm_atomic_helper.h> 23#include <linux/of_reserved_mem.h> 24 25#include "arcpgu.h" 26#include "arcpgu_regs.h" 27 28static void arcpgu_fb_output_poll_changed(struct drm_device *dev) 29{ 30 struct arcpgu_drm_private *arcpgu = dev->dev_private; 31 32 drm_fbdev_cma_hotplug_event(arcpgu->fbdev); 33} 34 35static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { 36 .fb_create = drm_gem_fb_create, 37 .output_poll_changed = arcpgu_fb_output_poll_changed, 38 .atomic_check = drm_atomic_helper_check, 39 .atomic_commit = drm_atomic_helper_commit, 40}; 41 42static void arcpgu_setup_mode_config(struct drm_device *drm) 43{ 44 drm_mode_config_init(drm); 45 drm->mode_config.min_width = 0; 46 drm->mode_config.min_height = 0; 47 drm->mode_config.max_width = 1920; 48 drm->mode_config.max_height = 1080; 49 drm->mode_config.funcs = &arcpgu_drm_modecfg_funcs; 50} 51 52DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops); 53 54static void arcpgu_lastclose(struct drm_device *drm) 55{ 56 struct arcpgu_drm_private *arcpgu = drm->dev_private; 57 58 drm_fbdev_cma_restore_mode(arcpgu->fbdev); 59} 60 61static int arcpgu_load(struct drm_device *drm) 62{ 63 struct platform_device *pdev = to_platform_device(drm->dev); 64 struct arcpgu_drm_private *arcpgu; 65 struct device_node *encoder_node; 66 struct resource *res; 67 int ret; 68 69 arcpgu = devm_kzalloc(&pdev->dev, sizeof(*arcpgu), GFP_KERNEL); 70 if (arcpgu == NULL) 71 return -ENOMEM; 72 73 drm->dev_private = arcpgu; 74 75 arcpgu->clk = devm_clk_get(drm->dev, "pxlclk"); 76 if (IS_ERR(arcpgu->clk)) 77 return PTR_ERR(arcpgu->clk); 78 79 arcpgu_setup_mode_config(drm); 80 81 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 82 arcpgu->regs = devm_ioremap_resource(&pdev->dev, res); 83 if (IS_ERR(arcpgu->regs)) 84 return PTR_ERR(arcpgu->regs); 85 86 dev_info(drm->dev, "arc_pgu ID: 0x%x\n", 87 arc_pgu_read(arcpgu, ARCPGU_REG_ID)); 88 89 /* Get the optional framebuffer memory resource */ 90 ret = of_reserved_mem_device_init(drm->dev); 91 if (ret && ret != -ENODEV) 92 return ret; 93 94 if (dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32))) 95 return -ENODEV; 96 97 if (arc_pgu_setup_crtc(drm) < 0) 98 return -ENODEV; 99 100 /* find the encoder node and initialize it */ 101 encoder_node = of_parse_phandle(drm->dev->of_node, "encoder-slave", 0); 102 if (encoder_node) { 103 ret = arcpgu_drm_hdmi_init(drm, encoder_node); 104 of_node_put(encoder_node); 105 if (ret < 0) 106 return ret; 107 } else { 108 ret = arcpgu_drm_sim_init(drm, NULL); 109 if (ret < 0) 110 return ret; 111 } 112 113 drm_mode_config_reset(drm); 114 drm_kms_helper_poll_init(drm); 115 116 arcpgu->fbdev = drm_fbdev_cma_init(drm, 16, 117 drm->mode_config.num_connector); 118 if (IS_ERR(arcpgu->fbdev)) { 119 ret = PTR_ERR(arcpgu->fbdev); 120 arcpgu->fbdev = NULL; 121 return -ENODEV; 122 } 123 124 platform_set_drvdata(pdev, drm); 125 return 0; 126} 127 128static int arcpgu_unload(struct drm_device *drm) 129{ 130 struct arcpgu_drm_private *arcpgu = drm->dev_private; 131 132 if (arcpgu->fbdev) { 133 drm_fbdev_cma_fini(arcpgu->fbdev); 134 arcpgu->fbdev = NULL; 135 } 136 drm_kms_helper_poll_fini(drm); 137 drm_mode_config_cleanup(drm); 138 139 return 0; 140} 141 142#ifdef CONFIG_DEBUG_FS 143static int arcpgu_show_pxlclock(struct seq_file *m, void *arg) 144{ 145 struct drm_info_node *node = (struct drm_info_node *)m->private; 146 struct drm_device *drm = node->minor->dev; 147 struct arcpgu_drm_private *arcpgu = drm->dev_private; 148 unsigned long clkrate = clk_get_rate(arcpgu->clk); 149 unsigned long mode_clock = arcpgu->crtc.mode.crtc_clock * 1000; 150 151 seq_printf(m, "hw : %lu\n", clkrate); 152 seq_printf(m, "mode: %lu\n", mode_clock); 153 return 0; 154} 155 156static struct drm_info_list arcpgu_debugfs_list[] = { 157 { "clocks", arcpgu_show_pxlclock, 0 }, 158 { "fb", drm_fb_cma_debugfs_show, 0 }, 159}; 160 161static int arcpgu_debugfs_init(struct drm_minor *minor) 162{ 163 return drm_debugfs_create_files(arcpgu_debugfs_list, 164 ARRAY_SIZE(arcpgu_debugfs_list), minor->debugfs_root, minor); 165} 166#endif 167 168static struct drm_driver arcpgu_drm_driver = { 169 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | 170 DRIVER_ATOMIC, 171 .lastclose = arcpgu_lastclose, 172 .name = "arcpgu", 173 .desc = "ARC PGU Controller", 174 .date = "20160219", 175 .major = 1, 176 .minor = 0, 177 .patchlevel = 0, 178 .fops = &arcpgu_drm_ops, 179 .dumb_create = drm_gem_cma_dumb_create, 180 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 181 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 182 .gem_free_object_unlocked = drm_gem_cma_free_object, 183 .gem_vm_ops = &drm_gem_cma_vm_ops, 184 .gem_prime_export = drm_gem_prime_export, 185 .gem_prime_import = drm_gem_prime_import, 186 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 187 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 188 .gem_prime_vmap = drm_gem_cma_prime_vmap, 189 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 190 .gem_prime_mmap = drm_gem_cma_prime_mmap, 191#ifdef CONFIG_DEBUG_FS 192 .debugfs_init = arcpgu_debugfs_init, 193#endif 194}; 195 196static int arcpgu_probe(struct platform_device *pdev) 197{ 198 struct drm_device *drm; 199 int ret; 200 201 drm = drm_dev_alloc(&arcpgu_drm_driver, &pdev->dev); 202 if (IS_ERR(drm)) 203 return PTR_ERR(drm); 204 205 ret = arcpgu_load(drm); 206 if (ret) 207 goto err_unref; 208 209 ret = drm_dev_register(drm, 0); 210 if (ret) 211 goto err_unload; 212 213 return 0; 214 215err_unload: 216 arcpgu_unload(drm); 217 218err_unref: 219 drm_dev_unref(drm); 220 221 return ret; 222} 223 224static int arcpgu_remove(struct platform_device *pdev) 225{ 226 struct drm_device *drm = platform_get_drvdata(pdev); 227 228 drm_dev_unregister(drm); 229 arcpgu_unload(drm); 230 drm_dev_unref(drm); 231 232 return 0; 233} 234 235static const struct of_device_id arcpgu_of_table[] = { 236 {.compatible = "snps,arcpgu"}, 237 {} 238}; 239 240MODULE_DEVICE_TABLE(of, arcpgu_of_table); 241 242static struct platform_driver arcpgu_platform_driver = { 243 .probe = arcpgu_probe, 244 .remove = arcpgu_remove, 245 .driver = { 246 .name = "arcpgu", 247 .of_match_table = arcpgu_of_table, 248 }, 249}; 250 251module_platform_driver(arcpgu_platform_driver); 252 253MODULE_AUTHOR("Carlos Palminha <palminha@synopsys.com>"); 254MODULE_DESCRIPTION("ARC PGU DRM driver"); 255MODULE_LICENSE("GPL");