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.14-rc3 224 lines 5.1 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_encoder.h" 18#include "exynos_drm_connector.h" 19#include "exynos_drm_fbdev.h" 20 21static LIST_HEAD(exynos_drm_subdrv_list); 22 23static int exynos_drm_create_enc_conn(struct drm_device *dev, 24 struct exynos_drm_subdrv *subdrv) 25{ 26 struct drm_encoder *encoder; 27 struct drm_connector *connector; 28 int ret; 29 30 subdrv->manager->dev = subdrv->dev; 31 32 /* create and initialize a encoder for this sub driver. */ 33 encoder = exynos_drm_encoder_create(dev, subdrv->manager, 34 (1 << MAX_CRTC) - 1); 35 if (!encoder) { 36 DRM_ERROR("failed to create encoder\n"); 37 return -EFAULT; 38 } 39 40 /* 41 * create and initialize a connector for this sub driver and 42 * attach the encoder created above to the connector. 43 */ 44 connector = exynos_drm_connector_create(dev, encoder); 45 if (!connector) { 46 DRM_ERROR("failed to create connector\n"); 47 ret = -EFAULT; 48 goto err_destroy_encoder; 49 } 50 51 subdrv->encoder = encoder; 52 subdrv->connector = connector; 53 54 return 0; 55 56err_destroy_encoder: 57 encoder->funcs->destroy(encoder); 58 return ret; 59} 60 61static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv) 62{ 63 if (subdrv->encoder) { 64 struct drm_encoder *encoder = subdrv->encoder; 65 encoder->funcs->destroy(encoder); 66 subdrv->encoder = NULL; 67 } 68 69 if (subdrv->connector) { 70 struct drm_connector *connector = subdrv->connector; 71 connector->funcs->destroy(connector); 72 subdrv->connector = NULL; 73 } 74} 75 76static int exynos_drm_subdrv_probe(struct drm_device *dev, 77 struct exynos_drm_subdrv *subdrv) 78{ 79 if (subdrv->probe) { 80 int ret; 81 82 subdrv->drm_dev = dev; 83 84 /* 85 * this probe callback would be called by sub driver 86 * after setting of all resources to this sub driver, 87 * such as clock, irq and register map are done or by load() 88 * of exynos drm driver. 89 * 90 * P.S. note that this driver is considered for modularization. 91 */ 92 ret = subdrv->probe(dev, subdrv->dev); 93 if (ret) 94 return ret; 95 } 96 97 return 0; 98} 99 100static void exynos_drm_subdrv_remove(struct drm_device *dev, 101 struct exynos_drm_subdrv *subdrv) 102{ 103 if (subdrv->remove) 104 subdrv->remove(dev, subdrv->dev); 105} 106 107int exynos_drm_device_register(struct drm_device *dev) 108{ 109 struct exynos_drm_subdrv *subdrv, *n; 110 unsigned int fine_cnt = 0; 111 int err; 112 113 if (!dev) 114 return -EINVAL; 115 116 list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { 117 err = exynos_drm_subdrv_probe(dev, subdrv); 118 if (err) { 119 DRM_DEBUG("exynos drm subdrv probe failed.\n"); 120 list_del(&subdrv->list); 121 continue; 122 } 123 124 /* 125 * if manager is null then it means that this sub driver 126 * doesn't need encoder and connector. 127 */ 128 if (!subdrv->manager) { 129 fine_cnt++; 130 continue; 131 } 132 133 err = exynos_drm_create_enc_conn(dev, subdrv); 134 if (err) { 135 DRM_DEBUG("failed to create encoder and connector.\n"); 136 exynos_drm_subdrv_remove(dev, subdrv); 137 list_del(&subdrv->list); 138 continue; 139 } 140 141 fine_cnt++; 142 } 143 144 if (!fine_cnt) 145 return -EINVAL; 146 147 return 0; 148} 149EXPORT_SYMBOL_GPL(exynos_drm_device_register); 150 151int exynos_drm_device_unregister(struct drm_device *dev) 152{ 153 struct exynos_drm_subdrv *subdrv; 154 155 if (!dev) { 156 WARN(1, "Unexpected drm device unregister!\n"); 157 return -EINVAL; 158 } 159 160 list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { 161 exynos_drm_subdrv_remove(dev, subdrv); 162 exynos_drm_destroy_enc_conn(subdrv); 163 } 164 165 return 0; 166} 167EXPORT_SYMBOL_GPL(exynos_drm_device_unregister); 168 169int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) 170{ 171 if (!subdrv) 172 return -EINVAL; 173 174 list_add_tail(&subdrv->list, &exynos_drm_subdrv_list); 175 176 return 0; 177} 178EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register); 179 180int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) 181{ 182 if (!subdrv) 183 return -EINVAL; 184 185 list_del(&subdrv->list); 186 187 return 0; 188} 189EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister); 190 191int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) 192{ 193 struct exynos_drm_subdrv *subdrv; 194 int ret; 195 196 list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { 197 if (subdrv->open) { 198 ret = subdrv->open(dev, subdrv->dev, file); 199 if (ret) 200 goto err; 201 } 202 } 203 204 return 0; 205 206err: 207 list_for_each_entry_reverse(subdrv, &subdrv->list, list) { 208 if (subdrv->close) 209 subdrv->close(dev, subdrv->dev, file); 210 } 211 return ret; 212} 213EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open); 214 215void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) 216{ 217 struct exynos_drm_subdrv *subdrv; 218 219 list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { 220 if (subdrv->close) 221 subdrv->close(dev, subdrv->dev, file); 222 } 223} 224EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);