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 v3.15-rc2 305 lines 7.0 kB view raw
1/* exynos_drm_core.c 2 * 3 * Copyright (c) 2011 Samsung Electronics Co., Ltd. 4 * Author: 5 * Inki Dae <inki.dae@samsung.com> 6 * Joonyoung Shim <jy0922.shim@samsung.com> 7 * Seung-Woo Kim <sw0312.kim@samsung.com> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 15#include <drm/drmP.h> 16#include "exynos_drm_drv.h" 17#include "exynos_drm_crtc.h" 18#include "exynos_drm_encoder.h" 19#include "exynos_drm_fbdev.h" 20 21static LIST_HEAD(exynos_drm_subdrv_list); 22static LIST_HEAD(exynos_drm_manager_list); 23static LIST_HEAD(exynos_drm_display_list); 24 25static int exynos_drm_create_enc_conn(struct drm_device *dev, 26 struct exynos_drm_display *display) 27{ 28 struct drm_encoder *encoder; 29 struct exynos_drm_manager *manager; 30 int ret; 31 unsigned long possible_crtcs = 0; 32 33 /* Find possible crtcs for this display */ 34 list_for_each_entry(manager, &exynos_drm_manager_list, list) 35 if (manager->type == display->type) 36 possible_crtcs |= 1 << manager->pipe; 37 38 /* create and initialize a encoder for this sub driver. */ 39 encoder = exynos_drm_encoder_create(dev, display, possible_crtcs); 40 if (!encoder) { 41 DRM_ERROR("failed to create encoder\n"); 42 return -EFAULT; 43 } 44 45 display->encoder = encoder; 46 47 ret = display->ops->create_connector(display, encoder); 48 if (ret) { 49 DRM_ERROR("failed to create connector ret = %d\n", ret); 50 goto err_destroy_encoder; 51 } 52 53 return 0; 54 55err_destroy_encoder: 56 encoder->funcs->destroy(encoder); 57 return ret; 58} 59 60static int exynos_drm_subdrv_probe(struct drm_device *dev, 61 struct exynos_drm_subdrv *subdrv) 62{ 63 if (subdrv->probe) { 64 int ret; 65 66 subdrv->drm_dev = dev; 67 68 /* 69 * this probe callback would be called by sub driver 70 * after setting of all resources to this sub driver, 71 * such as clock, irq and register map are done or by load() 72 * of exynos drm driver. 73 * 74 * P.S. note that this driver is considered for modularization. 75 */ 76 ret = subdrv->probe(dev, subdrv->dev); 77 if (ret) 78 return ret; 79 } 80 81 return 0; 82} 83 84static void exynos_drm_subdrv_remove(struct drm_device *dev, 85 struct exynos_drm_subdrv *subdrv) 86{ 87 if (subdrv->remove) 88 subdrv->remove(dev, subdrv->dev); 89} 90 91int exynos_drm_initialize_managers(struct drm_device *dev) 92{ 93 struct exynos_drm_manager *manager, *n; 94 int ret, pipe = 0; 95 96 list_for_each_entry(manager, &exynos_drm_manager_list, list) { 97 if (manager->ops->initialize) { 98 ret = manager->ops->initialize(manager, dev, pipe); 99 if (ret) { 100 DRM_ERROR("Mgr init [%d] failed with %d\n", 101 manager->type, ret); 102 goto err; 103 } 104 } 105 106 manager->drm_dev = dev; 107 manager->pipe = pipe++; 108 109 ret = exynos_drm_crtc_create(manager); 110 if (ret) { 111 DRM_ERROR("CRTC create [%d] failed with %d\n", 112 manager->type, ret); 113 goto err; 114 } 115 } 116 return 0; 117 118err: 119 list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) { 120 if (pipe-- > 0) 121 exynos_drm_manager_unregister(manager); 122 else 123 list_del(&manager->list); 124 } 125 return ret; 126} 127 128void exynos_drm_remove_managers(struct drm_device *dev) 129{ 130 struct exynos_drm_manager *manager, *n; 131 132 list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) 133 exynos_drm_manager_unregister(manager); 134} 135 136int exynos_drm_initialize_displays(struct drm_device *dev) 137{ 138 struct exynos_drm_display *display, *n; 139 int ret, initialized = 0; 140 141 list_for_each_entry(display, &exynos_drm_display_list, list) { 142 if (display->ops->initialize) { 143 ret = display->ops->initialize(display, dev); 144 if (ret) { 145 DRM_ERROR("Display init [%d] failed with %d\n", 146 display->type, ret); 147 goto err; 148 } 149 } 150 151 initialized++; 152 153 ret = exynos_drm_create_enc_conn(dev, display); 154 if (ret) { 155 DRM_ERROR("Encoder create [%d] failed with %d\n", 156 display->type, ret); 157 goto err; 158 } 159 } 160 return 0; 161 162err: 163 list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) { 164 if (initialized-- > 0) 165 exynos_drm_display_unregister(display); 166 else 167 list_del(&display->list); 168 } 169 return ret; 170} 171 172void exynos_drm_remove_displays(struct drm_device *dev) 173{ 174 struct exynos_drm_display *display, *n; 175 176 list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) 177 exynos_drm_display_unregister(display); 178} 179 180int exynos_drm_device_register(struct drm_device *dev) 181{ 182 struct exynos_drm_subdrv *subdrv, *n; 183 int err; 184 185 if (!dev) 186 return -EINVAL; 187 188 list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { 189 err = exynos_drm_subdrv_probe(dev, subdrv); 190 if (err) { 191 DRM_DEBUG("exynos drm subdrv probe failed.\n"); 192 list_del(&subdrv->list); 193 continue; 194 } 195 } 196 197 return 0; 198} 199EXPORT_SYMBOL_GPL(exynos_drm_device_register); 200 201int exynos_drm_device_unregister(struct drm_device *dev) 202{ 203 struct exynos_drm_subdrv *subdrv; 204 205 if (!dev) { 206 WARN(1, "Unexpected drm device unregister!\n"); 207 return -EINVAL; 208 } 209 210 list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { 211 exynos_drm_subdrv_remove(dev, subdrv); 212 } 213 214 return 0; 215} 216EXPORT_SYMBOL_GPL(exynos_drm_device_unregister); 217 218int exynos_drm_manager_register(struct exynos_drm_manager *manager) 219{ 220 BUG_ON(!manager->ops); 221 list_add_tail(&manager->list, &exynos_drm_manager_list); 222 return 0; 223} 224 225int exynos_drm_manager_unregister(struct exynos_drm_manager *manager) 226{ 227 if (manager->ops->remove) 228 manager->ops->remove(manager); 229 230 list_del(&manager->list); 231 return 0; 232} 233 234int exynos_drm_display_register(struct exynos_drm_display *display) 235{ 236 BUG_ON(!display->ops); 237 list_add_tail(&display->list, &exynos_drm_display_list); 238 return 0; 239} 240 241int exynos_drm_display_unregister(struct exynos_drm_display *display) 242{ 243 if (display->ops->remove) 244 display->ops->remove(display); 245 246 list_del(&display->list); 247 return 0; 248} 249 250int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) 251{ 252 if (!subdrv) 253 return -EINVAL; 254 255 list_add_tail(&subdrv->list, &exynos_drm_subdrv_list); 256 257 return 0; 258} 259EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register); 260 261int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) 262{ 263 if (!subdrv) 264 return -EINVAL; 265 266 list_del(&subdrv->list); 267 268 return 0; 269} 270EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister); 271 272int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) 273{ 274 struct exynos_drm_subdrv *subdrv; 275 int ret; 276 277 list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { 278 if (subdrv->open) { 279 ret = subdrv->open(dev, subdrv->dev, file); 280 if (ret) 281 goto err; 282 } 283 } 284 285 return 0; 286 287err: 288 list_for_each_entry_reverse(subdrv, &subdrv->list, list) { 289 if (subdrv->close) 290 subdrv->close(dev, subdrv->dev, file); 291 } 292 return ret; 293} 294EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open); 295 296void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) 297{ 298 struct exynos_drm_subdrv *subdrv; 299 300 list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { 301 if (subdrv->close) 302 subdrv->close(dev, subdrv->dev, file); 303 } 304} 305EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);