Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: sti: Add DRM driver itself

Make the link between all the hardware drivers and DRM/KMS interface.
Create the driver itself and make it register all the sub-components.
Use GEM CMA helpers for buffer allocation.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Reviewed-by: Rob Clark <robdclark@gmail.com>

+985 -3
+8
drivers/gpu/drm/sti/Kconfig
··· 1 1 config DRM_STI 2 2 tristate "DRM Support for STMicroelectronics SoC stiH41x Series" 3 3 depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM) 4 + select DRM_KMS_HELPER 5 + select DRM_GEM_CMA_HELPER 4 6 select DRM_KMS_CMA_HELPER 5 7 help 6 8 Choose this option to enable DRM on STM stiH41x chipset 9 + 10 + config DRM_STI_FBDEV 11 + bool "DRM frame buffer device for STMicroelectronics SoC stiH41x Serie" 12 + depends on DRM_STI 13 + help 14 + Choose this option to enable FBDEV on top of DRM for STM stiH41x chipset
+5 -2
drivers/gpu/drm/sti/Makefile
··· 3 3 sti_mixer.o \ 4 4 sti_gdp.o \ 5 5 sti_vid.o \ 6 - sti_compositor.o 6 + sti_compositor.o \ 7 + sti_drm_crtc.o \ 8 + sti_drm_plane.o 7 9 8 10 stihdmi-y := sti_hdmi.o \ 9 11 sti_hdmi_tx3g0c55phy.o \ ··· 17 15 stihdmi.o \ 18 16 sti_hda.o \ 19 17 sti_tvout.o \ 20 - sticompositor.o 18 + sticompositor.o \ 19 + sti_drm_drv.o
+44 -1
drivers/gpu/drm/sti/sti_compositor.c
··· 14 14 #include <drm/drmP.h> 15 15 16 16 #include "sti_compositor.h" 17 + #include "sti_drm_crtc.h" 18 + #include "sti_drm_drv.h" 19 + #include "sti_drm_plane.h" 17 20 #include "sti_gdp.h" 18 21 #include "sti_vtg.h" 19 22 ··· 90 87 struct sti_compositor *compo = dev_get_drvdata(dev); 91 88 struct drm_device *drm_dev = data; 92 89 unsigned int i, crtc = 0, plane = 0; 90 + struct sti_drm_private *dev_priv = drm_dev->dev_private; 91 + struct drm_plane *cursor = NULL; 92 + struct drm_plane *primary = NULL; 93 + 94 + dev_priv->compo = compo; 95 + 96 + for (i = 0; i < compo->nb_layers; i++) { 97 + if (compo->layer[i]) { 98 + enum sti_layer_desc desc = compo->layer[i]->desc; 99 + enum sti_layer_type type = desc & STI_LAYER_TYPE_MASK; 100 + enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY; 101 + 102 + if (compo->mixer[crtc]) 103 + plane_type = DRM_PLANE_TYPE_PRIMARY; 104 + 105 + switch (type) { 106 + case STI_CUR: 107 + cursor = sti_drm_plane_init(drm_dev, 108 + compo->layer[i], 109 + (1 << crtc) - 1, 110 + DRM_PLANE_TYPE_CURSOR); 111 + break; 112 + case STI_GDP: 113 + case STI_VID: 114 + primary = sti_drm_plane_init(drm_dev, 115 + compo->layer[i], 116 + (1 << crtc) - 1, plane_type); 117 + plane++; 118 + break; 119 + } 120 + 121 + /* The first planes are reserved for primary planes*/ 122 + if (compo->mixer[crtc]) { 123 + sti_drm_crtc_init(drm_dev, compo->mixer[crtc], 124 + primary, cursor); 125 + crtc++; 126 + cursor = NULL; 127 + } 128 + } 129 + } 93 130 94 131 drm_vblank_init(drm_dev, crtc); 95 132 /* Allow usage of vblank without having to call drm_irq_install */ 96 133 drm_dev->irq_enabled = 1; 97 - 98 134 99 135 DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n", 100 136 crtc, plane); ··· 181 139 return -ENOMEM; 182 140 } 183 141 compo->dev = dev; 142 + compo->vtg_vblank_nb.notifier_call = sti_drm_crtc_vblank_cb; 184 143 185 144 /* populate data structure depending on compatibility */ 186 145 BUG_ON(!of_match_node(compositor_of_match, np)->data);
+423
drivers/gpu/drm/sti/sti_drm_crtc.c
··· 1 + /* 2 + * Copyright (C) STMicroelectronics SA 2014 3 + * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 + * Fabien Dessenne <fabien.dessenne@st.com> 5 + * for STMicroelectronics. 6 + * License terms: GNU General Public License (GPL), version 2 7 + */ 8 + 9 + #include <linux/clk.h> 10 + 11 + #include <drm/drmP.h> 12 + #include <drm/drm_crtc_helper.h> 13 + 14 + #include "sti_compositor.h" 15 + #include "sti_drm_drv.h" 16 + #include "sti_drm_crtc.h" 17 + #include "sti_vtg.h" 18 + 19 + static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 20 + { 21 + DRM_DEBUG_KMS("\n"); 22 + } 23 + 24 + static void sti_drm_crtc_prepare(struct drm_crtc *crtc) 25 + { 26 + struct sti_mixer *mixer = to_sti_mixer(crtc); 27 + struct device *dev = mixer->dev; 28 + struct sti_compositor *compo = dev_get_drvdata(dev); 29 + 30 + compo->enable = true; 31 + 32 + /* Prepare and enable the compo IP clock */ 33 + if (mixer->id == STI_MIXER_MAIN) { 34 + if (clk_prepare_enable(compo->clk_compo_main)) 35 + DRM_INFO("Failed to prepare/enable compo_main clk\n"); 36 + } else { 37 + if (clk_prepare_enable(compo->clk_compo_aux)) 38 + DRM_INFO("Failed to prepare/enable compo_aux clk\n"); 39 + } 40 + } 41 + 42 + static void sti_drm_crtc_commit(struct drm_crtc *crtc) 43 + { 44 + struct sti_mixer *mixer = to_sti_mixer(crtc); 45 + struct device *dev = mixer->dev; 46 + struct sti_compositor *compo = dev_get_drvdata(dev); 47 + struct sti_layer *layer; 48 + 49 + if ((!mixer || !compo)) { 50 + DRM_ERROR("Can not find mixer or compositor)\n"); 51 + return; 52 + } 53 + 54 + /* get GDP which is reserved to the CRTC FB */ 55 + layer = to_sti_layer(crtc->primary); 56 + if (layer) 57 + sti_layer_commit(layer); 58 + else 59 + DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n"); 60 + 61 + /* Enable layer on mixer */ 62 + if (sti_mixer_set_layer_status(mixer, layer, true)) 63 + DRM_ERROR("Can not enable layer at mixer\n"); 64 + } 65 + 66 + static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc, 67 + const struct drm_display_mode *mode, 68 + struct drm_display_mode *adjusted_mode) 69 + { 70 + /* accept the provided drm_display_mode, do not fix it up */ 71 + return true; 72 + } 73 + 74 + static int 75 + sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 76 + struct drm_display_mode *adjusted_mode, int x, int y, 77 + struct drm_framebuffer *old_fb) 78 + { 79 + struct sti_mixer *mixer = to_sti_mixer(crtc); 80 + struct device *dev = mixer->dev; 81 + struct sti_compositor *compo = dev_get_drvdata(dev); 82 + struct sti_layer *layer; 83 + struct clk *clk; 84 + int rate = mode->clock * 1000; 85 + int res; 86 + unsigned int w, h; 87 + 88 + DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n", 89 + crtc->base.id, sti_mixer_to_str(mixer), 90 + crtc->primary->fb->base.id, mode->base.id, mode->name); 91 + 92 + DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", 93 + mode->vrefresh, mode->clock, 94 + mode->hdisplay, 95 + mode->hsync_start, mode->hsync_end, 96 + mode->htotal, 97 + mode->vdisplay, 98 + mode->vsync_start, mode->vsync_end, 99 + mode->vtotal, mode->type, mode->flags); 100 + 101 + /* Set rate and prepare/enable pixel clock */ 102 + if (mixer->id == STI_MIXER_MAIN) 103 + clk = compo->clk_pix_main; 104 + else 105 + clk = compo->clk_pix_aux; 106 + 107 + res = clk_set_rate(clk, rate); 108 + if (res < 0) { 109 + DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); 110 + return -EINVAL; 111 + } 112 + if (clk_prepare_enable(clk)) { 113 + DRM_ERROR("Failed to prepare/enable pix clk\n"); 114 + return -EINVAL; 115 + } 116 + 117 + sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? 118 + compo->vtg_main : compo->vtg_aux, &crtc->mode); 119 + 120 + /* a GDP is reserved to the CRTC FB */ 121 + layer = to_sti_layer(crtc->primary); 122 + if (!layer) { 123 + DRM_ERROR("Can not find GDP0)\n"); 124 + return -EINVAL; 125 + } 126 + 127 + /* copy the mode data adjusted by mode_fixup() into crtc->mode 128 + * so that hardware can be set to proper mode 129 + */ 130 + memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); 131 + 132 + res = sti_mixer_set_layer_depth(mixer, layer); 133 + if (res) { 134 + DRM_ERROR("Can not set layer depth\n"); 135 + return -EINVAL; 136 + } 137 + res = sti_mixer_active_video_area(mixer, &crtc->mode); 138 + if (res) { 139 + DRM_ERROR("Can not set active video area\n"); 140 + return -EINVAL; 141 + } 142 + 143 + w = crtc->primary->fb->width - x; 144 + h = crtc->primary->fb->height - y; 145 + 146 + return sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode, 147 + mixer->id, 0, 0, w, h, x, y, w, h); 148 + } 149 + 150 + static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 151 + struct drm_framebuffer *old_fb) 152 + { 153 + struct sti_mixer *mixer = to_sti_mixer(crtc); 154 + struct device *dev = mixer->dev; 155 + struct sti_compositor *compo = dev_get_drvdata(dev); 156 + struct sti_layer *layer; 157 + unsigned int w, h; 158 + int ret; 159 + 160 + DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n", 161 + crtc->base.id, sti_mixer_to_str(mixer), 162 + crtc->primary->fb->base.id, x, y); 163 + 164 + /* GDP is reserved to the CRTC FB */ 165 + layer = to_sti_layer(crtc->primary); 166 + if (!layer) { 167 + DRM_ERROR("Can not find GDP0)\n"); 168 + ret = -EINVAL; 169 + goto out; 170 + } 171 + 172 + w = crtc->primary->fb->width - crtc->x; 173 + h = crtc->primary->fb->height - crtc->y; 174 + 175 + ret = sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode, 176 + mixer->id, 0, 0, w, h, 177 + crtc->x, crtc->y, w, h); 178 + if (ret) { 179 + DRM_ERROR("Can not prepare layer\n"); 180 + goto out; 181 + } 182 + 183 + sti_drm_crtc_commit(crtc); 184 + out: 185 + return ret; 186 + } 187 + 188 + static void sti_drm_crtc_load_lut(struct drm_crtc *crtc) 189 + { 190 + /* do nothing */ 191 + } 192 + 193 + static void sti_drm_crtc_disable(struct drm_crtc *crtc) 194 + { 195 + struct sti_mixer *mixer = to_sti_mixer(crtc); 196 + struct device *dev = mixer->dev; 197 + struct sti_compositor *compo = dev_get_drvdata(dev); 198 + struct sti_layer *layer; 199 + 200 + if (!compo->enable) 201 + return; 202 + 203 + DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); 204 + 205 + /* Disable Background */ 206 + sti_mixer_set_background_status(mixer, false); 207 + 208 + /* Disable GDP */ 209 + layer = to_sti_layer(crtc->primary); 210 + if (!layer) { 211 + DRM_ERROR("Cannot find GDP0\n"); 212 + return; 213 + } 214 + 215 + /* Disable layer at mixer level */ 216 + if (sti_mixer_set_layer_status(mixer, layer, false)) 217 + DRM_ERROR("Can not disable %s layer at mixer\n", 218 + sti_layer_to_str(layer)); 219 + 220 + /* Wait a while to be sure that a Vsync event is received */ 221 + msleep(WAIT_NEXT_VSYNC_MS); 222 + 223 + /* Then disable layer itself */ 224 + sti_layer_disable(layer); 225 + 226 + drm_vblank_off(crtc->dev, mixer->id); 227 + 228 + /* Disable pixel clock and compo IP clocks */ 229 + if (mixer->id == STI_MIXER_MAIN) { 230 + clk_disable_unprepare(compo->clk_pix_main); 231 + clk_disable_unprepare(compo->clk_compo_main); 232 + } else { 233 + clk_disable_unprepare(compo->clk_pix_aux); 234 + clk_disable_unprepare(compo->clk_compo_aux); 235 + } 236 + 237 + compo->enable = false; 238 + } 239 + 240 + static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { 241 + .dpms = sti_drm_crtc_dpms, 242 + .prepare = sti_drm_crtc_prepare, 243 + .commit = sti_drm_crtc_commit, 244 + .mode_fixup = sti_drm_crtc_mode_fixup, 245 + .mode_set = sti_drm_crtc_mode_set, 246 + .mode_set_base = sti_drm_crtc_mode_set_base, 247 + .load_lut = sti_drm_crtc_load_lut, 248 + .disable = sti_drm_crtc_disable, 249 + }; 250 + 251 + static int sti_drm_crtc_page_flip(struct drm_crtc *crtc, 252 + struct drm_framebuffer *fb, 253 + struct drm_pending_vblank_event *event, 254 + uint32_t page_flip_flags) 255 + { 256 + struct drm_device *drm_dev = crtc->dev; 257 + struct drm_framebuffer *old_fb; 258 + struct sti_mixer *mixer = to_sti_mixer(crtc); 259 + unsigned long flags; 260 + int ret; 261 + 262 + DRM_DEBUG_KMS("fb %d --> fb %d\n", 263 + crtc->primary->fb->base.id, fb->base.id); 264 + 265 + mutex_lock(&drm_dev->struct_mutex); 266 + 267 + old_fb = crtc->primary->fb; 268 + crtc->primary->fb = fb; 269 + ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); 270 + if (ret) { 271 + DRM_ERROR("failed\n"); 272 + crtc->primary->fb = old_fb; 273 + goto out; 274 + } 275 + 276 + if (event) { 277 + event->pipe = mixer->id; 278 + 279 + ret = drm_vblank_get(drm_dev, event->pipe); 280 + if (ret) { 281 + DRM_ERROR("Cannot get vblank\n"); 282 + goto out; 283 + } 284 + 285 + spin_lock_irqsave(&drm_dev->event_lock, flags); 286 + if (mixer->pending_event) { 287 + drm_vblank_put(drm_dev, event->pipe); 288 + ret = -EBUSY; 289 + } else { 290 + mixer->pending_event = event; 291 + } 292 + spin_unlock_irqrestore(&drm_dev->event_lock, flags); 293 + } 294 + out: 295 + mutex_unlock(&drm_dev->struct_mutex); 296 + return ret; 297 + } 298 + 299 + static void sti_drm_crtc_destroy(struct drm_crtc *crtc) 300 + { 301 + DRM_DEBUG_KMS("\n"); 302 + drm_crtc_cleanup(crtc); 303 + } 304 + 305 + static int sti_drm_crtc_set_property(struct drm_crtc *crtc, 306 + struct drm_property *property, 307 + uint64_t val) 308 + { 309 + DRM_DEBUG_KMS("\n"); 310 + return 0; 311 + } 312 + 313 + int sti_drm_crtc_vblank_cb(struct notifier_block *nb, 314 + unsigned long event, void *data) 315 + { 316 + struct drm_device *drm_dev; 317 + struct sti_compositor *compo = 318 + container_of(nb, struct sti_compositor, vtg_vblank_nb); 319 + int *crtc = data; 320 + unsigned long flags; 321 + struct sti_drm_private *priv; 322 + 323 + drm_dev = compo->mixer[*crtc]->drm_crtc.dev; 324 + priv = drm_dev->dev_private; 325 + 326 + if ((event != VTG_TOP_FIELD_EVENT) && 327 + (event != VTG_BOTTOM_FIELD_EVENT)) { 328 + DRM_ERROR("unknown event: %lu\n", event); 329 + return -EINVAL; 330 + } 331 + 332 + drm_handle_vblank(drm_dev, *crtc); 333 + 334 + spin_lock_irqsave(&drm_dev->event_lock, flags); 335 + if (compo->mixer[*crtc]->pending_event) { 336 + drm_send_vblank_event(drm_dev, -1, 337 + compo->mixer[*crtc]->pending_event); 338 + drm_vblank_put(drm_dev, *crtc); 339 + compo->mixer[*crtc]->pending_event = NULL; 340 + } 341 + spin_unlock_irqrestore(&drm_dev->event_lock, flags); 342 + 343 + return 0; 344 + } 345 + 346 + int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) 347 + { 348 + struct sti_drm_private *dev_priv = dev->dev_private; 349 + struct sti_compositor *compo = dev_priv->compo; 350 + struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; 351 + 352 + if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? 353 + compo->vtg_main : compo->vtg_aux, 354 + vtg_vblank_nb, crtc)) { 355 + DRM_ERROR("Cannot register VTG notifier\n"); 356 + return -EINVAL; 357 + } 358 + 359 + return 0; 360 + } 361 + EXPORT_SYMBOL(sti_drm_crtc_enable_vblank); 362 + 363 + void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) 364 + { 365 + struct sti_drm_private *priv = dev->dev_private; 366 + struct sti_compositor *compo = priv->compo; 367 + struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; 368 + unsigned long flags; 369 + 370 + DRM_DEBUG_DRIVER("\n"); 371 + 372 + if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? 373 + compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) 374 + DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); 375 + 376 + /* free the resources of the pending requests */ 377 + spin_lock_irqsave(&dev->event_lock, flags); 378 + if (compo->mixer[crtc]->pending_event) { 379 + drm_vblank_put(dev, crtc); 380 + compo->mixer[crtc]->pending_event = NULL; 381 + } 382 + spin_unlock_irqrestore(&dev->event_lock, flags); 383 + 384 + } 385 + EXPORT_SYMBOL(sti_drm_crtc_disable_vblank); 386 + 387 + static struct drm_crtc_funcs sti_crtc_funcs = { 388 + .set_config = drm_crtc_helper_set_config, 389 + .page_flip = sti_drm_crtc_page_flip, 390 + .destroy = sti_drm_crtc_destroy, 391 + .set_property = sti_drm_crtc_set_property, 392 + }; 393 + 394 + bool sti_drm_crtc_is_main(struct drm_crtc *crtc) 395 + { 396 + struct sti_mixer *mixer = to_sti_mixer(crtc); 397 + 398 + if (mixer->id == STI_MIXER_MAIN) 399 + return true; 400 + 401 + return false; 402 + } 403 + 404 + int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, 405 + struct drm_plane *primary, struct drm_plane *cursor) 406 + { 407 + struct drm_crtc *crtc = &mixer->drm_crtc; 408 + int res; 409 + 410 + res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, 411 + &sti_crtc_funcs); 412 + if (res) { 413 + DRM_ERROR("Can not initialze CRTC\n"); 414 + return -EINVAL; 415 + } 416 + 417 + drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs); 418 + 419 + DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n", 420 + crtc->base.id, sti_mixer_to_str(mixer)); 421 + 422 + return 0; 423 + }
+22
drivers/gpu/drm/sti/sti_drm_crtc.h
··· 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 + #ifndef _STI_DRM_CRTC_H_ 8 + #define _STI_DRM_CRTC_H_ 9 + 10 + #include <drm/drmP.h> 11 + 12 + struct sti_mixer; 13 + 14 + int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, 15 + struct drm_plane *primary, struct drm_plane *cursor); 16 + int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc); 17 + void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc); 18 + int sti_drm_crtc_vblank_cb(struct notifier_block *nb, 19 + unsigned long event, void *data); 20 + bool sti_drm_crtc_is_main(struct drm_crtc *drm_crtc); 21 + 22 + #endif
+241
drivers/gpu/drm/sti/sti_drm_drv.c
··· 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_crtc_helper.h> 16 + #include <drm/drm_gem_cma_helper.h> 17 + #include <drm/drm_fb_cma_helper.h> 18 + 19 + #include "sti_drm_drv.h" 20 + #include "sti_drm_crtc.h" 21 + 22 + #define DRIVER_NAME "sti" 23 + #define DRIVER_DESC "STMicroelectronics SoC DRM" 24 + #define DRIVER_DATE "20140601" 25 + #define DRIVER_MAJOR 1 26 + #define DRIVER_MINOR 0 27 + 28 + #define STI_MAX_FB_HEIGHT 4096 29 + #define STI_MAX_FB_WIDTH 4096 30 + 31 + static struct drm_mode_config_funcs sti_drm_mode_config_funcs = { 32 + .fb_create = drm_fb_cma_create, 33 + }; 34 + 35 + static void sti_drm_mode_config_init(struct drm_device *dev) 36 + { 37 + dev->mode_config.min_width = 0; 38 + dev->mode_config.min_height = 0; 39 + 40 + /* 41 + * set max width and height as default value. 42 + * this value would be used to check framebuffer size limitation 43 + * at drm_mode_addfb(). 44 + */ 45 + dev->mode_config.max_width = STI_MAX_FB_HEIGHT; 46 + dev->mode_config.max_height = STI_MAX_FB_WIDTH; 47 + 48 + dev->mode_config.funcs = &sti_drm_mode_config_funcs; 49 + } 50 + 51 + static int sti_drm_load(struct drm_device *dev, unsigned long flags) 52 + { 53 + struct sti_drm_private *private; 54 + int ret; 55 + 56 + private = kzalloc(sizeof(struct sti_drm_private), GFP_KERNEL); 57 + if (!private) { 58 + DRM_ERROR("Failed to allocate private\n"); 59 + return -ENOMEM; 60 + } 61 + dev->dev_private = (void *)private; 62 + private->drm_dev = dev; 63 + 64 + drm_mode_config_init(dev); 65 + drm_kms_helper_poll_init(dev); 66 + 67 + sti_drm_mode_config_init(dev); 68 + 69 + ret = component_bind_all(dev->dev, dev); 70 + if (ret) 71 + return ret; 72 + 73 + drm_helper_disable_unused_functions(dev); 74 + 75 + #ifdef CONFIG_DRM_STI_FBDEV 76 + drm_fbdev_cma_init(dev, 32, 77 + dev->mode_config.num_crtc, 78 + dev->mode_config.num_connector); 79 + #endif 80 + return 0; 81 + } 82 + 83 + static const struct file_operations sti_drm_driver_fops = { 84 + .owner = THIS_MODULE, 85 + .open = drm_open, 86 + .mmap = drm_gem_cma_mmap, 87 + .poll = drm_poll, 88 + .read = drm_read, 89 + .unlocked_ioctl = drm_ioctl, 90 + #ifdef CONFIG_COMPAT 91 + .compat_ioctl = drm_compat_ioctl, 92 + #endif 93 + .release = drm_release, 94 + }; 95 + 96 + static struct dma_buf *sti_drm_gem_prime_export(struct drm_device *dev, 97 + struct drm_gem_object *obj, 98 + int flags) 99 + { 100 + /* we want to be able to write in mmapped buffer */ 101 + flags |= O_RDWR; 102 + return drm_gem_prime_export(dev, obj, flags); 103 + } 104 + 105 + static struct drm_driver sti_drm_driver = { 106 + .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | 107 + DRIVER_GEM | DRIVER_PRIME, 108 + .load = sti_drm_load, 109 + .gem_free_object = drm_gem_cma_free_object, 110 + .gem_vm_ops = &drm_gem_cma_vm_ops, 111 + .dumb_create = drm_gem_cma_dumb_create, 112 + .dumb_map_offset = drm_gem_cma_dumb_map_offset, 113 + .dumb_destroy = drm_gem_dumb_destroy, 114 + .fops = &sti_drm_driver_fops, 115 + 116 + .get_vblank_counter = drm_vblank_count, 117 + .enable_vblank = sti_drm_crtc_enable_vblank, 118 + .disable_vblank = sti_drm_crtc_disable_vblank, 119 + 120 + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 121 + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 122 + .gem_prime_export = sti_drm_gem_prime_export, 123 + .gem_prime_import = drm_gem_prime_import, 124 + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 125 + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 126 + .gem_prime_vmap = drm_gem_cma_prime_vmap, 127 + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 128 + .gem_prime_mmap = drm_gem_cma_prime_mmap, 129 + 130 + .name = DRIVER_NAME, 131 + .desc = DRIVER_DESC, 132 + .date = DRIVER_DATE, 133 + .major = DRIVER_MAJOR, 134 + .minor = DRIVER_MINOR, 135 + }; 136 + 137 + static int compare_of(struct device *dev, void *data) 138 + { 139 + return dev->of_node == data; 140 + } 141 + 142 + static int sti_drm_bind(struct device *dev) 143 + { 144 + return drm_platform_init(&sti_drm_driver, to_platform_device(dev)); 145 + } 146 + 147 + static void sti_drm_unbind(struct device *dev) 148 + { 149 + drm_put_dev(dev_get_drvdata(dev)); 150 + } 151 + 152 + static const struct component_master_ops sti_drm_ops = { 153 + .bind = sti_drm_bind, 154 + .unbind = sti_drm_unbind, 155 + }; 156 + 157 + static int sti_drm_master_probe(struct platform_device *pdev) 158 + { 159 + struct device *dev = &pdev->dev; 160 + struct device_node *node = dev->parent->of_node; 161 + struct device_node *child_np; 162 + struct component_match *match = NULL; 163 + 164 + dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 165 + 166 + child_np = of_get_next_available_child(node, NULL); 167 + 168 + while (child_np) { 169 + component_match_add(dev, &match, compare_of, child_np); 170 + of_node_put(child_np); 171 + child_np = of_get_next_available_child(node, child_np); 172 + } 173 + 174 + return component_master_add_with_match(dev, &sti_drm_ops, match); 175 + } 176 + 177 + static int sti_drm_master_remove(struct platform_device *pdev) 178 + { 179 + component_master_del(&pdev->dev, &sti_drm_ops); 180 + return 0; 181 + } 182 + 183 + static struct platform_driver sti_drm_master_driver = { 184 + .probe = sti_drm_master_probe, 185 + .remove = sti_drm_master_remove, 186 + .driver = { 187 + .owner = THIS_MODULE, 188 + .name = DRIVER_NAME "__master", 189 + }, 190 + }; 191 + 192 + static int sti_drm_platform_probe(struct platform_device *pdev) 193 + { 194 + struct device *dev = &pdev->dev; 195 + struct device_node *node = dev->of_node; 196 + struct platform_device *master; 197 + 198 + of_platform_populate(node, NULL, NULL, dev); 199 + 200 + platform_driver_register(&sti_drm_master_driver); 201 + master = platform_device_register_resndata(dev, 202 + DRIVER_NAME "__master", -1, 203 + NULL, 0, NULL, 0); 204 + if (!master) 205 + return -EINVAL; 206 + 207 + platform_set_drvdata(pdev, master); 208 + return 0; 209 + } 210 + 211 + static int sti_drm_platform_remove(struct platform_device *pdev) 212 + { 213 + struct platform_device *master = platform_get_drvdata(pdev); 214 + 215 + of_platform_depopulate(&pdev->dev); 216 + platform_device_unregister(master); 217 + platform_driver_unregister(&sti_drm_master_driver); 218 + return 0; 219 + } 220 + 221 + static const struct of_device_id sti_drm_dt_ids[] = { 222 + { .compatible = "st,sti-display-subsystem", }, 223 + { /* end node */ }, 224 + }; 225 + MODULE_DEVICE_TABLE(of, sti_drm_dt_ids); 226 + 227 + static struct platform_driver sti_drm_platform_driver = { 228 + .probe = sti_drm_platform_probe, 229 + .remove = sti_drm_platform_remove, 230 + .driver = { 231 + .owner = THIS_MODULE, 232 + .name = DRIVER_NAME, 233 + .of_match_table = sti_drm_dt_ids, 234 + }, 235 + }; 236 + 237 + module_platform_driver(sti_drm_platform_driver); 238 + 239 + MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 240 + MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 241 + MODULE_LICENSE("GPL");
+29
drivers/gpu/drm/sti/sti_drm_drv.h
··· 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 + #ifndef _STI_DRM_DRV_H_ 8 + #define _STI_DRM_DRV_H_ 9 + 10 + #include <drm/drmP.h> 11 + 12 + struct sti_compositor; 13 + struct sti_tvout; 14 + 15 + /** 16 + * STI drm private structure 17 + * This structure is stored as private in the drm_device 18 + * 19 + * @compo: compositor 20 + * @plane_zorder_property: z-order property for CRTC planes 21 + * @drm_dev: drm device 22 + */ 23 + struct sti_drm_private { 24 + struct sti_compositor *compo; 25 + struct drm_property *plane_zorder_property; 26 + struct drm_device *drm_dev; 27 + }; 28 + 29 + #endif
+195
drivers/gpu/drm/sti/sti_drm_plane.c
··· 1 + /* 2 + * Copyright (C) STMicroelectronics SA 2014 3 + * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 + * Fabien Dessenne <fabien.dessenne@st.com> 5 + * for STMicroelectronics. 6 + * License terms: GNU General Public License (GPL), version 2 7 + */ 8 + 9 + #include "sti_compositor.h" 10 + #include "sti_drm_drv.h" 11 + #include "sti_drm_plane.h" 12 + #include "sti_vtg.h" 13 + 14 + enum sti_layer_desc sti_layer_default_zorder[] = { 15 + STI_GDP_0, 16 + STI_VID_0, 17 + STI_GDP_1, 18 + STI_VID_1, 19 + STI_GDP_2, 20 + STI_GDP_3, 21 + }; 22 + 23 + /* (Background) < GDP0 < VID0 < GDP1 < VID1 < GDP2 < GDP3 < (ForeGround) */ 24 + 25 + static int 26 + sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 27 + struct drm_framebuffer *fb, int crtc_x, int crtc_y, 28 + unsigned int crtc_w, unsigned int crtc_h, 29 + uint32_t src_x, uint32_t src_y, 30 + uint32_t src_w, uint32_t src_h) 31 + { 32 + struct sti_layer *layer = to_sti_layer(plane); 33 + struct sti_mixer *mixer = to_sti_mixer(crtc); 34 + int res; 35 + 36 + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n", 37 + crtc->base.id, sti_mixer_to_str(mixer), 38 + plane->base.id, sti_layer_to_str(layer), fb->base.id); 39 + DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y); 40 + 41 + res = sti_mixer_set_layer_depth(mixer, layer); 42 + if (res) { 43 + DRM_ERROR("Can not set layer depth\n"); 44 + return res; 45 + } 46 + 47 + /* src_x are in 16.16 format. */ 48 + res = sti_layer_prepare(layer, fb, &crtc->mode, mixer->id, 49 + crtc_x, crtc_y, crtc_w, crtc_h, 50 + src_x >> 16, src_y >> 16, 51 + src_w >> 16, src_h >> 16); 52 + if (res) { 53 + DRM_ERROR("Layer prepare failed\n"); 54 + return res; 55 + } 56 + 57 + res = sti_layer_commit(layer); 58 + if (res) { 59 + DRM_ERROR("Layer commit failed\n"); 60 + return res; 61 + } 62 + 63 + res = sti_mixer_set_layer_status(mixer, layer, true); 64 + if (res) { 65 + DRM_ERROR("Can not enable layer at mixer\n"); 66 + return res; 67 + } 68 + 69 + return 0; 70 + } 71 + 72 + static int sti_drm_disable_plane(struct drm_plane *plane) 73 + { 74 + struct sti_layer *layer; 75 + struct sti_mixer *mixer; 76 + int lay_res, mix_res; 77 + 78 + if (!plane->crtc) { 79 + DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", plane->base.id); 80 + return 0; 81 + } 82 + layer = to_sti_layer(plane); 83 + mixer = to_sti_mixer(plane->crtc); 84 + 85 + DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", 86 + plane->crtc->base.id, sti_mixer_to_str(mixer), 87 + plane->base.id, sti_layer_to_str(layer)); 88 + 89 + /* Disable layer at mixer level */ 90 + mix_res = sti_mixer_set_layer_status(mixer, layer, false); 91 + if (mix_res) 92 + DRM_ERROR("Can not disable layer at mixer\n"); 93 + 94 + /* Wait a while to be sure that a Vsync event is received */ 95 + msleep(WAIT_NEXT_VSYNC_MS); 96 + 97 + /* Then disable layer itself */ 98 + lay_res = sti_layer_disable(layer); 99 + if (lay_res) 100 + DRM_ERROR("Layer disable failed\n"); 101 + 102 + if (lay_res || mix_res) 103 + return -EINVAL; 104 + 105 + return 0; 106 + } 107 + 108 + static void sti_drm_plane_destroy(struct drm_plane *plane) 109 + { 110 + DRM_DEBUG_DRIVER("\n"); 111 + 112 + sti_drm_disable_plane(plane); 113 + drm_plane_cleanup(plane); 114 + } 115 + 116 + static int sti_drm_plane_set_property(struct drm_plane *plane, 117 + struct drm_property *property, 118 + uint64_t val) 119 + { 120 + struct drm_device *dev = plane->dev; 121 + struct sti_drm_private *private = dev->dev_private; 122 + struct sti_layer *layer = to_sti_layer(plane); 123 + 124 + DRM_DEBUG_DRIVER("\n"); 125 + 126 + if (property == private->plane_zorder_property) { 127 + layer->zorder = val; 128 + return 0; 129 + } 130 + 131 + return -EINVAL; 132 + } 133 + 134 + static struct drm_plane_funcs sti_drm_plane_funcs = { 135 + .update_plane = sti_drm_update_plane, 136 + .disable_plane = sti_drm_disable_plane, 137 + .destroy = sti_drm_plane_destroy, 138 + .set_property = sti_drm_plane_set_property, 139 + }; 140 + 141 + static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane, 142 + uint64_t default_val) 143 + { 144 + struct drm_device *dev = plane->dev; 145 + struct sti_drm_private *private = dev->dev_private; 146 + struct drm_property *prop; 147 + struct sti_layer *layer = to_sti_layer(plane); 148 + 149 + prop = private->plane_zorder_property; 150 + if (!prop) { 151 + prop = drm_property_create_range(dev, 0, "zpos", 0, 152 + GAM_MIXER_NB_DEPTH_LEVEL - 1); 153 + if (!prop) 154 + return; 155 + 156 + private->plane_zorder_property = prop; 157 + } 158 + 159 + drm_object_attach_property(&plane->base, prop, default_val); 160 + layer->zorder = default_val; 161 + } 162 + 163 + struct drm_plane *sti_drm_plane_init(struct drm_device *dev, 164 + struct sti_layer *layer, 165 + unsigned int possible_crtcs, 166 + enum drm_plane_type type) 167 + { 168 + int err, i; 169 + uint64_t default_zorder = 0; 170 + 171 + err = drm_universal_plane_init(dev, &layer->plane, possible_crtcs, 172 + &sti_drm_plane_funcs, 173 + sti_layer_get_formats(layer), 174 + sti_layer_get_nb_formats(layer), type); 175 + if (err) { 176 + DRM_ERROR("Failed to initialize plane\n"); 177 + return NULL; 178 + } 179 + 180 + for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++) 181 + if (sti_layer_default_zorder[i] == layer->desc) 182 + break; 183 + 184 + default_zorder = i; 185 + 186 + if (type == DRM_PLANE_TYPE_OVERLAY) 187 + sti_drm_plane_attach_zorder_property(&layer->plane, 188 + default_zorder); 189 + 190 + DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%llu\n", 191 + layer->plane.base.id, 192 + sti_layer_to_str(layer), default_zorder); 193 + 194 + return &layer->plane; 195 + }
+18
drivers/gpu/drm/sti/sti_drm_plane.h
··· 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 + #ifndef _STI_DRM_PLANE_H_ 8 + #define _STI_DRM_PLANE_H_ 9 + 10 + #include <drm/drmP.h> 11 + 12 + struct sti_layer; 13 + 14 + struct drm_plane *sti_drm_plane_init(struct drm_device *dev, 15 + struct sti_layer *layer, 16 + unsigned int possible_crtcs, 17 + enum drm_plane_type type); 18 + #endif