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

Merge branch 'drm-tda998x-3.12' of git://ftp.arm.linux.org.uk/~rmk/linux-cubox into drm-next

This adds support for the Armada 510 display subsystem found on the
Marvell Dove devices. This IP is re-used across several different Marvell
SoCs with various tweaks, and this driver has been structured to allow
the other IPs to re-use the bulk of this code; further work in this area
is expected from interested parties.

This has been extensively tested on the SolidRun Cubox platform and
appears to work well there.

[airlied: update for api changes merged previous to this]

+4318
+2
drivers/gpu/drm/Kconfig
··· 225 225 226 226 source "drivers/gpu/drm/cirrus/Kconfig" 227 227 228 + source "drivers/gpu/drm/armada/Kconfig" 229 + 228 230 source "drivers/gpu/drm/rcar-du/Kconfig" 229 231 230 232 source "drivers/gpu/drm/shmobile/Kconfig"
+1
drivers/gpu/drm/Makefile
··· 49 49 obj-$(CONFIG_DRM_GMA500) += gma500/ 50 50 obj-$(CONFIG_DRM_UDL) += udl/ 51 51 obj-$(CONFIG_DRM_AST) += ast/ 52 + obj-$(CONFIG_DRM_ARMADA) += armada/ 52 53 obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ 53 54 obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ 54 55 obj-$(CONFIG_DRM_OMAP) += omapdrm/
+24
drivers/gpu/drm/armada/Kconfig
··· 1 + config DRM_ARMADA 2 + tristate "DRM support for Marvell Armada SoCs" 3 + depends on DRM && HAVE_CLK 4 + select FB_CFB_FILLRECT 5 + select FB_CFB_COPYAREA 6 + select FB_CFB_IMAGEBLIT 7 + select DRM_KMS_HELPER 8 + help 9 + Support the "LCD" controllers found on the Marvell Armada 510 10 + devices. There are two controllers on the device, each controller 11 + supports graphics and video overlays. 12 + 13 + This driver provides no built-in acceleration; acceleration is 14 + performed by other IP found on the SoC. This driver provides 15 + kernel mode setting and buffer management to userspace. 16 + 17 + config DRM_ARMADA_TDA1998X 18 + bool "Support TDA1998X HDMI output" 19 + depends on DRM_ARMADA != n 20 + depends on I2C && DRM_I2C_NXP_TDA998X = y 21 + default y 22 + help 23 + Support the TDA1998x HDMI output device found on the Solid-Run 24 + CuBox.
+7
drivers/gpu/drm/armada/Makefile
··· 1 + armada-y := armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \ 2 + armada_gem.o armada_output.o armada_overlay.o \ 3 + armada_slave.o 4 + armada-y += armada_510.o 5 + armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o 6 + 7 + obj-$(CONFIG_DRM_ARMADA) := armada.o
+87
drivers/gpu/drm/armada/armada_510.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * Armada 510 (aka Dove) variant support 9 + */ 10 + #include <linux/clk.h> 11 + #include <linux/io.h> 12 + #include <drm/drmP.h> 13 + #include <drm/drm_crtc_helper.h> 14 + #include "armada_crtc.h" 15 + #include "armada_drm.h" 16 + #include "armada_hw.h" 17 + 18 + static int armada510_init(struct armada_private *priv, struct device *dev) 19 + { 20 + priv->extclk[0] = devm_clk_get(dev, "ext_ref_clk_1"); 21 + 22 + if (IS_ERR(priv->extclk[0]) && PTR_ERR(priv->extclk[0]) == -ENOENT) 23 + priv->extclk[0] = ERR_PTR(-EPROBE_DEFER); 24 + 25 + return PTR_RET(priv->extclk[0]); 26 + } 27 + 28 + static int armada510_crtc_init(struct armada_crtc *dcrtc) 29 + { 30 + /* Lower the watermark so to eliminate jitter at higher bandwidths */ 31 + armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); 32 + return 0; 33 + } 34 + 35 + /* 36 + * Armada510 specific SCLK register selection. 37 + * This gets called with sclk = NULL to test whether the mode is 38 + * supportable, and again with sclk != NULL to set the clocks up for 39 + * that. The former can return an error, but the latter is expected 40 + * not to. 41 + * 42 + * We currently are pretty rudimentary here, always selecting 43 + * EXT_REF_CLK_1 for LCD0 and erroring LCD1. This needs improvement! 44 + */ 45 + static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, 46 + const struct drm_display_mode *mode, uint32_t *sclk) 47 + { 48 + struct armada_private *priv = dcrtc->crtc.dev->dev_private; 49 + struct clk *clk = priv->extclk[0]; 50 + int ret; 51 + 52 + if (dcrtc->num == 1) 53 + return -EINVAL; 54 + 55 + if (IS_ERR(clk)) 56 + return PTR_ERR(clk); 57 + 58 + if (dcrtc->clk != clk) { 59 + ret = clk_prepare_enable(clk); 60 + if (ret) 61 + return ret; 62 + dcrtc->clk = clk; 63 + } 64 + 65 + if (sclk) { 66 + uint32_t rate, ref, div; 67 + 68 + rate = mode->clock * 1000; 69 + ref = clk_round_rate(clk, rate); 70 + div = DIV_ROUND_UP(ref, rate); 71 + if (div < 1) 72 + div = 1; 73 + 74 + clk_set_rate(clk, ref); 75 + *sclk = div | SCLK_510_EXTCLK1; 76 + } 77 + 78 + return 0; 79 + } 80 + 81 + const struct armada_variant armada510_ops = { 82 + .has_spu_adv_reg = true, 83 + .spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, 84 + .init = armada510_init, 85 + .crtc_init = armada510_crtc_init, 86 + .crtc_compute_clock = armada510_crtc_compute_clock, 87 + };
+1098
drivers/gpu/drm/armada/armada_crtc.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * Rewritten from the dovefb driver, and Armada510 manuals. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + #include <linux/clk.h> 10 + #include <drm/drmP.h> 11 + #include <drm/drm_crtc_helper.h> 12 + #include "armada_crtc.h" 13 + #include "armada_drm.h" 14 + #include "armada_fb.h" 15 + #include "armada_gem.h" 16 + #include "armada_hw.h" 17 + 18 + struct armada_frame_work { 19 + struct drm_pending_vblank_event *event; 20 + struct armada_regs regs[4]; 21 + struct drm_framebuffer *old_fb; 22 + }; 23 + 24 + enum csc_mode { 25 + CSC_AUTO = 0, 26 + CSC_YUV_CCIR601 = 1, 27 + CSC_YUV_CCIR709 = 2, 28 + CSC_RGB_COMPUTER = 1, 29 + CSC_RGB_STUDIO = 2, 30 + }; 31 + 32 + /* 33 + * A note about interlacing. Let's consider HDMI 1920x1080i. 34 + * The timing parameters we have from X are: 35 + * Hact HsyA HsyI Htot Vact VsyA VsyI Vtot 36 + * 1920 2448 2492 2640 1080 1084 1094 1125 37 + * Which get translated to: 38 + * Hact HsyA HsyI Htot Vact VsyA VsyI Vtot 39 + * 1920 2448 2492 2640 540 542 547 562 40 + * 41 + * This is how it is defined by CEA-861-D - line and pixel numbers are 42 + * referenced to the rising edge of VSYNC and HSYNC. Total clocks per 43 + * line: 2640. The odd frame, the first active line is at line 21, and 44 + * the even frame, the first active line is 584. 45 + * 46 + * LN: 560 561 562 563 567 568 569 47 + * DE: ~~~|____________________________//__________________________ 48 + * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____ 49 + * VSYNC: _________________________|~~~~~~//~~~~~~~~~~~~~~~|__________ 50 + * 22 blanking lines. VSYNC at 1320 (referenced to the HSYNC rising edge). 51 + * 52 + * LN: 1123 1124 1125 1 5 6 7 53 + * DE: ~~~|____________________________//__________________________ 54 + * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____ 55 + * VSYNC: ____________________|~~~~~~~~~~~//~~~~~~~~~~|_______________ 56 + * 23 blanking lines 57 + * 58 + * The Armada LCD Controller line and pixel numbers are, like X timings, 59 + * referenced to the top left of the active frame. 60 + * 61 + * So, translating these to our LCD controller: 62 + * Odd frame, 563 total lines, VSYNC at line 543-548, pixel 1128. 63 + * Even frame, 562 total lines, VSYNC at line 542-547, pixel 2448. 64 + * Note: Vsync front porch remains constant! 65 + * 66 + * if (odd_frame) { 67 + * vtotal = mode->crtc_vtotal + 1; 68 + * vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay + 1; 69 + * vhorizpos = mode->crtc_hsync_start - mode->crtc_htotal / 2 70 + * } else { 71 + * vtotal = mode->crtc_vtotal; 72 + * vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay; 73 + * vhorizpos = mode->crtc_hsync_start; 74 + * } 75 + * vfrontporch = mode->crtc_vtotal - mode->crtc_vsync_end; 76 + * 77 + * So, we need to reprogram these registers on each vsync event: 78 + * LCD_SPU_V_PORCH, LCD_SPU_ADV_REG, LCD_SPUT_V_H_TOTAL 79 + * 80 + * Note: we do not use the frame done interrupts because these appear 81 + * to happen too early, and lead to jitter on the display (presumably 82 + * they occur at the end of the last active line, before the vsync back 83 + * porch, which we're reprogramming.) 84 + */ 85 + 86 + void 87 + armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs) 88 + { 89 + while (regs->offset != ~0) { 90 + void __iomem *reg = dcrtc->base + regs->offset; 91 + uint32_t val; 92 + 93 + val = regs->mask; 94 + if (val != 0) 95 + val &= readl_relaxed(reg); 96 + writel_relaxed(val | regs->val, reg); 97 + ++regs; 98 + } 99 + } 100 + 101 + #define dpms_blanked(dpms) ((dpms) != DRM_MODE_DPMS_ON) 102 + 103 + static void armada_drm_crtc_update(struct armada_crtc *dcrtc) 104 + { 105 + uint32_t dumb_ctrl; 106 + 107 + dumb_ctrl = dcrtc->cfg_dumb_ctrl; 108 + 109 + if (!dpms_blanked(dcrtc->dpms)) 110 + dumb_ctrl |= CFG_DUMB_ENA; 111 + 112 + /* 113 + * When the dumb interface isn't in DUMB24_RGB888_0 mode, it might 114 + * be using SPI or GPIO. If we set this to DUMB_BLANK, we will 115 + * force LCD_D[23:0] to output blank color, overriding the GPIO or 116 + * SPI usage. So leave it as-is unless in DUMB24_RGB888_0 mode. 117 + */ 118 + if (dpms_blanked(dcrtc->dpms) && 119 + (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) { 120 + dumb_ctrl &= ~DUMB_MASK; 121 + dumb_ctrl |= DUMB_BLANK; 122 + } 123 + 124 + /* 125 + * The documentation doesn't indicate what the normal state of 126 + * the sync signals are. Sebastian Hesselbart kindly probed 127 + * these signals on his board to determine their state. 128 + * 129 + * The non-inverted state of the sync signals is active high. 130 + * Setting these bits makes the appropriate signal active low. 131 + */ 132 + if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NCSYNC) 133 + dumb_ctrl |= CFG_INV_CSYNC; 134 + if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NHSYNC) 135 + dumb_ctrl |= CFG_INV_HSYNC; 136 + if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NVSYNC) 137 + dumb_ctrl |= CFG_INV_VSYNC; 138 + 139 + if (dcrtc->dumb_ctrl != dumb_ctrl) { 140 + dcrtc->dumb_ctrl = dumb_ctrl; 141 + writel_relaxed(dumb_ctrl, dcrtc->base + LCD_SPU_DUMB_CTRL); 142 + } 143 + } 144 + 145 + static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, 146 + int x, int y, struct armada_regs *regs, bool interlaced) 147 + { 148 + struct armada_gem_object *obj = drm_fb_obj(fb); 149 + unsigned pitch = fb->pitches[0]; 150 + unsigned offset = y * pitch + x * fb->bits_per_pixel / 8; 151 + uint32_t addr_odd, addr_even; 152 + unsigned i = 0; 153 + 154 + DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n", 155 + pitch, x, y, fb->bits_per_pixel); 156 + 157 + addr_odd = addr_even = obj->dev_addr + offset; 158 + 159 + if (interlaced) { 160 + addr_even += pitch; 161 + pitch *= 2; 162 + } 163 + 164 + /* write offset, base, and pitch */ 165 + armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); 166 + armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); 167 + armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH); 168 + 169 + return i; 170 + } 171 + 172 + static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc, 173 + struct armada_frame_work *work) 174 + { 175 + struct drm_device *dev = dcrtc->crtc.dev; 176 + unsigned long flags; 177 + int ret; 178 + 179 + ret = drm_vblank_get(dev, dcrtc->num); 180 + if (ret) { 181 + DRM_ERROR("failed to acquire vblank counter\n"); 182 + return ret; 183 + } 184 + 185 + spin_lock_irqsave(&dev->event_lock, flags); 186 + if (!dcrtc->frame_work) 187 + dcrtc->frame_work = work; 188 + else 189 + ret = -EBUSY; 190 + spin_unlock_irqrestore(&dev->event_lock, flags); 191 + 192 + if (ret) 193 + drm_vblank_put(dev, dcrtc->num); 194 + 195 + return ret; 196 + } 197 + 198 + static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc) 199 + { 200 + struct drm_device *dev = dcrtc->crtc.dev; 201 + struct armada_frame_work *work = dcrtc->frame_work; 202 + 203 + dcrtc->frame_work = NULL; 204 + 205 + armada_drm_crtc_update_regs(dcrtc, work->regs); 206 + 207 + if (work->event) 208 + drm_send_vblank_event(dev, dcrtc->num, work->event); 209 + 210 + drm_vblank_put(dev, dcrtc->num); 211 + 212 + /* Finally, queue the process-half of the cleanup. */ 213 + __armada_drm_queue_unref_work(dcrtc->crtc.dev, work->old_fb); 214 + kfree(work); 215 + } 216 + 217 + static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, 218 + struct drm_framebuffer *fb, bool force) 219 + { 220 + struct armada_frame_work *work; 221 + 222 + if (!fb) 223 + return; 224 + 225 + if (force) { 226 + /* Display is disabled, so just drop the old fb */ 227 + drm_framebuffer_unreference(fb); 228 + return; 229 + } 230 + 231 + work = kmalloc(sizeof(*work), GFP_KERNEL); 232 + if (work) { 233 + int i = 0; 234 + work->event = NULL; 235 + work->old_fb = fb; 236 + armada_reg_queue_end(work->regs, i); 237 + 238 + if (armada_drm_crtc_queue_frame_work(dcrtc, work) == 0) 239 + return; 240 + 241 + kfree(work); 242 + } 243 + 244 + /* 245 + * Oops - just drop the reference immediately and hope for 246 + * the best. The worst that will happen is the buffer gets 247 + * reused before it has finished being displayed. 248 + */ 249 + drm_framebuffer_unreference(fb); 250 + } 251 + 252 + static void armada_drm_vblank_off(struct armada_crtc *dcrtc) 253 + { 254 + struct drm_device *dev = dcrtc->crtc.dev; 255 + 256 + /* 257 + * Tell the DRM core that vblank IRQs aren't going to happen for 258 + * a while. This cleans up any pending vblank events for us. 259 + */ 260 + drm_vblank_off(dev, dcrtc->num); 261 + 262 + /* Handle any pending flip event. */ 263 + spin_lock_irq(&dev->event_lock); 264 + if (dcrtc->frame_work) 265 + armada_drm_crtc_complete_frame_work(dcrtc); 266 + spin_unlock_irq(&dev->event_lock); 267 + } 268 + 269 + void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b, 270 + int idx) 271 + { 272 + } 273 + 274 + void armada_drm_crtc_gamma_get(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, 275 + int idx) 276 + { 277 + } 278 + 279 + /* The mode_config.mutex will be held for this call */ 280 + static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) 281 + { 282 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 283 + 284 + if (dcrtc->dpms != dpms) { 285 + dcrtc->dpms = dpms; 286 + armada_drm_crtc_update(dcrtc); 287 + if (dpms_blanked(dpms)) 288 + armada_drm_vblank_off(dcrtc); 289 + } 290 + } 291 + 292 + /* 293 + * Prepare for a mode set. Turn off overlay to ensure that we don't end 294 + * up with the overlay size being bigger than the active screen size. 295 + * We rely upon X refreshing this state after the mode set has completed. 296 + * 297 + * The mode_config.mutex will be held for this call 298 + */ 299 + static void armada_drm_crtc_prepare(struct drm_crtc *crtc) 300 + { 301 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 302 + struct drm_plane *plane; 303 + 304 + /* 305 + * If we have an overlay plane associated with this CRTC, disable 306 + * it before the modeset to avoid its coordinates being outside 307 + * the new mode parameters. DRM doesn't provide help with this. 308 + */ 309 + plane = dcrtc->plane; 310 + if (plane) { 311 + struct drm_framebuffer *fb = plane->fb; 312 + 313 + plane->funcs->disable_plane(plane); 314 + plane->fb = NULL; 315 + plane->crtc = NULL; 316 + drm_framebuffer_unreference(fb); 317 + } 318 + } 319 + 320 + /* The mode_config.mutex will be held for this call */ 321 + static void armada_drm_crtc_commit(struct drm_crtc *crtc) 322 + { 323 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 324 + 325 + if (dcrtc->dpms != DRM_MODE_DPMS_ON) { 326 + dcrtc->dpms = DRM_MODE_DPMS_ON; 327 + armada_drm_crtc_update(dcrtc); 328 + } 329 + } 330 + 331 + /* The mode_config.mutex will be held for this call */ 332 + static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, 333 + const struct drm_display_mode *mode, struct drm_display_mode *adj) 334 + { 335 + struct armada_private *priv = crtc->dev->dev_private; 336 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 337 + int ret; 338 + 339 + /* We can't do interlaced modes if we don't have the SPU_ADV_REG */ 340 + if (!priv->variant->has_spu_adv_reg && 341 + adj->flags & DRM_MODE_FLAG_INTERLACE) 342 + return false; 343 + 344 + /* Check whether the display mode is possible */ 345 + ret = priv->variant->crtc_compute_clock(dcrtc, adj, NULL); 346 + if (ret) 347 + return false; 348 + 349 + return true; 350 + } 351 + 352 + void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) 353 + { 354 + struct armada_vbl_event *e, *n; 355 + void __iomem *base = dcrtc->base; 356 + 357 + if (stat & DMA_FF_UNDERFLOW) 358 + DRM_ERROR("video underflow on crtc %u\n", dcrtc->num); 359 + if (stat & GRA_FF_UNDERFLOW) 360 + DRM_ERROR("graphics underflow on crtc %u\n", dcrtc->num); 361 + 362 + if (stat & VSYNC_IRQ) 363 + drm_handle_vblank(dcrtc->crtc.dev, dcrtc->num); 364 + 365 + spin_lock(&dcrtc->irq_lock); 366 + 367 + list_for_each_entry_safe(e, n, &dcrtc->vbl_list, node) { 368 + list_del_init(&e->node); 369 + drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); 370 + e->fn(dcrtc, e->data); 371 + } 372 + 373 + if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) { 374 + int i = stat & GRA_FRAME_IRQ0 ? 0 : 1; 375 + uint32_t val; 376 + 377 + writel_relaxed(dcrtc->v[i].spu_v_porch, base + LCD_SPU_V_PORCH); 378 + writel_relaxed(dcrtc->v[i].spu_v_h_total, 379 + base + LCD_SPUT_V_H_TOTAL); 380 + 381 + val = readl_relaxed(base + LCD_SPU_ADV_REG); 382 + val &= ~(ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN); 383 + val |= dcrtc->v[i].spu_adv_reg; 384 + writel_relaxed(val, base + LCD_SPU_ADV_REG); 385 + } 386 + 387 + if (stat & DUMB_FRAMEDONE && dcrtc->cursor_update) { 388 + writel_relaxed(dcrtc->cursor_hw_pos, 389 + base + LCD_SPU_HWC_OVSA_HPXL_VLN); 390 + writel_relaxed(dcrtc->cursor_hw_sz, 391 + base + LCD_SPU_HWC_HPXL_VLN); 392 + armada_updatel(CFG_HWC_ENA, 393 + CFG_HWC_ENA | CFG_HWC_1BITMOD | CFG_HWC_1BITENA, 394 + base + LCD_SPU_DMA_CTRL0); 395 + dcrtc->cursor_update = false; 396 + armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); 397 + } 398 + 399 + spin_unlock(&dcrtc->irq_lock); 400 + 401 + if (stat & GRA_FRAME_IRQ) { 402 + struct drm_device *dev = dcrtc->crtc.dev; 403 + 404 + spin_lock(&dev->event_lock); 405 + if (dcrtc->frame_work) 406 + armada_drm_crtc_complete_frame_work(dcrtc); 407 + spin_unlock(&dev->event_lock); 408 + 409 + wake_up(&dcrtc->frame_wait); 410 + } 411 + } 412 + 413 + /* These are locked by dev->vbl_lock */ 414 + void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask) 415 + { 416 + if (dcrtc->irq_ena & mask) { 417 + dcrtc->irq_ena &= ~mask; 418 + writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); 419 + } 420 + } 421 + 422 + void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask) 423 + { 424 + if ((dcrtc->irq_ena & mask) != mask) { 425 + dcrtc->irq_ena |= mask; 426 + writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); 427 + if (readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR) & mask) 428 + writel(0, dcrtc->base + LCD_SPU_IRQ_ISR); 429 + } 430 + } 431 + 432 + static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) 433 + { 434 + struct drm_display_mode *adj = &dcrtc->crtc.mode; 435 + uint32_t val = 0; 436 + 437 + if (dcrtc->csc_yuv_mode == CSC_YUV_CCIR709) 438 + val |= CFG_CSC_YUV_CCIR709; 439 + if (dcrtc->csc_rgb_mode == CSC_RGB_STUDIO) 440 + val |= CFG_CSC_RGB_STUDIO; 441 + 442 + /* 443 + * In auto mode, set the colorimetry, based upon the HDMI spec. 444 + * 1280x720p, 1920x1080p and 1920x1080i use ITU709, others use 445 + * ITU601. It may be more appropriate to set this depending on 446 + * the source - but what if the graphic frame is YUV and the 447 + * video frame is RGB? 448 + */ 449 + if ((adj->hdisplay == 1280 && adj->vdisplay == 720 && 450 + !(adj->flags & DRM_MODE_FLAG_INTERLACE)) || 451 + (adj->hdisplay == 1920 && adj->vdisplay == 1080)) { 452 + if (dcrtc->csc_yuv_mode == CSC_AUTO) 453 + val |= CFG_CSC_YUV_CCIR709; 454 + } 455 + 456 + /* 457 + * We assume we're connected to a TV-like device, so the YUV->RGB 458 + * conversion should produce a limited range. We should set this 459 + * depending on the connectors attached to this CRTC, and what 460 + * kind of device they report being connected. 461 + */ 462 + if (dcrtc->csc_rgb_mode == CSC_AUTO) 463 + val |= CFG_CSC_RGB_STUDIO; 464 + 465 + return val; 466 + } 467 + 468 + /* The mode_config.mutex will be held for this call */ 469 + static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, 470 + struct drm_display_mode *mode, struct drm_display_mode *adj, 471 + int x, int y, struct drm_framebuffer *old_fb) 472 + { 473 + struct armada_private *priv = crtc->dev->dev_private; 474 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 475 + struct armada_regs regs[17]; 476 + uint32_t lm, rm, tm, bm, val, sclk; 477 + unsigned long flags; 478 + unsigned i; 479 + bool interlaced; 480 + 481 + drm_framebuffer_reference(crtc->fb); 482 + 483 + interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); 484 + 485 + i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced); 486 + 487 + rm = adj->crtc_hsync_start - adj->crtc_hdisplay; 488 + lm = adj->crtc_htotal - adj->crtc_hsync_end; 489 + bm = adj->crtc_vsync_start - adj->crtc_vdisplay; 490 + tm = adj->crtc_vtotal - adj->crtc_vsync_end; 491 + 492 + DRM_DEBUG_DRIVER("H: %d %d %d %d lm %d rm %d\n", 493 + adj->crtc_hdisplay, 494 + adj->crtc_hsync_start, 495 + adj->crtc_hsync_end, 496 + adj->crtc_htotal, lm, rm); 497 + DRM_DEBUG_DRIVER("V: %d %d %d %d tm %d bm %d\n", 498 + adj->crtc_vdisplay, 499 + adj->crtc_vsync_start, 500 + adj->crtc_vsync_end, 501 + adj->crtc_vtotal, tm, bm); 502 + 503 + /* Wait for pending flips to complete */ 504 + wait_event(dcrtc->frame_wait, !dcrtc->frame_work); 505 + 506 + drm_vblank_pre_modeset(crtc->dev, dcrtc->num); 507 + 508 + crtc->mode = *adj; 509 + 510 + val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA; 511 + if (val != dcrtc->dumb_ctrl) { 512 + dcrtc->dumb_ctrl = val; 513 + writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); 514 + } 515 + 516 + /* Now compute the divider for real */ 517 + priv->variant->crtc_compute_clock(dcrtc, adj, &sclk); 518 + 519 + /* Ensure graphic fifo is enabled */ 520 + armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); 521 + armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV); 522 + 523 + if (interlaced ^ dcrtc->interlaced) { 524 + if (adj->flags & DRM_MODE_FLAG_INTERLACE) 525 + drm_vblank_get(dcrtc->crtc.dev, dcrtc->num); 526 + else 527 + drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); 528 + dcrtc->interlaced = interlaced; 529 + } 530 + 531 + spin_lock_irqsave(&dcrtc->irq_lock, flags); 532 + 533 + /* Even interlaced/progressive frame */ 534 + dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 | 535 + adj->crtc_htotal; 536 + dcrtc->v[1].spu_v_porch = tm << 16 | bm; 537 + val = adj->crtc_hsync_start; 538 + dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | 539 + priv->variant->spu_adv_reg; 540 + 541 + if (interlaced) { 542 + /* Odd interlaced frame */ 543 + dcrtc->v[0].spu_v_h_total = dcrtc->v[1].spu_v_h_total + 544 + (1 << 16); 545 + dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; 546 + val = adj->crtc_hsync_start - adj->crtc_htotal / 2; 547 + dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | 548 + priv->variant->spu_adv_reg; 549 + } else { 550 + dcrtc->v[0] = dcrtc->v[1]; 551 + } 552 + 553 + val = adj->crtc_vdisplay << 16 | adj->crtc_hdisplay; 554 + 555 + armada_reg_queue_set(regs, i, val, LCD_SPU_V_H_ACTIVE); 556 + armada_reg_queue_set(regs, i, val, LCD_SPU_GRA_HPXL_VLN); 557 + armada_reg_queue_set(regs, i, val, LCD_SPU_GZM_HPXL_VLN); 558 + armada_reg_queue_set(regs, i, (lm << 16) | rm, LCD_SPU_H_PORCH); 559 + armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_porch, LCD_SPU_V_PORCH); 560 + armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, 561 + LCD_SPUT_V_H_TOTAL); 562 + 563 + if (priv->variant->has_spu_adv_reg) { 564 + armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, 565 + ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | 566 + ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); 567 + } 568 + 569 + val = CFG_GRA_ENA | CFG_GRA_HSMOOTH; 570 + val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt); 571 + val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod); 572 + 573 + if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420) 574 + val |= CFG_PALETTE_ENA; 575 + 576 + if (interlaced) 577 + val |= CFG_GRA_FTOGGLE; 578 + 579 + armada_reg_queue_mod(regs, i, val, CFG_GRAFORMAT | 580 + CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | 581 + CFG_SWAPYU | CFG_YUV2RGB) | 582 + CFG_PALETTE_ENA | CFG_GRA_FTOGGLE, 583 + LCD_SPU_DMA_CTRL0); 584 + 585 + val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; 586 + armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); 587 + 588 + val = dcrtc->spu_iopad_ctrl | armada_drm_crtc_calculate_csc(dcrtc); 589 + armada_reg_queue_set(regs, i, val, LCD_SPU_IOPAD_CONTROL); 590 + armada_reg_queue_end(regs, i); 591 + 592 + armada_drm_crtc_update_regs(dcrtc, regs); 593 + spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 594 + 595 + armada_drm_crtc_update(dcrtc); 596 + 597 + drm_vblank_post_modeset(crtc->dev, dcrtc->num); 598 + armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); 599 + 600 + return 0; 601 + } 602 + 603 + /* The mode_config.mutex will be held for this call */ 604 + static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 605 + struct drm_framebuffer *old_fb) 606 + { 607 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 608 + struct armada_regs regs[4]; 609 + unsigned i; 610 + 611 + i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs, 612 + dcrtc->interlaced); 613 + armada_reg_queue_end(regs, i); 614 + 615 + /* Wait for pending flips to complete */ 616 + wait_event(dcrtc->frame_wait, !dcrtc->frame_work); 617 + 618 + /* Take a reference to the new fb as we're using it */ 619 + drm_framebuffer_reference(crtc->fb); 620 + 621 + /* Update the base in the CRTC */ 622 + armada_drm_crtc_update_regs(dcrtc, regs); 623 + 624 + /* Drop our previously held reference */ 625 + armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); 626 + 627 + return 0; 628 + } 629 + 630 + static void armada_drm_crtc_load_lut(struct drm_crtc *crtc) 631 + { 632 + } 633 + 634 + /* The mode_config.mutex will be held for this call */ 635 + static void armada_drm_crtc_disable(struct drm_crtc *crtc) 636 + { 637 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 638 + 639 + armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 640 + armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true); 641 + 642 + /* Power down most RAMs and FIFOs */ 643 + writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | 644 + CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 | 645 + CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); 646 + } 647 + 648 + static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { 649 + .dpms = armada_drm_crtc_dpms, 650 + .prepare = armada_drm_crtc_prepare, 651 + .commit = armada_drm_crtc_commit, 652 + .mode_fixup = armada_drm_crtc_mode_fixup, 653 + .mode_set = armada_drm_crtc_mode_set, 654 + .mode_set_base = armada_drm_crtc_mode_set_base, 655 + .load_lut = armada_drm_crtc_load_lut, 656 + .disable = armada_drm_crtc_disable, 657 + }; 658 + 659 + static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix, 660 + unsigned stride, unsigned width, unsigned height) 661 + { 662 + uint32_t addr; 663 + unsigned y; 664 + 665 + addr = SRAM_HWC32_RAM1; 666 + for (y = 0; y < height; y++) { 667 + uint32_t *p = &pix[y * stride]; 668 + unsigned x; 669 + 670 + for (x = 0; x < width; x++, p++) { 671 + uint32_t val = *p; 672 + 673 + val = (val & 0xff00ff00) | 674 + (val & 0x000000ff) << 16 | 675 + (val & 0x00ff0000) >> 16; 676 + 677 + writel_relaxed(val, 678 + base + LCD_SPU_SRAM_WRDAT); 679 + writel_relaxed(addr | SRAM_WRITE, 680 + base + LCD_SPU_SRAM_CTRL); 681 + addr += 1; 682 + if ((addr & 0x00ff) == 0) 683 + addr += 0xf00; 684 + if ((addr & 0x30ff) == 0) 685 + addr = SRAM_HWC32_RAM2; 686 + } 687 + } 688 + } 689 + 690 + static void armada_drm_crtc_cursor_tran(void __iomem *base) 691 + { 692 + unsigned addr; 693 + 694 + for (addr = 0; addr < 256; addr++) { 695 + /* write the default value */ 696 + writel_relaxed(0x55555555, base + LCD_SPU_SRAM_WRDAT); 697 + writel_relaxed(addr | SRAM_WRITE | SRAM_HWC32_TRAN, 698 + base + LCD_SPU_SRAM_CTRL); 699 + } 700 + } 701 + 702 + static int armada_drm_crtc_cursor_update(struct armada_crtc *dcrtc, bool reload) 703 + { 704 + uint32_t xoff, xscr, w = dcrtc->cursor_w, s; 705 + uint32_t yoff, yscr, h = dcrtc->cursor_h; 706 + uint32_t para1; 707 + 708 + /* 709 + * Calculate the visible width and height of the cursor, 710 + * screen position, and the position in the cursor bitmap. 711 + */ 712 + if (dcrtc->cursor_x < 0) { 713 + xoff = -dcrtc->cursor_x; 714 + xscr = 0; 715 + w -= min(xoff, w); 716 + } else if (dcrtc->cursor_x + w > dcrtc->crtc.mode.hdisplay) { 717 + xoff = 0; 718 + xscr = dcrtc->cursor_x; 719 + w = max_t(int, dcrtc->crtc.mode.hdisplay - dcrtc->cursor_x, 0); 720 + } else { 721 + xoff = 0; 722 + xscr = dcrtc->cursor_x; 723 + } 724 + 725 + if (dcrtc->cursor_y < 0) { 726 + yoff = -dcrtc->cursor_y; 727 + yscr = 0; 728 + h -= min(yoff, h); 729 + } else if (dcrtc->cursor_y + h > dcrtc->crtc.mode.vdisplay) { 730 + yoff = 0; 731 + yscr = dcrtc->cursor_y; 732 + h = max_t(int, dcrtc->crtc.mode.vdisplay - dcrtc->cursor_y, 0); 733 + } else { 734 + yoff = 0; 735 + yscr = dcrtc->cursor_y; 736 + } 737 + 738 + /* On interlaced modes, the vertical cursor size must be halved */ 739 + s = dcrtc->cursor_w; 740 + if (dcrtc->interlaced) { 741 + s *= 2; 742 + yscr /= 2; 743 + h /= 2; 744 + } 745 + 746 + if (!dcrtc->cursor_obj || !h || !w) { 747 + spin_lock_irq(&dcrtc->irq_lock); 748 + armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); 749 + dcrtc->cursor_update = false; 750 + armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0); 751 + spin_unlock_irq(&dcrtc->irq_lock); 752 + return 0; 753 + } 754 + 755 + para1 = readl_relaxed(dcrtc->base + LCD_SPU_SRAM_PARA1); 756 + armada_updatel(CFG_CSB_256x32, CFG_CSB_256x32 | CFG_PDWN256x32, 757 + dcrtc->base + LCD_SPU_SRAM_PARA1); 758 + 759 + /* 760 + * Initialize the transparency if the SRAM was powered down. 761 + * We must also reload the cursor data as well. 762 + */ 763 + if (!(para1 & CFG_CSB_256x32)) { 764 + armada_drm_crtc_cursor_tran(dcrtc->base); 765 + reload = true; 766 + } 767 + 768 + if (dcrtc->cursor_hw_sz != (h << 16 | w)) { 769 + spin_lock_irq(&dcrtc->irq_lock); 770 + armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); 771 + dcrtc->cursor_update = false; 772 + armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0); 773 + spin_unlock_irq(&dcrtc->irq_lock); 774 + reload = true; 775 + } 776 + if (reload) { 777 + struct armada_gem_object *obj = dcrtc->cursor_obj; 778 + uint32_t *pix; 779 + /* Set the top-left corner of the cursor image */ 780 + pix = obj->addr; 781 + pix += yoff * s + xoff; 782 + armada_load_cursor_argb(dcrtc->base, pix, s, w, h); 783 + } 784 + 785 + /* Reload the cursor position, size and enable in the IRQ handler */ 786 + spin_lock_irq(&dcrtc->irq_lock); 787 + dcrtc->cursor_hw_pos = yscr << 16 | xscr; 788 + dcrtc->cursor_hw_sz = h << 16 | w; 789 + dcrtc->cursor_update = true; 790 + armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA); 791 + spin_unlock_irq(&dcrtc->irq_lock); 792 + 793 + return 0; 794 + } 795 + 796 + static void cursor_update(void *data) 797 + { 798 + armada_drm_crtc_cursor_update(data, true); 799 + } 800 + 801 + static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc, 802 + struct drm_file *file, uint32_t handle, uint32_t w, uint32_t h) 803 + { 804 + struct drm_device *dev = crtc->dev; 805 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 806 + struct armada_private *priv = crtc->dev->dev_private; 807 + struct armada_gem_object *obj = NULL; 808 + int ret; 809 + 810 + /* If no cursor support, replicate drm's return value */ 811 + if (!priv->variant->has_spu_adv_reg) 812 + return -ENXIO; 813 + 814 + if (handle && w > 0 && h > 0) { 815 + /* maximum size is 64x32 or 32x64 */ 816 + if (w > 64 || h > 64 || (w > 32 && h > 32)) 817 + return -ENOMEM; 818 + 819 + obj = armada_gem_object_lookup(dev, file, handle); 820 + if (!obj) 821 + return -ENOENT; 822 + 823 + /* Must be a kernel-mapped object */ 824 + if (!obj->addr) { 825 + drm_gem_object_unreference_unlocked(&obj->obj); 826 + return -EINVAL; 827 + } 828 + 829 + if (obj->obj.size < w * h * 4) { 830 + DRM_ERROR("buffer is too small\n"); 831 + drm_gem_object_unreference_unlocked(&obj->obj); 832 + return -ENOMEM; 833 + } 834 + } 835 + 836 + mutex_lock(&dev->struct_mutex); 837 + if (dcrtc->cursor_obj) { 838 + dcrtc->cursor_obj->update = NULL; 839 + dcrtc->cursor_obj->update_data = NULL; 840 + drm_gem_object_unreference(&dcrtc->cursor_obj->obj); 841 + } 842 + dcrtc->cursor_obj = obj; 843 + dcrtc->cursor_w = w; 844 + dcrtc->cursor_h = h; 845 + ret = armada_drm_crtc_cursor_update(dcrtc, true); 846 + if (obj) { 847 + obj->update_data = dcrtc; 848 + obj->update = cursor_update; 849 + } 850 + mutex_unlock(&dev->struct_mutex); 851 + 852 + return ret; 853 + } 854 + 855 + static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) 856 + { 857 + struct drm_device *dev = crtc->dev; 858 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 859 + struct armada_private *priv = crtc->dev->dev_private; 860 + int ret; 861 + 862 + /* If no cursor support, replicate drm's return value */ 863 + if (!priv->variant->has_spu_adv_reg) 864 + return -EFAULT; 865 + 866 + mutex_lock(&dev->struct_mutex); 867 + dcrtc->cursor_x = x; 868 + dcrtc->cursor_y = y; 869 + ret = armada_drm_crtc_cursor_update(dcrtc, false); 870 + mutex_unlock(&dev->struct_mutex); 871 + 872 + return ret; 873 + } 874 + 875 + static void armada_drm_crtc_destroy(struct drm_crtc *crtc) 876 + { 877 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 878 + struct armada_private *priv = crtc->dev->dev_private; 879 + 880 + if (dcrtc->cursor_obj) 881 + drm_gem_object_unreference(&dcrtc->cursor_obj->obj); 882 + 883 + priv->dcrtc[dcrtc->num] = NULL; 884 + drm_crtc_cleanup(&dcrtc->crtc); 885 + 886 + if (!IS_ERR(dcrtc->clk)) 887 + clk_disable_unprepare(dcrtc->clk); 888 + 889 + kfree(dcrtc); 890 + } 891 + 892 + /* 893 + * The mode_config lock is held here, to prevent races between this 894 + * and a mode_set. 895 + */ 896 + static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, 897 + struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags) 898 + { 899 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 900 + struct armada_frame_work *work; 901 + struct drm_device *dev = crtc->dev; 902 + unsigned long flags; 903 + unsigned i; 904 + int ret; 905 + 906 + /* We don't support changing the pixel format */ 907 + if (fb->pixel_format != crtc->fb->pixel_format) 908 + return -EINVAL; 909 + 910 + work = kmalloc(sizeof(*work), GFP_KERNEL); 911 + if (!work) 912 + return -ENOMEM; 913 + 914 + work->event = event; 915 + work->old_fb = dcrtc->crtc.fb; 916 + 917 + i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs, 918 + dcrtc->interlaced); 919 + armada_reg_queue_end(work->regs, i); 920 + 921 + /* 922 + * Hold the old framebuffer for the work - DRM appears to drop our 923 + * reference to the old framebuffer in drm_mode_page_flip_ioctl(). 924 + */ 925 + drm_framebuffer_reference(work->old_fb); 926 + 927 + ret = armada_drm_crtc_queue_frame_work(dcrtc, work); 928 + if (ret) { 929 + /* 930 + * Undo our reference above; DRM does not drop the reference 931 + * to this object on error, so that's okay. 932 + */ 933 + drm_framebuffer_unreference(work->old_fb); 934 + kfree(work); 935 + return ret; 936 + } 937 + 938 + /* 939 + * Don't take a reference on the new framebuffer; 940 + * drm_mode_page_flip_ioctl() has already grabbed a reference and 941 + * will _not_ drop that reference on successful return from this 942 + * function. Simply mark this new framebuffer as the current one. 943 + */ 944 + dcrtc->crtc.fb = fb; 945 + 946 + /* 947 + * Finally, if the display is blanked, we won't receive an 948 + * interrupt, so complete it now. 949 + */ 950 + if (dpms_blanked(dcrtc->dpms)) { 951 + spin_lock_irqsave(&dev->event_lock, flags); 952 + if (dcrtc->frame_work) 953 + armada_drm_crtc_complete_frame_work(dcrtc); 954 + spin_unlock_irqrestore(&dev->event_lock, flags); 955 + } 956 + 957 + return 0; 958 + } 959 + 960 + static int 961 + armada_drm_crtc_set_property(struct drm_crtc *crtc, 962 + struct drm_property *property, uint64_t val) 963 + { 964 + struct armada_private *priv = crtc->dev->dev_private; 965 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 966 + bool update_csc = false; 967 + 968 + if (property == priv->csc_yuv_prop) { 969 + dcrtc->csc_yuv_mode = val; 970 + update_csc = true; 971 + } else if (property == priv->csc_rgb_prop) { 972 + dcrtc->csc_rgb_mode = val; 973 + update_csc = true; 974 + } 975 + 976 + if (update_csc) { 977 + uint32_t val; 978 + 979 + val = dcrtc->spu_iopad_ctrl | 980 + armada_drm_crtc_calculate_csc(dcrtc); 981 + writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL); 982 + } 983 + 984 + return 0; 985 + } 986 + 987 + static struct drm_crtc_funcs armada_crtc_funcs = { 988 + .cursor_set = armada_drm_crtc_cursor_set, 989 + .cursor_move = armada_drm_crtc_cursor_move, 990 + .destroy = armada_drm_crtc_destroy, 991 + .set_config = drm_crtc_helper_set_config, 992 + .page_flip = armada_drm_crtc_page_flip, 993 + .set_property = armada_drm_crtc_set_property, 994 + }; 995 + 996 + static struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = { 997 + { CSC_AUTO, "Auto" }, 998 + { CSC_YUV_CCIR601, "CCIR601" }, 999 + { CSC_YUV_CCIR709, "CCIR709" }, 1000 + }; 1001 + 1002 + static struct drm_prop_enum_list armada_drm_csc_rgb_enum_list[] = { 1003 + { CSC_AUTO, "Auto" }, 1004 + { CSC_RGB_COMPUTER, "Computer system" }, 1005 + { CSC_RGB_STUDIO, "Studio" }, 1006 + }; 1007 + 1008 + static int armada_drm_crtc_create_properties(struct drm_device *dev) 1009 + { 1010 + struct armada_private *priv = dev->dev_private; 1011 + 1012 + if (priv->csc_yuv_prop) 1013 + return 0; 1014 + 1015 + priv->csc_yuv_prop = drm_property_create_enum(dev, 0, 1016 + "CSC_YUV", armada_drm_csc_yuv_enum_list, 1017 + ARRAY_SIZE(armada_drm_csc_yuv_enum_list)); 1018 + priv->csc_rgb_prop = drm_property_create_enum(dev, 0, 1019 + "CSC_RGB", armada_drm_csc_rgb_enum_list, 1020 + ARRAY_SIZE(armada_drm_csc_rgb_enum_list)); 1021 + 1022 + if (!priv->csc_yuv_prop || !priv->csc_rgb_prop) 1023 + return -ENOMEM; 1024 + 1025 + return 0; 1026 + } 1027 + 1028 + int armada_drm_crtc_create(struct drm_device *dev, unsigned num, 1029 + struct resource *res) 1030 + { 1031 + struct armada_private *priv = dev->dev_private; 1032 + struct armada_crtc *dcrtc; 1033 + void __iomem *base; 1034 + int ret; 1035 + 1036 + ret = armada_drm_crtc_create_properties(dev); 1037 + if (ret) 1038 + return ret; 1039 + 1040 + base = devm_request_and_ioremap(dev->dev, res); 1041 + if (!base) { 1042 + DRM_ERROR("failed to ioremap register\n"); 1043 + return -ENOMEM; 1044 + } 1045 + 1046 + dcrtc = kzalloc(sizeof(*dcrtc), GFP_KERNEL); 1047 + if (!dcrtc) { 1048 + DRM_ERROR("failed to allocate Armada crtc\n"); 1049 + return -ENOMEM; 1050 + } 1051 + 1052 + dcrtc->base = base; 1053 + dcrtc->num = num; 1054 + dcrtc->clk = ERR_PTR(-EINVAL); 1055 + dcrtc->csc_yuv_mode = CSC_AUTO; 1056 + dcrtc->csc_rgb_mode = CSC_AUTO; 1057 + dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0; 1058 + dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24; 1059 + spin_lock_init(&dcrtc->irq_lock); 1060 + dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR; 1061 + INIT_LIST_HEAD(&dcrtc->vbl_list); 1062 + init_waitqueue_head(&dcrtc->frame_wait); 1063 + 1064 + /* Initialize some registers which we don't otherwise set */ 1065 + writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV); 1066 + writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_BLANKCOLOR); 1067 + writel_relaxed(dcrtc->spu_iopad_ctrl, 1068 + dcrtc->base + LCD_SPU_IOPAD_CONTROL); 1069 + writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_SRAM_PARA0); 1070 + writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | 1071 + CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 | 1072 + CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); 1073 + writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1); 1074 + writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN); 1075 + 1076 + if (priv->variant->crtc_init) { 1077 + ret = priv->variant->crtc_init(dcrtc); 1078 + if (ret) { 1079 + kfree(dcrtc); 1080 + return ret; 1081 + } 1082 + } 1083 + 1084 + /* Ensure AXI pipeline is enabled */ 1085 + armada_updatel(CFG_ARBFAST_ENA, 0, dcrtc->base + LCD_SPU_DMA_CTRL0); 1086 + 1087 + priv->dcrtc[dcrtc->num] = dcrtc; 1088 + 1089 + drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs); 1090 + drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); 1091 + 1092 + drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop, 1093 + dcrtc->csc_yuv_mode); 1094 + drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop, 1095 + dcrtc->csc_rgb_mode); 1096 + 1097 + return armada_overlay_plane_create(dev, 1 << dcrtc->num); 1098 + }
+83
drivers/gpu/drm/armada/armada_crtc.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #ifndef ARMADA_CRTC_H 9 + #define ARMADA_CRTC_H 10 + 11 + struct armada_gem_object; 12 + 13 + struct armada_regs { 14 + uint32_t offset; 15 + uint32_t mask; 16 + uint32_t val; 17 + }; 18 + 19 + #define armada_reg_queue_mod(_r, _i, _v, _m, _o) \ 20 + do { \ 21 + struct armada_regs *__reg = _r; \ 22 + __reg[_i].offset = _o; \ 23 + __reg[_i].mask = ~(_m); \ 24 + __reg[_i].val = _v; \ 25 + _i++; \ 26 + } while (0) 27 + 28 + #define armada_reg_queue_set(_r, _i, _v, _o) \ 29 + armada_reg_queue_mod(_r, _i, _v, ~0, _o) 30 + 31 + #define armada_reg_queue_end(_r, _i) \ 32 + armada_reg_queue_mod(_r, _i, 0, 0, ~0) 33 + 34 + struct armada_frame_work; 35 + 36 + struct armada_crtc { 37 + struct drm_crtc crtc; 38 + unsigned num; 39 + void __iomem *base; 40 + struct clk *clk; 41 + struct { 42 + uint32_t spu_v_h_total; 43 + uint32_t spu_v_porch; 44 + uint32_t spu_adv_reg; 45 + } v[2]; 46 + bool interlaced; 47 + bool cursor_update; 48 + uint8_t csc_yuv_mode; 49 + uint8_t csc_rgb_mode; 50 + 51 + struct drm_plane *plane; 52 + 53 + struct armada_gem_object *cursor_obj; 54 + int cursor_x; 55 + int cursor_y; 56 + uint32_t cursor_hw_pos; 57 + uint32_t cursor_hw_sz; 58 + uint32_t cursor_w; 59 + uint32_t cursor_h; 60 + 61 + int dpms; 62 + uint32_t cfg_dumb_ctrl; 63 + uint32_t dumb_ctrl; 64 + uint32_t spu_iopad_ctrl; 65 + 66 + wait_queue_head_t frame_wait; 67 + struct armada_frame_work *frame_work; 68 + 69 + spinlock_t irq_lock; 70 + uint32_t irq_ena; 71 + struct list_head vbl_list; 72 + }; 73 + #define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc) 74 + 75 + int armada_drm_crtc_create(struct drm_device *, unsigned, struct resource *); 76 + void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int); 77 + void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int); 78 + void armada_drm_crtc_irq(struct armada_crtc *, u32); 79 + void armada_drm_crtc_disable_irq(struct armada_crtc *, u32); 80 + void armada_drm_crtc_enable_irq(struct armada_crtc *, u32); 81 + void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); 82 + 83 + #endif
+183
drivers/gpu/drm/armada/armada_debugfs.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * Rewritten from the dovefb driver, and Armada510 manuals. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + #include <linux/ctype.h> 10 + #include <linux/debugfs.h> 11 + #include <linux/module.h> 12 + #include <linux/seq_file.h> 13 + #include <drm/drmP.h> 14 + #include "armada_crtc.h" 15 + #include "armada_drm.h" 16 + 17 + static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data) 18 + { 19 + struct drm_info_node *node = m->private; 20 + struct drm_device *dev = node->minor->dev; 21 + struct armada_private *priv = dev->dev_private; 22 + int ret; 23 + 24 + mutex_lock(&dev->struct_mutex); 25 + ret = drm_mm_dump_table(m, &priv->linear); 26 + mutex_unlock(&dev->struct_mutex); 27 + 28 + return ret; 29 + } 30 + 31 + static int armada_debugfs_reg_show(struct seq_file *m, void *data) 32 + { 33 + struct drm_device *dev = m->private; 34 + struct armada_private *priv = dev->dev_private; 35 + int n, i; 36 + 37 + if (priv) { 38 + for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { 39 + struct armada_crtc *dcrtc = priv->dcrtc[n]; 40 + if (!dcrtc) 41 + continue; 42 + 43 + for (i = 0x84; i <= 0x1c4; i += 4) { 44 + uint32_t v = readl_relaxed(dcrtc->base + i); 45 + seq_printf(m, "%u: 0x%04x: 0x%08x\n", n, i, v); 46 + } 47 + } 48 + } 49 + 50 + return 0; 51 + } 52 + 53 + static int armada_debugfs_reg_r_open(struct inode *inode, struct file *file) 54 + { 55 + return single_open(file, armada_debugfs_reg_show, inode->i_private); 56 + } 57 + 58 + static const struct file_operations fops_reg_r = { 59 + .owner = THIS_MODULE, 60 + .open = armada_debugfs_reg_r_open, 61 + .read = seq_read, 62 + .llseek = seq_lseek, 63 + .release = single_release, 64 + }; 65 + 66 + static int armada_debugfs_write(struct file *file, const char __user *ptr, 67 + size_t len, loff_t *off) 68 + { 69 + struct drm_device *dev = file->private_data; 70 + struct armada_private *priv = dev->dev_private; 71 + struct armada_crtc *dcrtc = priv->dcrtc[0]; 72 + char buf[32], *p; 73 + uint32_t reg, val; 74 + int ret; 75 + 76 + if (*off != 0) 77 + return 0; 78 + 79 + if (len > sizeof(buf) - 1) 80 + len = sizeof(buf) - 1; 81 + 82 + ret = strncpy_from_user(buf, ptr, len); 83 + if (ret < 0) 84 + return ret; 85 + buf[len] = '\0'; 86 + 87 + reg = simple_strtoul(buf, &p, 16); 88 + if (!isspace(*p)) 89 + return -EINVAL; 90 + val = simple_strtoul(p + 1, NULL, 16); 91 + 92 + if (reg >= 0x84 && reg <= 0x1c4) 93 + writel(val, dcrtc->base + reg); 94 + 95 + return len; 96 + } 97 + 98 + static int armada_debugfs_reg_w_open(struct inode *inode, struct file *file) 99 + { 100 + file->private_data = inode->i_private; 101 + return 0; 102 + } 103 + 104 + static const struct file_operations fops_reg_w = { 105 + .owner = THIS_MODULE, 106 + .open = armada_debugfs_reg_w_open, 107 + .write = armada_debugfs_write, 108 + .llseek = noop_llseek, 109 + }; 110 + 111 + static struct drm_info_list armada_debugfs_list[] = { 112 + { "gem_linear", armada_debugfs_gem_linear_show, 0 }, 113 + }; 114 + #define ARMADA_DEBUGFS_ENTRIES ARRAY_SIZE(armada_debugfs_list) 115 + 116 + static int drm_add_fake_info_node(struct drm_minor *minor, struct dentry *ent, 117 + const void *key) 118 + { 119 + struct drm_info_node *node; 120 + 121 + node = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); 122 + if (node == NULL) { 123 + debugfs_remove(ent); 124 + return -ENOMEM; 125 + } 126 + 127 + node->minor = minor; 128 + node->dent = ent; 129 + node->info_ent = (void *) key; 130 + 131 + mutex_lock(&minor->debugfs_lock); 132 + list_add(&node->list, &minor->debugfs_list); 133 + mutex_unlock(&minor->debugfs_lock); 134 + 135 + return 0; 136 + } 137 + 138 + static int armada_debugfs_create(struct dentry *root, struct drm_minor *minor, 139 + const char *name, umode_t mode, const struct file_operations *fops) 140 + { 141 + struct dentry *de; 142 + 143 + de = debugfs_create_file(name, mode, root, minor->dev, fops); 144 + 145 + return drm_add_fake_info_node(minor, de, fops); 146 + } 147 + 148 + int armada_drm_debugfs_init(struct drm_minor *minor) 149 + { 150 + int ret; 151 + 152 + ret = drm_debugfs_create_files(armada_debugfs_list, 153 + ARMADA_DEBUGFS_ENTRIES, 154 + minor->debugfs_root, minor); 155 + if (ret) 156 + return ret; 157 + 158 + ret = armada_debugfs_create(minor->debugfs_root, minor, 159 + "reg", S_IFREG | S_IRUSR, &fops_reg_r); 160 + if (ret) 161 + goto err_1; 162 + 163 + ret = armada_debugfs_create(minor->debugfs_root, minor, 164 + "reg_wr", S_IFREG | S_IWUSR, &fops_reg_w); 165 + if (ret) 166 + goto err_2; 167 + return ret; 168 + 169 + err_2: 170 + drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_r, 1, minor); 171 + err_1: 172 + drm_debugfs_remove_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES, 173 + minor); 174 + return ret; 175 + } 176 + 177 + void armada_drm_debugfs_cleanup(struct drm_minor *minor) 178 + { 179 + drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_w, 1, minor); 180 + drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_r, 1, minor); 181 + drm_debugfs_remove_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES, 182 + minor); 183 + }
+113
drivers/gpu/drm/armada/armada_drm.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #ifndef ARMADA_DRM_H 9 + #define ARMADA_DRM_H 10 + 11 + #include <linux/kfifo.h> 12 + #include <linux/io.h> 13 + #include <linux/workqueue.h> 14 + #include <drm/drmP.h> 15 + 16 + struct armada_crtc; 17 + struct armada_gem_object; 18 + struct clk; 19 + struct drm_fb_helper; 20 + 21 + static inline void 22 + armada_updatel(uint32_t val, uint32_t mask, void __iomem *ptr) 23 + { 24 + uint32_t ov, v; 25 + 26 + ov = v = readl_relaxed(ptr); 27 + v = (v & ~mask) | val; 28 + if (ov != v) 29 + writel_relaxed(v, ptr); 30 + } 31 + 32 + static inline uint32_t armada_pitch(uint32_t width, uint32_t bpp) 33 + { 34 + uint32_t pitch = bpp != 4 ? width * ((bpp + 7) / 8) : width / 2; 35 + 36 + /* 88AP510 spec recommends pitch be a multiple of 128 */ 37 + return ALIGN(pitch, 128); 38 + } 39 + 40 + struct armada_vbl_event { 41 + struct list_head node; 42 + void *data; 43 + void (*fn)(struct armada_crtc *, void *); 44 + }; 45 + void armada_drm_vbl_event_add(struct armada_crtc *, 46 + struct armada_vbl_event *); 47 + void armada_drm_vbl_event_remove(struct armada_crtc *, 48 + struct armada_vbl_event *); 49 + void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *, 50 + struct armada_vbl_event *); 51 + #define armada_drm_vbl_event_init(_e, _f, _d) do { \ 52 + struct armada_vbl_event *__e = _e; \ 53 + INIT_LIST_HEAD(&__e->node); \ 54 + __e->data = _d; \ 55 + __e->fn = _f; \ 56 + } while (0) 57 + 58 + 59 + struct armada_private; 60 + 61 + struct armada_variant { 62 + bool has_spu_adv_reg; 63 + uint32_t spu_adv_reg; 64 + int (*init)(struct armada_private *, struct device *); 65 + int (*crtc_init)(struct armada_crtc *); 66 + int (*crtc_compute_clock)(struct armada_crtc *, 67 + const struct drm_display_mode *, 68 + uint32_t *); 69 + }; 70 + 71 + /* Variant ops */ 72 + extern const struct armada_variant armada510_ops; 73 + 74 + struct armada_private { 75 + const struct armada_variant *variant; 76 + struct work_struct fb_unref_work; 77 + DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8); 78 + struct drm_fb_helper *fbdev; 79 + struct armada_crtc *dcrtc[2]; 80 + struct drm_mm linear; 81 + struct clk *extclk[2]; 82 + struct drm_property *csc_yuv_prop; 83 + struct drm_property *csc_rgb_prop; 84 + struct drm_property *colorkey_prop; 85 + struct drm_property *colorkey_min_prop; 86 + struct drm_property *colorkey_max_prop; 87 + struct drm_property *colorkey_val_prop; 88 + struct drm_property *colorkey_alpha_prop; 89 + struct drm_property *colorkey_mode_prop; 90 + struct drm_property *brightness_prop; 91 + struct drm_property *contrast_prop; 92 + struct drm_property *saturation_prop; 93 + #ifdef CONFIG_DEBUG_FS 94 + struct dentry *de; 95 + #endif 96 + }; 97 + 98 + void __armada_drm_queue_unref_work(struct drm_device *, 99 + struct drm_framebuffer *); 100 + void armada_drm_queue_unref_work(struct drm_device *, 101 + struct drm_framebuffer *); 102 + 103 + extern const struct drm_mode_config_funcs armada_drm_mode_config_funcs; 104 + 105 + int armada_fbdev_init(struct drm_device *); 106 + void armada_fbdev_fini(struct drm_device *); 107 + 108 + int armada_overlay_plane_create(struct drm_device *, unsigned long); 109 + 110 + int armada_drm_debugfs_init(struct drm_minor *); 111 + void armada_drm_debugfs_cleanup(struct drm_minor *); 112 + 113 + #endif
+421
drivers/gpu/drm/armada/armada_drv.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #include <linux/clk.h> 9 + #include <linux/module.h> 10 + #include <drm/drmP.h> 11 + #include <drm/drm_crtc_helper.h> 12 + #include "armada_crtc.h" 13 + #include "armada_drm.h" 14 + #include "armada_gem.h" 15 + #include "armada_hw.h" 16 + #include <drm/armada_drm.h> 17 + #include "armada_ioctlP.h" 18 + 19 + #ifdef CONFIG_DRM_ARMADA_TDA1998X 20 + #include <drm/i2c/tda998x.h> 21 + #include "armada_slave.h" 22 + 23 + static struct tda998x_encoder_params params = { 24 + /* With 0x24, there is no translation between vp_out and int_vp 25 + FB LCD out Pins VIP Int Vp 26 + R:23:16 R:7:0 VPC7:0 7:0 7:0[R] 27 + G:15:8 G:15:8 VPB7:0 23:16 23:16[G] 28 + B:7:0 B:23:16 VPA7:0 15:8 15:8[B] 29 + */ 30 + .swap_a = 2, 31 + .swap_b = 3, 32 + .swap_c = 4, 33 + .swap_d = 5, 34 + .swap_e = 0, 35 + .swap_f = 1, 36 + .audio_cfg = BIT(2), 37 + .audio_frame[1] = 1, 38 + .audio_format = AFMT_SPDIF, 39 + .audio_sample_rate = 44100, 40 + }; 41 + 42 + static const struct armada_drm_slave_config tda19988_config = { 43 + .i2c_adapter_id = 0, 44 + .crtcs = 1 << 0, /* Only LCD0 at the moment */ 45 + .polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT, 46 + .interlace_allowed = true, 47 + .info = { 48 + .type = "tda998x", 49 + .addr = 0x70, 50 + .platform_data = &params, 51 + }, 52 + }; 53 + #endif 54 + 55 + static void armada_drm_unref_work(struct work_struct *work) 56 + { 57 + struct armada_private *priv = 58 + container_of(work, struct armada_private, fb_unref_work); 59 + struct drm_framebuffer *fb; 60 + 61 + while (kfifo_get(&priv->fb_unref, &fb)) 62 + drm_framebuffer_unreference(fb); 63 + } 64 + 65 + /* Must be called with dev->event_lock held */ 66 + void __armada_drm_queue_unref_work(struct drm_device *dev, 67 + struct drm_framebuffer *fb) 68 + { 69 + struct armada_private *priv = dev->dev_private; 70 + 71 + /* 72 + * Yes, we really must jump through these hoops just to store a 73 + * _pointer_ to something into the kfifo. This is utterly insane 74 + * and idiotic, because it kfifo requires the _data_ pointed to by 75 + * the pointer const, not the pointer itself. Not only that, but 76 + * you have to pass a pointer _to_ the pointer you want stored. 77 + */ 78 + const struct drm_framebuffer *silly_api_alert = fb; 79 + WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert)); 80 + schedule_work(&priv->fb_unref_work); 81 + } 82 + 83 + void armada_drm_queue_unref_work(struct drm_device *dev, 84 + struct drm_framebuffer *fb) 85 + { 86 + unsigned long flags; 87 + 88 + spin_lock_irqsave(&dev->event_lock, flags); 89 + __armada_drm_queue_unref_work(dev, fb); 90 + spin_unlock_irqrestore(&dev->event_lock, flags); 91 + } 92 + 93 + static int armada_drm_load(struct drm_device *dev, unsigned long flags) 94 + { 95 + const struct platform_device_id *id; 96 + struct armada_private *priv; 97 + struct resource *res[ARRAY_SIZE(priv->dcrtc)]; 98 + struct resource *mem = NULL; 99 + int ret, n, i; 100 + 101 + memset(res, 0, sizeof(res)); 102 + 103 + for (n = i = 0; ; n++) { 104 + struct resource *r = platform_get_resource(dev->platformdev, 105 + IORESOURCE_MEM, n); 106 + if (!r) 107 + break; 108 + 109 + /* Resources above 64K are graphics memory */ 110 + if (resource_size(r) > SZ_64K) 111 + mem = r; 112 + else if (i < ARRAY_SIZE(priv->dcrtc)) 113 + res[i++] = r; 114 + else 115 + return -EINVAL; 116 + } 117 + 118 + if (!res[0] || !mem) 119 + return -ENXIO; 120 + 121 + if (!devm_request_mem_region(dev->dev, mem->start, 122 + resource_size(mem), "armada-drm")) 123 + return -EBUSY; 124 + 125 + priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL); 126 + if (!priv) { 127 + DRM_ERROR("failed to allocate private\n"); 128 + return -ENOMEM; 129 + } 130 + 131 + dev->dev_private = priv; 132 + 133 + /* Get the implementation specific driver data. */ 134 + id = platform_get_device_id(dev->platformdev); 135 + if (!id) 136 + return -ENXIO; 137 + 138 + priv->variant = (struct armada_variant *)id->driver_data; 139 + 140 + ret = priv->variant->init(priv, dev->dev); 141 + if (ret) 142 + return ret; 143 + 144 + INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work); 145 + INIT_KFIFO(priv->fb_unref); 146 + 147 + /* Mode setting support */ 148 + drm_mode_config_init(dev); 149 + dev->mode_config.min_width = 320; 150 + dev->mode_config.min_height = 200; 151 + 152 + /* 153 + * With vscale enabled, the maximum width is 1920 due to the 154 + * 1920 by 3 lines RAM 155 + */ 156 + dev->mode_config.max_width = 1920; 157 + dev->mode_config.max_height = 2048; 158 + 159 + dev->mode_config.preferred_depth = 24; 160 + dev->mode_config.funcs = &armada_drm_mode_config_funcs; 161 + drm_mm_init(&priv->linear, mem->start, resource_size(mem)); 162 + 163 + /* Create all LCD controllers */ 164 + for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { 165 + if (!res[n]) 166 + break; 167 + 168 + ret = armada_drm_crtc_create(dev, n, res[n]); 169 + if (ret) 170 + goto err_kms; 171 + } 172 + 173 + #ifdef CONFIG_DRM_ARMADA_TDA1998X 174 + ret = armada_drm_connector_slave_create(dev, &tda19988_config); 175 + if (ret) 176 + goto err_kms; 177 + #endif 178 + 179 + ret = drm_vblank_init(dev, n); 180 + if (ret) 181 + goto err_kms; 182 + 183 + ret = drm_irq_install(dev); 184 + if (ret) 185 + goto err_kms; 186 + 187 + dev->vblank_disable_allowed = 1; 188 + 189 + ret = armada_fbdev_init(dev); 190 + if (ret) 191 + goto err_irq; 192 + 193 + drm_kms_helper_poll_init(dev); 194 + 195 + return 0; 196 + 197 + err_irq: 198 + drm_irq_uninstall(dev); 199 + err_kms: 200 + drm_mode_config_cleanup(dev); 201 + drm_mm_takedown(&priv->linear); 202 + flush_work(&priv->fb_unref_work); 203 + 204 + return ret; 205 + } 206 + 207 + static int armada_drm_unload(struct drm_device *dev) 208 + { 209 + struct armada_private *priv = dev->dev_private; 210 + 211 + drm_kms_helper_poll_fini(dev); 212 + armada_fbdev_fini(dev); 213 + drm_irq_uninstall(dev); 214 + drm_mode_config_cleanup(dev); 215 + drm_mm_takedown(&priv->linear); 216 + flush_work(&priv->fb_unref_work); 217 + dev->dev_private = NULL; 218 + 219 + return 0; 220 + } 221 + 222 + void armada_drm_vbl_event_add(struct armada_crtc *dcrtc, 223 + struct armada_vbl_event *evt) 224 + { 225 + unsigned long flags; 226 + 227 + spin_lock_irqsave(&dcrtc->irq_lock, flags); 228 + if (list_empty(&evt->node)) { 229 + list_add_tail(&evt->node, &dcrtc->vbl_list); 230 + 231 + drm_vblank_get(dcrtc->crtc.dev, dcrtc->num); 232 + } 233 + spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 234 + } 235 + 236 + void armada_drm_vbl_event_remove(struct armada_crtc *dcrtc, 237 + struct armada_vbl_event *evt) 238 + { 239 + if (!list_empty(&evt->node)) { 240 + list_del_init(&evt->node); 241 + drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); 242 + } 243 + } 244 + 245 + void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *dcrtc, 246 + struct armada_vbl_event *evt) 247 + { 248 + unsigned long flags; 249 + 250 + spin_lock_irqsave(&dcrtc->irq_lock, flags); 251 + armada_drm_vbl_event_remove(dcrtc, evt); 252 + spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 253 + } 254 + 255 + /* These are called under the vbl_lock. */ 256 + static int armada_drm_enable_vblank(struct drm_device *dev, int crtc) 257 + { 258 + struct armada_private *priv = dev->dev_private; 259 + armada_drm_crtc_enable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA); 260 + return 0; 261 + } 262 + 263 + static void armada_drm_disable_vblank(struct drm_device *dev, int crtc) 264 + { 265 + struct armada_private *priv = dev->dev_private; 266 + armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA); 267 + } 268 + 269 + static irqreturn_t armada_drm_irq_handler(int irq, void *arg) 270 + { 271 + struct drm_device *dev = arg; 272 + struct armada_private *priv = dev->dev_private; 273 + struct armada_crtc *dcrtc = priv->dcrtc[0]; 274 + uint32_t v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR); 275 + irqreturn_t handled = IRQ_NONE; 276 + 277 + /* 278 + * This is rediculous - rather than writing bits to clear, we 279 + * have to set the actual status register value. This is racy. 280 + */ 281 + writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); 282 + 283 + /* Mask out those interrupts we haven't enabled */ 284 + v = stat & dcrtc->irq_ena; 285 + 286 + if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) { 287 + armada_drm_crtc_irq(dcrtc, stat); 288 + handled = IRQ_HANDLED; 289 + } 290 + 291 + return handled; 292 + } 293 + 294 + static int armada_drm_irq_postinstall(struct drm_device *dev) 295 + { 296 + struct armada_private *priv = dev->dev_private; 297 + struct armada_crtc *dcrtc = priv->dcrtc[0]; 298 + 299 + spin_lock_irq(&dev->vbl_lock); 300 + writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); 301 + writel(0, dcrtc->base + LCD_SPU_IRQ_ISR); 302 + spin_unlock_irq(&dev->vbl_lock); 303 + 304 + return 0; 305 + } 306 + 307 + static void armada_drm_irq_uninstall(struct drm_device *dev) 308 + { 309 + struct armada_private *priv = dev->dev_private; 310 + struct armada_crtc *dcrtc = priv->dcrtc[0]; 311 + 312 + writel(0, dcrtc->base + LCD_SPU_IRQ_ENA); 313 + } 314 + 315 + static struct drm_ioctl_desc armada_ioctls[] = { 316 + DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl, 317 + DRM_UNLOCKED), 318 + DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 319 + DRM_UNLOCKED), 320 + DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, 321 + DRM_UNLOCKED), 322 + }; 323 + 324 + static const struct file_operations armada_drm_fops = { 325 + .owner = THIS_MODULE, 326 + .llseek = no_llseek, 327 + .read = drm_read, 328 + .poll = drm_poll, 329 + .unlocked_ioctl = drm_ioctl, 330 + .mmap = drm_gem_mmap, 331 + .open = drm_open, 332 + .release = drm_release, 333 + }; 334 + 335 + static struct drm_driver armada_drm_driver = { 336 + .load = armada_drm_load, 337 + .open = NULL, 338 + .preclose = NULL, 339 + .postclose = NULL, 340 + .lastclose = NULL, 341 + .unload = armada_drm_unload, 342 + .get_vblank_counter = drm_vblank_count, 343 + .enable_vblank = armada_drm_enable_vblank, 344 + .disable_vblank = armada_drm_disable_vblank, 345 + .irq_handler = armada_drm_irq_handler, 346 + .irq_postinstall = armada_drm_irq_postinstall, 347 + .irq_uninstall = armada_drm_irq_uninstall, 348 + #ifdef CONFIG_DEBUG_FS 349 + .debugfs_init = armada_drm_debugfs_init, 350 + .debugfs_cleanup = armada_drm_debugfs_cleanup, 351 + #endif 352 + .gem_free_object = armada_gem_free_object, 353 + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 354 + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 355 + .gem_prime_export = armada_gem_prime_export, 356 + .gem_prime_import = armada_gem_prime_import, 357 + .dumb_create = armada_gem_dumb_create, 358 + .dumb_map_offset = armada_gem_dumb_map_offset, 359 + .dumb_destroy = armada_gem_dumb_destroy, 360 + .gem_vm_ops = &armada_gem_vm_ops, 361 + .major = 1, 362 + .minor = 0, 363 + .name = "armada-drm", 364 + .desc = "Armada SoC DRM", 365 + .date = "20120730", 366 + .driver_features = DRIVER_GEM | DRIVER_MODESET | 367 + DRIVER_HAVE_IRQ | DRIVER_PRIME, 368 + .ioctls = armada_ioctls, 369 + .fops = &armada_drm_fops, 370 + }; 371 + 372 + static int armada_drm_probe(struct platform_device *pdev) 373 + { 374 + return drm_platform_init(&armada_drm_driver, pdev); 375 + } 376 + 377 + static int armada_drm_remove(struct platform_device *pdev) 378 + { 379 + drm_platform_exit(&armada_drm_driver, pdev); 380 + return 0; 381 + } 382 + 383 + static const struct platform_device_id armada_drm_platform_ids[] = { 384 + { 385 + .name = "armada-drm", 386 + .driver_data = (unsigned long)&armada510_ops, 387 + }, { 388 + .name = "armada-510-drm", 389 + .driver_data = (unsigned long)&armada510_ops, 390 + }, 391 + { }, 392 + }; 393 + MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids); 394 + 395 + static struct platform_driver armada_drm_platform_driver = { 396 + .probe = armada_drm_probe, 397 + .remove = armada_drm_remove, 398 + .driver = { 399 + .name = "armada-drm", 400 + .owner = THIS_MODULE, 401 + }, 402 + .id_table = armada_drm_platform_ids, 403 + }; 404 + 405 + static int __init armada_drm_init(void) 406 + { 407 + armada_drm_driver.num_ioctls = DRM_ARRAY_SIZE(armada_ioctls); 408 + return platform_driver_register(&armada_drm_platform_driver); 409 + } 410 + module_init(armada_drm_init); 411 + 412 + static void __exit armada_drm_exit(void) 413 + { 414 + platform_driver_unregister(&armada_drm_platform_driver); 415 + } 416 + module_exit(armada_drm_exit); 417 + 418 + MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); 419 + MODULE_DESCRIPTION("Armada DRM Driver"); 420 + MODULE_LICENSE("GPL"); 421 + MODULE_ALIAS("platform:armada-drm");
+170
drivers/gpu/drm/armada/armada_fb.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #include <drm/drmP.h> 9 + #include <drm/drm_crtc_helper.h> 10 + #include <drm/drm_fb_helper.h> 11 + #include "armada_drm.h" 12 + #include "armada_fb.h" 13 + #include "armada_gem.h" 14 + #include "armada_hw.h" 15 + 16 + static void armada_fb_destroy(struct drm_framebuffer *fb) 17 + { 18 + struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb); 19 + 20 + drm_framebuffer_cleanup(&dfb->fb); 21 + drm_gem_object_unreference_unlocked(&dfb->obj->obj); 22 + kfree(dfb); 23 + } 24 + 25 + static int armada_fb_create_handle(struct drm_framebuffer *fb, 26 + struct drm_file *dfile, unsigned int *handle) 27 + { 28 + struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb); 29 + return drm_gem_handle_create(dfile, &dfb->obj->obj, handle); 30 + } 31 + 32 + static const struct drm_framebuffer_funcs armada_fb_funcs = { 33 + .destroy = armada_fb_destroy, 34 + .create_handle = armada_fb_create_handle, 35 + }; 36 + 37 + struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, 38 + struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj) 39 + { 40 + struct armada_framebuffer *dfb; 41 + uint8_t format, config; 42 + int ret; 43 + 44 + switch (mode->pixel_format) { 45 + #define FMT(drm, fmt, mod) \ 46 + case DRM_FORMAT_##drm: \ 47 + format = CFG_##fmt; \ 48 + config = mod; \ 49 + break 50 + FMT(RGB565, 565, CFG_SWAPRB); 51 + FMT(BGR565, 565, 0); 52 + FMT(ARGB1555, 1555, CFG_SWAPRB); 53 + FMT(ABGR1555, 1555, 0); 54 + FMT(RGB888, 888PACK, CFG_SWAPRB); 55 + FMT(BGR888, 888PACK, 0); 56 + FMT(XRGB8888, X888, CFG_SWAPRB); 57 + FMT(XBGR8888, X888, 0); 58 + FMT(ARGB8888, 8888, CFG_SWAPRB); 59 + FMT(ABGR8888, 8888, 0); 60 + FMT(YUYV, 422PACK, CFG_YUV2RGB | CFG_SWAPYU | CFG_SWAPUV); 61 + FMT(UYVY, 422PACK, CFG_YUV2RGB); 62 + FMT(VYUY, 422PACK, CFG_YUV2RGB | CFG_SWAPUV); 63 + FMT(YVYU, 422PACK, CFG_YUV2RGB | CFG_SWAPYU); 64 + FMT(YUV422, 422, CFG_YUV2RGB); 65 + FMT(YVU422, 422, CFG_YUV2RGB | CFG_SWAPUV); 66 + FMT(YUV420, 420, CFG_YUV2RGB); 67 + FMT(YVU420, 420, CFG_YUV2RGB | CFG_SWAPUV); 68 + FMT(C8, PSEUDO8, 0); 69 + #undef FMT 70 + default: 71 + return ERR_PTR(-EINVAL); 72 + } 73 + 74 + dfb = kzalloc(sizeof(*dfb), GFP_KERNEL); 75 + if (!dfb) { 76 + DRM_ERROR("failed to allocate Armada fb object\n"); 77 + return ERR_PTR(-ENOMEM); 78 + } 79 + 80 + dfb->fmt = format; 81 + dfb->mod = config; 82 + dfb->obj = obj; 83 + 84 + drm_helper_mode_fill_fb_struct(&dfb->fb, mode); 85 + 86 + ret = drm_framebuffer_init(dev, &dfb->fb, &armada_fb_funcs); 87 + if (ret) { 88 + kfree(dfb); 89 + return ERR_PTR(ret); 90 + } 91 + 92 + /* 93 + * Take a reference on our object as we're successful - the 94 + * caller already holds a reference, which keeps us safe for 95 + * the above call, but the caller will drop their reference 96 + * to it. Hence we need to take our own reference. 97 + */ 98 + drm_gem_object_reference(&obj->obj); 99 + 100 + return dfb; 101 + } 102 + 103 + static struct drm_framebuffer *armada_fb_create(struct drm_device *dev, 104 + struct drm_file *dfile, struct drm_mode_fb_cmd2 *mode) 105 + { 106 + struct armada_gem_object *obj; 107 + struct armada_framebuffer *dfb; 108 + int ret; 109 + 110 + DRM_DEBUG_DRIVER("w%u h%u pf%08x f%u p%u,%u,%u\n", 111 + mode->width, mode->height, mode->pixel_format, 112 + mode->flags, mode->pitches[0], mode->pitches[1], 113 + mode->pitches[2]); 114 + 115 + /* We can only handle a single plane at the moment */ 116 + if (drm_format_num_planes(mode->pixel_format) > 1 && 117 + (mode->handles[0] != mode->handles[1] || 118 + mode->handles[0] != mode->handles[2])) { 119 + ret = -EINVAL; 120 + goto err; 121 + } 122 + 123 + obj = armada_gem_object_lookup(dev, dfile, mode->handles[0]); 124 + if (!obj) { 125 + ret = -ENOENT; 126 + goto err; 127 + } 128 + 129 + if (obj->obj.import_attach && !obj->sgt) { 130 + ret = armada_gem_map_import(obj); 131 + if (ret) 132 + goto err_unref; 133 + } 134 + 135 + /* Framebuffer objects must have a valid device address for scanout */ 136 + if (obj->dev_addr == DMA_ERROR_CODE) { 137 + ret = -EINVAL; 138 + goto err_unref; 139 + } 140 + 141 + dfb = armada_framebuffer_create(dev, mode, obj); 142 + if (IS_ERR(dfb)) { 143 + ret = PTR_ERR(dfb); 144 + goto err; 145 + } 146 + 147 + drm_gem_object_unreference_unlocked(&obj->obj); 148 + 149 + return &dfb->fb; 150 + 151 + err_unref: 152 + drm_gem_object_unreference_unlocked(&obj->obj); 153 + err: 154 + DRM_ERROR("failed to initialize framebuffer: %d\n", ret); 155 + return ERR_PTR(ret); 156 + } 157 + 158 + static void armada_output_poll_changed(struct drm_device *dev) 159 + { 160 + struct armada_private *priv = dev->dev_private; 161 + struct drm_fb_helper *fbh = priv->fbdev; 162 + 163 + if (fbh) 164 + drm_fb_helper_hotplug_event(fbh); 165 + } 166 + 167 + const struct drm_mode_config_funcs armada_drm_mode_config_funcs = { 168 + .fb_create = armada_fb_create, 169 + .output_poll_changed = armada_output_poll_changed, 170 + };
+24
drivers/gpu/drm/armada/armada_fb.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #ifndef ARMADA_FB_H 9 + #define ARMADA_FB_H 10 + 11 + struct armada_framebuffer { 12 + struct drm_framebuffer fb; 13 + struct armada_gem_object *obj; 14 + uint8_t fmt; 15 + uint8_t mod; 16 + }; 17 + #define drm_fb_to_armada_fb(dfb) \ 18 + container_of(dfb, struct armada_framebuffer, fb) 19 + #define drm_fb_obj(fb) drm_fb_to_armada_fb(fb)->obj 20 + 21 + struct armada_framebuffer *armada_framebuffer_create(struct drm_device *, 22 + struct drm_mode_fb_cmd2 *, struct armada_gem_object *); 23 + 24 + #endif
+202
drivers/gpu/drm/armada/armada_fbdev.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * Written from the i915 driver. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + #include <linux/errno.h> 10 + #include <linux/fb.h> 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + 14 + #include <drm/drmP.h> 15 + #include <drm/drm_fb_helper.h> 16 + #include "armada_crtc.h" 17 + #include "armada_drm.h" 18 + #include "armada_fb.h" 19 + #include "armada_gem.h" 20 + 21 + static /*const*/ struct fb_ops armada_fb_ops = { 22 + .owner = THIS_MODULE, 23 + .fb_check_var = drm_fb_helper_check_var, 24 + .fb_set_par = drm_fb_helper_set_par, 25 + .fb_fillrect = cfb_fillrect, 26 + .fb_copyarea = cfb_copyarea, 27 + .fb_imageblit = cfb_imageblit, 28 + .fb_pan_display = drm_fb_helper_pan_display, 29 + .fb_blank = drm_fb_helper_blank, 30 + .fb_setcmap = drm_fb_helper_setcmap, 31 + .fb_debug_enter = drm_fb_helper_debug_enter, 32 + .fb_debug_leave = drm_fb_helper_debug_leave, 33 + }; 34 + 35 + static int armada_fb_create(struct drm_fb_helper *fbh, 36 + struct drm_fb_helper_surface_size *sizes) 37 + { 38 + struct drm_device *dev = fbh->dev; 39 + struct drm_mode_fb_cmd2 mode; 40 + struct armada_framebuffer *dfb; 41 + struct armada_gem_object *obj; 42 + struct fb_info *info; 43 + int size, ret; 44 + void *ptr; 45 + 46 + memset(&mode, 0, sizeof(mode)); 47 + mode.width = sizes->surface_width; 48 + mode.height = sizes->surface_height; 49 + mode.pitches[0] = armada_pitch(mode.width, sizes->surface_bpp); 50 + mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 51 + sizes->surface_depth); 52 + 53 + size = mode.pitches[0] * mode.height; 54 + obj = armada_gem_alloc_private_object(dev, size); 55 + if (!obj) { 56 + DRM_ERROR("failed to allocate fb memory\n"); 57 + return -ENOMEM; 58 + } 59 + 60 + ret = armada_gem_linear_back(dev, obj); 61 + if (ret) { 62 + drm_gem_object_unreference_unlocked(&obj->obj); 63 + return ret; 64 + } 65 + 66 + ptr = armada_gem_map_object(dev, obj); 67 + if (!ptr) { 68 + drm_gem_object_unreference_unlocked(&obj->obj); 69 + return -ENOMEM; 70 + } 71 + 72 + dfb = armada_framebuffer_create(dev, &mode, obj); 73 + 74 + /* 75 + * A reference is now held by the framebuffer object if 76 + * successful, otherwise this drops the ref for the error path. 77 + */ 78 + drm_gem_object_unreference_unlocked(&obj->obj); 79 + 80 + if (IS_ERR(dfb)) 81 + return PTR_ERR(dfb); 82 + 83 + info = framebuffer_alloc(0, dev->dev); 84 + if (!info) { 85 + ret = -ENOMEM; 86 + goto err_fballoc; 87 + } 88 + 89 + ret = fb_alloc_cmap(&info->cmap, 256, 0); 90 + if (ret) { 91 + ret = -ENOMEM; 92 + goto err_fbcmap; 93 + } 94 + 95 + strlcpy(info->fix.id, "armada-drmfb", sizeof(info->fix.id)); 96 + info->par = fbh; 97 + info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; 98 + info->fbops = &armada_fb_ops; 99 + info->fix.smem_start = obj->phys_addr; 100 + info->fix.smem_len = obj->obj.size; 101 + info->screen_size = obj->obj.size; 102 + info->screen_base = ptr; 103 + fbh->fb = &dfb->fb; 104 + fbh->fbdev = info; 105 + drm_fb_helper_fill_fix(info, dfb->fb.pitches[0], dfb->fb.depth); 106 + drm_fb_helper_fill_var(info, fbh, sizes->fb_width, sizes->fb_height); 107 + 108 + DRM_DEBUG_KMS("allocated %dx%d %dbpp fb: 0x%08x\n", 109 + dfb->fb.width, dfb->fb.height, 110 + dfb->fb.bits_per_pixel, obj->phys_addr); 111 + 112 + return 0; 113 + 114 + err_fbcmap: 115 + framebuffer_release(info); 116 + err_fballoc: 117 + dfb->fb.funcs->destroy(&dfb->fb); 118 + return ret; 119 + } 120 + 121 + static int armada_fb_probe(struct drm_fb_helper *fbh, 122 + struct drm_fb_helper_surface_size *sizes) 123 + { 124 + int ret = 0; 125 + 126 + if (!fbh->fb) { 127 + ret = armada_fb_create(fbh, sizes); 128 + if (ret == 0) 129 + ret = 1; 130 + } 131 + return ret; 132 + } 133 + 134 + static struct drm_fb_helper_funcs armada_fb_helper_funcs = { 135 + .gamma_set = armada_drm_crtc_gamma_set, 136 + .gamma_get = armada_drm_crtc_gamma_get, 137 + .fb_probe = armada_fb_probe, 138 + }; 139 + 140 + int armada_fbdev_init(struct drm_device *dev) 141 + { 142 + struct armada_private *priv = dev->dev_private; 143 + struct drm_fb_helper *fbh; 144 + int ret; 145 + 146 + fbh = devm_kzalloc(dev->dev, sizeof(*fbh), GFP_KERNEL); 147 + if (!fbh) 148 + return -ENOMEM; 149 + 150 + priv->fbdev = fbh; 151 + 152 + fbh->funcs = &armada_fb_helper_funcs; 153 + 154 + ret = drm_fb_helper_init(dev, fbh, 1, 1); 155 + if (ret) { 156 + DRM_ERROR("failed to initialize drm fb helper\n"); 157 + goto err_fb_helper; 158 + } 159 + 160 + ret = drm_fb_helper_single_add_all_connectors(fbh); 161 + if (ret) { 162 + DRM_ERROR("failed to add fb connectors\n"); 163 + goto err_fb_setup; 164 + } 165 + 166 + ret = drm_fb_helper_initial_config(fbh, 32); 167 + if (ret) { 168 + DRM_ERROR("failed to set initial config\n"); 169 + goto err_fb_setup; 170 + } 171 + 172 + return 0; 173 + err_fb_setup: 174 + drm_fb_helper_fini(fbh); 175 + err_fb_helper: 176 + priv->fbdev = NULL; 177 + return ret; 178 + } 179 + 180 + void armada_fbdev_fini(struct drm_device *dev) 181 + { 182 + struct armada_private *priv = dev->dev_private; 183 + struct drm_fb_helper *fbh = priv->fbdev; 184 + 185 + if (fbh) { 186 + struct fb_info *info = fbh->fbdev; 187 + 188 + if (info) { 189 + unregister_framebuffer(info); 190 + if (info->cmap.len) 191 + fb_dealloc_cmap(&info->cmap); 192 + framebuffer_release(info); 193 + } 194 + 195 + if (fbh->fb) 196 + fbh->fb->funcs->destroy(fbh->fb); 197 + 198 + drm_fb_helper_fini(fbh); 199 + 200 + priv->fbdev = NULL; 201 + } 202 + }
+611
drivers/gpu/drm/armada/armada_gem.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #include <linux/dma-buf.h> 9 + #include <linux/dma-mapping.h> 10 + #include <linux/shmem_fs.h> 11 + #include <drm/drmP.h> 12 + #include "armada_drm.h" 13 + #include "armada_gem.h" 14 + #include <drm/armada_drm.h> 15 + #include "armada_ioctlP.h" 16 + 17 + static int armada_gem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 18 + { 19 + struct armada_gem_object *obj = drm_to_armada_gem(vma->vm_private_data); 20 + unsigned long addr = (unsigned long)vmf->virtual_address; 21 + unsigned long pfn = obj->phys_addr >> PAGE_SHIFT; 22 + int ret; 23 + 24 + pfn += (addr - vma->vm_start) >> PAGE_SHIFT; 25 + ret = vm_insert_pfn(vma, addr, pfn); 26 + 27 + switch (ret) { 28 + case 0: 29 + case -EBUSY: 30 + return VM_FAULT_NOPAGE; 31 + case -ENOMEM: 32 + return VM_FAULT_OOM; 33 + default: 34 + return VM_FAULT_SIGBUS; 35 + } 36 + } 37 + 38 + const struct vm_operations_struct armada_gem_vm_ops = { 39 + .fault = armada_gem_vm_fault, 40 + .open = drm_gem_vm_open, 41 + .close = drm_gem_vm_close, 42 + }; 43 + 44 + static size_t roundup_gem_size(size_t size) 45 + { 46 + return roundup(size, PAGE_SIZE); 47 + } 48 + 49 + /* dev->struct_mutex is held here */ 50 + void armada_gem_free_object(struct drm_gem_object *obj) 51 + { 52 + struct armada_gem_object *dobj = drm_to_armada_gem(obj); 53 + 54 + DRM_DEBUG_DRIVER("release obj %p\n", dobj); 55 + 56 + drm_gem_free_mmap_offset(&dobj->obj); 57 + 58 + if (dobj->page) { 59 + /* page backed memory */ 60 + unsigned int order = get_order(dobj->obj.size); 61 + __free_pages(dobj->page, order); 62 + } else if (dobj->linear) { 63 + /* linear backed memory */ 64 + drm_mm_remove_node(dobj->linear); 65 + kfree(dobj->linear); 66 + if (dobj->addr) 67 + iounmap(dobj->addr); 68 + } 69 + 70 + if (dobj->obj.import_attach) { 71 + /* We only ever display imported data */ 72 + dma_buf_unmap_attachment(dobj->obj.import_attach, dobj->sgt, 73 + DMA_TO_DEVICE); 74 + drm_prime_gem_destroy(&dobj->obj, NULL); 75 + } 76 + 77 + drm_gem_object_release(&dobj->obj); 78 + 79 + kfree(dobj); 80 + } 81 + 82 + int 83 + armada_gem_linear_back(struct drm_device *dev, struct armada_gem_object *obj) 84 + { 85 + struct armada_private *priv = dev->dev_private; 86 + size_t size = obj->obj.size; 87 + 88 + if (obj->page || obj->linear) 89 + return 0; 90 + 91 + /* 92 + * If it is a small allocation (typically cursor, which will 93 + * be 32x64 or 64x32 ARGB pixels) try to get it from the system. 94 + * Framebuffers will never be this small (our minimum size for 95 + * framebuffers is larger than this anyway.) Such objects are 96 + * only accessed by the CPU so we don't need any special handing 97 + * here. 98 + */ 99 + if (size <= 8192) { 100 + unsigned int order = get_order(size); 101 + struct page *p = alloc_pages(GFP_KERNEL, order); 102 + 103 + if (p) { 104 + obj->addr = page_address(p); 105 + obj->phys_addr = page_to_phys(p); 106 + obj->page = p; 107 + 108 + memset(obj->addr, 0, PAGE_ALIGN(size)); 109 + } 110 + } 111 + 112 + /* 113 + * We could grab something from CMA if it's enabled, but that 114 + * involves building in a problem: 115 + * 116 + * CMA's interface uses dma_alloc_coherent(), which provides us 117 + * with an CPU virtual address and a device address. 118 + * 119 + * The CPU virtual address may be either an address in the kernel 120 + * direct mapped region (for example, as it would be on x86) or 121 + * it may be remapped into another part of kernel memory space 122 + * (eg, as it would be on ARM.) This means virt_to_phys() on the 123 + * returned virtual address is invalid depending on the architecture 124 + * implementation. 125 + * 126 + * The device address may also not be a physical address; it may 127 + * be that there is some kind of remapping between the device and 128 + * system RAM, which makes the use of the device address also 129 + * unsafe to re-use as a physical address. 130 + * 131 + * This makes DRM usage of dma_alloc_coherent() in a generic way 132 + * at best very questionable and unsafe. 133 + */ 134 + 135 + /* Otherwise, grab it from our linear allocation */ 136 + if (!obj->page) { 137 + struct drm_mm_node *node; 138 + unsigned align = min_t(unsigned, size, SZ_2M); 139 + void __iomem *ptr; 140 + int ret; 141 + 142 + node = kzalloc(sizeof(*node), GFP_KERNEL); 143 + if (!node) 144 + return -ENOSPC; 145 + 146 + mutex_lock(&dev->struct_mutex); 147 + ret = drm_mm_insert_node(&priv->linear, node, size, align, 148 + DRM_MM_SEARCH_DEFAULT); 149 + mutex_unlock(&dev->struct_mutex); 150 + if (ret) { 151 + kfree(node); 152 + return ret; 153 + } 154 + 155 + obj->linear = node; 156 + 157 + /* Ensure that the memory we're returning is cleared. */ 158 + ptr = ioremap_wc(obj->linear->start, size); 159 + if (!ptr) { 160 + mutex_lock(&dev->struct_mutex); 161 + drm_mm_remove_node(obj->linear); 162 + mutex_unlock(&dev->struct_mutex); 163 + kfree(obj->linear); 164 + obj->linear = NULL; 165 + return -ENOMEM; 166 + } 167 + 168 + memset_io(ptr, 0, size); 169 + iounmap(ptr); 170 + 171 + obj->phys_addr = obj->linear->start; 172 + obj->dev_addr = obj->linear->start; 173 + } 174 + 175 + DRM_DEBUG_DRIVER("obj %p phys %#x dev %#x\n", 176 + obj, obj->phys_addr, obj->dev_addr); 177 + 178 + return 0; 179 + } 180 + 181 + void * 182 + armada_gem_map_object(struct drm_device *dev, struct armada_gem_object *dobj) 183 + { 184 + /* only linear objects need to be ioremap'd */ 185 + if (!dobj->addr && dobj->linear) 186 + dobj->addr = ioremap_wc(dobj->phys_addr, dobj->obj.size); 187 + return dobj->addr; 188 + } 189 + 190 + struct armada_gem_object * 191 + armada_gem_alloc_private_object(struct drm_device *dev, size_t size) 192 + { 193 + struct armada_gem_object *obj; 194 + 195 + size = roundup_gem_size(size); 196 + 197 + obj = kzalloc(sizeof(*obj), GFP_KERNEL); 198 + if (!obj) 199 + return NULL; 200 + 201 + drm_gem_private_object_init(dev, &obj->obj, size); 202 + obj->dev_addr = DMA_ERROR_CODE; 203 + 204 + DRM_DEBUG_DRIVER("alloc private obj %p size %zu\n", obj, size); 205 + 206 + return obj; 207 + } 208 + 209 + struct armada_gem_object *armada_gem_alloc_object(struct drm_device *dev, 210 + size_t size) 211 + { 212 + struct armada_gem_object *obj; 213 + struct address_space *mapping; 214 + 215 + size = roundup_gem_size(size); 216 + 217 + obj = kzalloc(sizeof(*obj), GFP_KERNEL); 218 + if (!obj) 219 + return NULL; 220 + 221 + if (drm_gem_object_init(dev, &obj->obj, size)) { 222 + kfree(obj); 223 + return NULL; 224 + } 225 + 226 + obj->dev_addr = DMA_ERROR_CODE; 227 + 228 + mapping = obj->obj.filp->f_path.dentry->d_inode->i_mapping; 229 + mapping_set_gfp_mask(mapping, GFP_HIGHUSER | __GFP_RECLAIMABLE); 230 + 231 + DRM_DEBUG_DRIVER("alloc obj %p size %zu\n", obj, size); 232 + 233 + return obj; 234 + } 235 + 236 + /* Dumb alloc support */ 237 + int armada_gem_dumb_create(struct drm_file *file, struct drm_device *dev, 238 + struct drm_mode_create_dumb *args) 239 + { 240 + struct armada_gem_object *dobj; 241 + u32 handle; 242 + size_t size; 243 + int ret; 244 + 245 + args->pitch = armada_pitch(args->width, args->bpp); 246 + args->size = size = args->pitch * args->height; 247 + 248 + dobj = armada_gem_alloc_private_object(dev, size); 249 + if (dobj == NULL) 250 + return -ENOMEM; 251 + 252 + ret = armada_gem_linear_back(dev, dobj); 253 + if (ret) 254 + goto err; 255 + 256 + ret = drm_gem_handle_create(file, &dobj->obj, &handle); 257 + if (ret) 258 + goto err; 259 + 260 + args->handle = handle; 261 + 262 + /* drop reference from allocate - handle holds it now */ 263 + DRM_DEBUG_DRIVER("obj %p size %zu handle %#x\n", dobj, size, handle); 264 + err: 265 + drm_gem_object_unreference_unlocked(&dobj->obj); 266 + return ret; 267 + } 268 + 269 + int armada_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, 270 + uint32_t handle, uint64_t *offset) 271 + { 272 + struct armada_gem_object *obj; 273 + int ret = 0; 274 + 275 + mutex_lock(&dev->struct_mutex); 276 + obj = armada_gem_object_lookup(dev, file, handle); 277 + if (!obj) { 278 + DRM_ERROR("failed to lookup gem object\n"); 279 + ret = -EINVAL; 280 + goto err_unlock; 281 + } 282 + 283 + /* Don't allow imported objects to be mapped */ 284 + if (obj->obj.import_attach) { 285 + ret = -EINVAL; 286 + goto err_unlock; 287 + } 288 + 289 + ret = drm_gem_create_mmap_offset(&obj->obj); 290 + if (ret == 0) { 291 + *offset = drm_vma_node_offset_addr(&obj->obj.vma_node); 292 + DRM_DEBUG_DRIVER("handle %#x offset %llx\n", handle, *offset); 293 + } 294 + 295 + drm_gem_object_unreference(&obj->obj); 296 + err_unlock: 297 + mutex_unlock(&dev->struct_mutex); 298 + 299 + return ret; 300 + } 301 + 302 + int armada_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, 303 + uint32_t handle) 304 + { 305 + return drm_gem_handle_delete(file, handle); 306 + } 307 + 308 + /* Private driver gem ioctls */ 309 + int armada_gem_create_ioctl(struct drm_device *dev, void *data, 310 + struct drm_file *file) 311 + { 312 + struct drm_armada_gem_create *args = data; 313 + struct armada_gem_object *dobj; 314 + size_t size; 315 + u32 handle; 316 + int ret; 317 + 318 + if (args->size == 0) 319 + return -ENOMEM; 320 + 321 + size = args->size; 322 + 323 + dobj = armada_gem_alloc_object(dev, size); 324 + if (dobj == NULL) 325 + return -ENOMEM; 326 + 327 + ret = drm_gem_handle_create(file, &dobj->obj, &handle); 328 + if (ret) 329 + goto err; 330 + 331 + args->handle = handle; 332 + 333 + /* drop reference from allocate - handle holds it now */ 334 + DRM_DEBUG_DRIVER("obj %p size %zu handle %#x\n", dobj, size, handle); 335 + err: 336 + drm_gem_object_unreference_unlocked(&dobj->obj); 337 + return ret; 338 + } 339 + 340 + /* Map a shmem-backed object into process memory space */ 341 + int armada_gem_mmap_ioctl(struct drm_device *dev, void *data, 342 + struct drm_file *file) 343 + { 344 + struct drm_armada_gem_mmap *args = data; 345 + struct armada_gem_object *dobj; 346 + unsigned long addr; 347 + 348 + dobj = armada_gem_object_lookup(dev, file, args->handle); 349 + if (dobj == NULL) 350 + return -ENOENT; 351 + 352 + if (!dobj->obj.filp) { 353 + drm_gem_object_unreference(&dobj->obj); 354 + return -EINVAL; 355 + } 356 + 357 + addr = vm_mmap(dobj->obj.filp, 0, args->size, PROT_READ | PROT_WRITE, 358 + MAP_SHARED, args->offset); 359 + drm_gem_object_unreference(&dobj->obj); 360 + if (IS_ERR_VALUE(addr)) 361 + return addr; 362 + 363 + args->addr = addr; 364 + 365 + return 0; 366 + } 367 + 368 + int armada_gem_pwrite_ioctl(struct drm_device *dev, void *data, 369 + struct drm_file *file) 370 + { 371 + struct drm_armada_gem_pwrite *args = data; 372 + struct armada_gem_object *dobj; 373 + char __user *ptr; 374 + int ret; 375 + 376 + DRM_DEBUG_DRIVER("handle %u off %u size %u ptr 0x%llx\n", 377 + args->handle, args->offset, args->size, args->ptr); 378 + 379 + if (args->size == 0) 380 + return 0; 381 + 382 + ptr = (char __user *)(uintptr_t)args->ptr; 383 + 384 + if (!access_ok(VERIFY_READ, ptr, args->size)) 385 + return -EFAULT; 386 + 387 + ret = fault_in_multipages_readable(ptr, args->size); 388 + if (ret) 389 + return ret; 390 + 391 + dobj = armada_gem_object_lookup(dev, file, args->handle); 392 + if (dobj == NULL) 393 + return -ENOENT; 394 + 395 + /* Must be a kernel-mapped object */ 396 + if (!dobj->addr) 397 + return -EINVAL; 398 + 399 + if (args->offset > dobj->obj.size || 400 + args->size > dobj->obj.size - args->offset) { 401 + DRM_ERROR("invalid size: object size %u\n", dobj->obj.size); 402 + ret = -EINVAL; 403 + goto unref; 404 + } 405 + 406 + if (copy_from_user(dobj->addr + args->offset, ptr, args->size)) { 407 + ret = -EFAULT; 408 + } else if (dobj->update) { 409 + dobj->update(dobj->update_data); 410 + ret = 0; 411 + } 412 + 413 + unref: 414 + drm_gem_object_unreference_unlocked(&dobj->obj); 415 + return ret; 416 + } 417 + 418 + /* Prime support */ 419 + struct sg_table * 420 + armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, 421 + enum dma_data_direction dir) 422 + { 423 + struct drm_gem_object *obj = attach->dmabuf->priv; 424 + struct armada_gem_object *dobj = drm_to_armada_gem(obj); 425 + struct scatterlist *sg; 426 + struct sg_table *sgt; 427 + int i, num; 428 + 429 + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); 430 + if (!sgt) 431 + return NULL; 432 + 433 + if (dobj->obj.filp) { 434 + struct address_space *mapping; 435 + gfp_t gfp; 436 + int count; 437 + 438 + count = dobj->obj.size / PAGE_SIZE; 439 + if (sg_alloc_table(sgt, count, GFP_KERNEL)) 440 + goto free_sgt; 441 + 442 + mapping = file_inode(dobj->obj.filp)->i_mapping; 443 + gfp = mapping_gfp_mask(mapping); 444 + 445 + for_each_sg(sgt->sgl, sg, count, i) { 446 + struct page *page; 447 + 448 + page = shmem_read_mapping_page_gfp(mapping, i, gfp); 449 + if (IS_ERR(page)) { 450 + num = i; 451 + goto release; 452 + } 453 + 454 + sg_set_page(sg, page, PAGE_SIZE, 0); 455 + } 456 + 457 + if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) { 458 + num = sgt->nents; 459 + goto release; 460 + } 461 + } else if (dobj->page) { 462 + /* Single contiguous page */ 463 + if (sg_alloc_table(sgt, 1, GFP_KERNEL)) 464 + goto free_sgt; 465 + 466 + sg_set_page(sgt->sgl, dobj->page, dobj->obj.size, 0); 467 + 468 + if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) 469 + goto free_table; 470 + } else if (dobj->linear) { 471 + /* Single contiguous physical region - no struct page */ 472 + if (sg_alloc_table(sgt, 1, GFP_KERNEL)) 473 + goto free_sgt; 474 + sg_dma_address(sgt->sgl) = dobj->dev_addr; 475 + sg_dma_len(sgt->sgl) = dobj->obj.size; 476 + } else { 477 + goto free_sgt; 478 + } 479 + return sgt; 480 + 481 + release: 482 + for_each_sg(sgt->sgl, sg, num, i) 483 + page_cache_release(sg_page(sg)); 484 + free_table: 485 + sg_free_table(sgt); 486 + free_sgt: 487 + kfree(sgt); 488 + return NULL; 489 + } 490 + 491 + static void armada_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, 492 + struct sg_table *sgt, enum dma_data_direction dir) 493 + { 494 + struct drm_gem_object *obj = attach->dmabuf->priv; 495 + struct armada_gem_object *dobj = drm_to_armada_gem(obj); 496 + int i; 497 + 498 + if (!dobj->linear) 499 + dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir); 500 + 501 + if (dobj->obj.filp) { 502 + struct scatterlist *sg; 503 + for_each_sg(sgt->sgl, sg, sgt->nents, i) 504 + page_cache_release(sg_page(sg)); 505 + } 506 + 507 + sg_free_table(sgt); 508 + kfree(sgt); 509 + } 510 + 511 + static void *armada_gem_dmabuf_no_kmap(struct dma_buf *buf, unsigned long n) 512 + { 513 + return NULL; 514 + } 515 + 516 + static void 517 + armada_gem_dmabuf_no_kunmap(struct dma_buf *buf, unsigned long n, void *addr) 518 + { 519 + } 520 + 521 + static int 522 + armada_gem_dmabuf_mmap(struct dma_buf *buf, struct vm_area_struct *vma) 523 + { 524 + return -EINVAL; 525 + } 526 + 527 + static const struct dma_buf_ops armada_gem_prime_dmabuf_ops = { 528 + .map_dma_buf = armada_gem_prime_map_dma_buf, 529 + .unmap_dma_buf = armada_gem_prime_unmap_dma_buf, 530 + .release = drm_gem_dmabuf_release, 531 + .kmap_atomic = armada_gem_dmabuf_no_kmap, 532 + .kunmap_atomic = armada_gem_dmabuf_no_kunmap, 533 + .kmap = armada_gem_dmabuf_no_kmap, 534 + .kunmap = armada_gem_dmabuf_no_kunmap, 535 + .mmap = armada_gem_dmabuf_mmap, 536 + }; 537 + 538 + struct dma_buf * 539 + armada_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj, 540 + int flags) 541 + { 542 + return dma_buf_export(obj, &armada_gem_prime_dmabuf_ops, obj->size, 543 + O_RDWR); 544 + } 545 + 546 + struct drm_gem_object * 547 + armada_gem_prime_import(struct drm_device *dev, struct dma_buf *buf) 548 + { 549 + struct dma_buf_attachment *attach; 550 + struct armada_gem_object *dobj; 551 + 552 + if (buf->ops == &armada_gem_prime_dmabuf_ops) { 553 + struct drm_gem_object *obj = buf->priv; 554 + if (obj->dev == dev) { 555 + /* 556 + * Importing our own dmabuf(s) increases the 557 + * refcount on the gem object itself. 558 + */ 559 + drm_gem_object_reference(obj); 560 + dma_buf_put(buf); 561 + return obj; 562 + } 563 + } 564 + 565 + attach = dma_buf_attach(buf, dev->dev); 566 + if (IS_ERR(attach)) 567 + return ERR_CAST(attach); 568 + 569 + dobj = armada_gem_alloc_private_object(dev, buf->size); 570 + if (!dobj) { 571 + dma_buf_detach(buf, attach); 572 + return ERR_PTR(-ENOMEM); 573 + } 574 + 575 + dobj->obj.import_attach = attach; 576 + 577 + /* 578 + * Don't call dma_buf_map_attachment() here - it maps the 579 + * scatterlist immediately for DMA, and this is not always 580 + * an appropriate thing to do. 581 + */ 582 + return &dobj->obj; 583 + } 584 + 585 + int armada_gem_map_import(struct armada_gem_object *dobj) 586 + { 587 + int ret; 588 + 589 + dobj->sgt = dma_buf_map_attachment(dobj->obj.import_attach, 590 + DMA_TO_DEVICE); 591 + if (!dobj->sgt) { 592 + DRM_ERROR("dma_buf_map_attachment() returned NULL\n"); 593 + return -EINVAL; 594 + } 595 + if (IS_ERR(dobj->sgt)) { 596 + ret = PTR_ERR(dobj->sgt); 597 + dobj->sgt = NULL; 598 + DRM_ERROR("dma_buf_map_attachment() error: %d\n", ret); 599 + return ret; 600 + } 601 + if (dobj->sgt->nents > 1) { 602 + DRM_ERROR("dma_buf_map_attachment() returned an (unsupported) scattered list\n"); 603 + return -EINVAL; 604 + } 605 + if (sg_dma_len(dobj->sgt->sgl) < dobj->obj.size) { 606 + DRM_ERROR("dma_buf_map_attachment() returned a small buffer\n"); 607 + return -EINVAL; 608 + } 609 + dobj->dev_addr = sg_dma_address(dobj->sgt->sgl); 610 + return 0; 611 + }
+52
drivers/gpu/drm/armada/armada_gem.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #ifndef ARMADA_GEM_H 9 + #define ARMADA_GEM_H 10 + 11 + /* GEM */ 12 + struct armada_gem_object { 13 + struct drm_gem_object obj; 14 + void *addr; 15 + phys_addr_t phys_addr; 16 + resource_size_t dev_addr; 17 + struct drm_mm_node *linear; /* for linear backed */ 18 + struct page *page; /* for page backed */ 19 + struct sg_table *sgt; /* for imported */ 20 + void (*update)(void *); 21 + void *update_data; 22 + }; 23 + 24 + extern const struct vm_operations_struct armada_gem_vm_ops; 25 + 26 + #define drm_to_armada_gem(o) container_of(o, struct armada_gem_object, obj) 27 + 28 + void armada_gem_free_object(struct drm_gem_object *); 29 + int armada_gem_linear_back(struct drm_device *, struct armada_gem_object *); 30 + void *armada_gem_map_object(struct drm_device *, struct armada_gem_object *); 31 + struct armada_gem_object *armada_gem_alloc_private_object(struct drm_device *, 32 + size_t); 33 + int armada_gem_dumb_create(struct drm_file *, struct drm_device *, 34 + struct drm_mode_create_dumb *); 35 + int armada_gem_dumb_map_offset(struct drm_file *, struct drm_device *, 36 + uint32_t, uint64_t *); 37 + int armada_gem_dumb_destroy(struct drm_file *, struct drm_device *, 38 + uint32_t); 39 + struct dma_buf *armada_gem_prime_export(struct drm_device *dev, 40 + struct drm_gem_object *obj, int flags); 41 + struct drm_gem_object *armada_gem_prime_import(struct drm_device *, 42 + struct dma_buf *); 43 + int armada_gem_map_import(struct armada_gem_object *); 44 + 45 + static inline struct armada_gem_object *armada_gem_object_lookup( 46 + struct drm_device *dev, struct drm_file *dfile, unsigned handle) 47 + { 48 + struct drm_gem_object *obj = drm_gem_object_lookup(dev, dfile, handle); 49 + 50 + return obj ? drm_to_armada_gem(obj) : NULL; 51 + } 52 + #endif
+318
drivers/gpu/drm/armada/armada_hw.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * Rewritten from the dovefb driver, and Armada510 manuals. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + #ifndef ARMADA_HW_H 10 + #define ARMADA_HW_H 11 + 12 + /* 13 + * Note: the following registers are written from IRQ context: 14 + * LCD_SPU_V_PORCH, LCD_SPU_ADV_REG, LCD_SPUT_V_H_TOTAL 15 + * LCD_SPU_DMA_START_ADDR_[YUV][01], LCD_SPU_DMA_PITCH_YC, 16 + * LCD_SPU_DMA_PITCH_UV, LCD_SPU_DMA_OVSA_HPXL_VLN, 17 + * LCD_SPU_DMA_HPXL_VLN, LCD_SPU_DZM_HPXL_VLN, LCD_SPU_DMA_CTRL0 18 + */ 19 + enum { 20 + LCD_SPU_ADV_REG = 0x0084, /* Armada 510 */ 21 + LCD_SPU_DMA_START_ADDR_Y0 = 0x00c0, 22 + LCD_SPU_DMA_START_ADDR_U0 = 0x00c4, 23 + LCD_SPU_DMA_START_ADDR_V0 = 0x00c8, 24 + LCD_CFG_DMA_START_ADDR_0 = 0x00cc, 25 + LCD_SPU_DMA_START_ADDR_Y1 = 0x00d0, 26 + LCD_SPU_DMA_START_ADDR_U1 = 0x00d4, 27 + LCD_SPU_DMA_START_ADDR_V1 = 0x00d8, 28 + LCD_CFG_DMA_START_ADDR_1 = 0x00dc, 29 + LCD_SPU_DMA_PITCH_YC = 0x00e0, 30 + LCD_SPU_DMA_PITCH_UV = 0x00e4, 31 + LCD_SPU_DMA_OVSA_HPXL_VLN = 0x00e8, 32 + LCD_SPU_DMA_HPXL_VLN = 0x00ec, 33 + LCD_SPU_DZM_HPXL_VLN = 0x00f0, 34 + LCD_CFG_GRA_START_ADDR0 = 0x00f4, 35 + LCD_CFG_GRA_START_ADDR1 = 0x00f8, 36 + LCD_CFG_GRA_PITCH = 0x00fc, 37 + LCD_SPU_GRA_OVSA_HPXL_VLN = 0x0100, 38 + LCD_SPU_GRA_HPXL_VLN = 0x0104, 39 + LCD_SPU_GZM_HPXL_VLN = 0x0108, 40 + LCD_SPU_HWC_OVSA_HPXL_VLN = 0x010c, 41 + LCD_SPU_HWC_HPXL_VLN = 0x0110, 42 + LCD_SPUT_V_H_TOTAL = 0x0114, 43 + LCD_SPU_V_H_ACTIVE = 0x0118, 44 + LCD_SPU_H_PORCH = 0x011c, 45 + LCD_SPU_V_PORCH = 0x0120, 46 + LCD_SPU_BLANKCOLOR = 0x0124, 47 + LCD_SPU_ALPHA_COLOR1 = 0x0128, 48 + LCD_SPU_ALPHA_COLOR2 = 0x012c, 49 + LCD_SPU_COLORKEY_Y = 0x0130, 50 + LCD_SPU_COLORKEY_U = 0x0134, 51 + LCD_SPU_COLORKEY_V = 0x0138, 52 + LCD_CFG_RDREG4F = 0x013c, /* Armada 510 */ 53 + LCD_SPU_SPI_RXDATA = 0x0140, 54 + LCD_SPU_ISA_RXDATA = 0x0144, 55 + LCD_SPU_HWC_RDDAT = 0x0158, 56 + LCD_SPU_GAMMA_RDDAT = 0x015c, 57 + LCD_SPU_PALETTE_RDDAT = 0x0160, 58 + LCD_SPU_IOPAD_IN = 0x0178, 59 + LCD_CFG_RDREG5F = 0x017c, 60 + LCD_SPU_SPI_CTRL = 0x0180, 61 + LCD_SPU_SPI_TXDATA = 0x0184, 62 + LCD_SPU_SMPN_CTRL = 0x0188, 63 + LCD_SPU_DMA_CTRL0 = 0x0190, 64 + LCD_SPU_DMA_CTRL1 = 0x0194, 65 + LCD_SPU_SRAM_CTRL = 0x0198, 66 + LCD_SPU_SRAM_WRDAT = 0x019c, 67 + LCD_SPU_SRAM_PARA0 = 0x01a0, /* Armada 510 */ 68 + LCD_SPU_SRAM_PARA1 = 0x01a4, 69 + LCD_CFG_SCLK_DIV = 0x01a8, 70 + LCD_SPU_CONTRAST = 0x01ac, 71 + LCD_SPU_SATURATION = 0x01b0, 72 + LCD_SPU_CBSH_HUE = 0x01b4, 73 + LCD_SPU_DUMB_CTRL = 0x01b8, 74 + LCD_SPU_IOPAD_CONTROL = 0x01bc, 75 + LCD_SPU_IRQ_ENA = 0x01c0, 76 + LCD_SPU_IRQ_ISR = 0x01c4, 77 + }; 78 + 79 + /* For LCD_SPU_ADV_REG */ 80 + enum { 81 + ADV_VSYNC_L_OFF = 0xfff << 20, 82 + ADV_GRACOLORKEY = 1 << 19, 83 + ADV_VIDCOLORKEY = 1 << 18, 84 + ADV_HWC32BLEND = 1 << 15, 85 + ADV_HWC32ARGB = 1 << 14, 86 + ADV_HWC32ENABLE = 1 << 13, 87 + ADV_VSYNCOFFEN = 1 << 12, 88 + ADV_VSYNC_H_OFF = 0xfff << 0, 89 + }; 90 + 91 + enum { 92 + CFG_565 = 0, 93 + CFG_1555 = 1, 94 + CFG_888PACK = 2, 95 + CFG_X888 = 3, 96 + CFG_8888 = 4, 97 + CFG_422PACK = 5, 98 + CFG_422 = 6, 99 + CFG_420 = 7, 100 + CFG_PSEUDO4 = 9, 101 + CFG_PSEUDO8 = 10, 102 + CFG_SWAPRB = 1 << 4, 103 + CFG_SWAPUV = 1 << 3, 104 + CFG_SWAPYU = 1 << 2, 105 + CFG_YUV2RGB = 1 << 1, 106 + }; 107 + 108 + /* For LCD_SPU_DMA_CTRL0 */ 109 + enum { 110 + CFG_NOBLENDING = 1 << 31, 111 + CFG_GAMMA_ENA = 1 << 30, 112 + CFG_CBSH_ENA = 1 << 29, 113 + CFG_PALETTE_ENA = 1 << 28, 114 + CFG_ARBFAST_ENA = 1 << 27, 115 + CFG_HWC_1BITMOD = 1 << 26, 116 + CFG_HWC_1BITENA = 1 << 25, 117 + CFG_HWC_ENA = 1 << 24, 118 + CFG_DMAFORMAT = 0xf << 20, 119 + #define CFG_DMA_FMT(x) ((x) << 20) 120 + CFG_GRAFORMAT = 0xf << 16, 121 + #define CFG_GRA_FMT(x) ((x) << 16) 122 + #define CFG_GRA_MOD(x) ((x) << 8) 123 + CFG_GRA_FTOGGLE = 1 << 15, 124 + CFG_GRA_HSMOOTH = 1 << 14, 125 + CFG_GRA_TSTMODE = 1 << 13, 126 + CFG_GRA_ENA = 1 << 8, 127 + #define CFG_DMA_MOD(x) ((x) << 0) 128 + CFG_DMA_FTOGGLE = 1 << 7, 129 + CFG_DMA_HSMOOTH = 1 << 6, 130 + CFG_DMA_TSTMODE = 1 << 5, 131 + CFG_DMA_ENA = 1 << 0, 132 + }; 133 + 134 + enum { 135 + CKMODE_DISABLE = 0, 136 + CKMODE_Y = 1, 137 + CKMODE_U = 2, 138 + CKMODE_RGB = 3, 139 + CKMODE_V = 4, 140 + CKMODE_R = 5, 141 + CKMODE_G = 6, 142 + CKMODE_B = 7, 143 + }; 144 + 145 + /* For LCD_SPU_DMA_CTRL1 */ 146 + enum { 147 + CFG_FRAME_TRIG = 1 << 31, 148 + CFG_VSYNC_INV = 1 << 27, 149 + CFG_CKMODE_MASK = 0x7 << 24, 150 + #define CFG_CKMODE(x) ((x) << 24) 151 + CFG_CARRY = 1 << 23, 152 + CFG_GATED_CLK = 1 << 21, 153 + CFG_PWRDN_ENA = 1 << 20, 154 + CFG_DSCALE_MASK = 0x3 << 18, 155 + CFG_DSCALE_NONE = 0x0 << 18, 156 + CFG_DSCALE_HALF = 0x1 << 18, 157 + CFG_DSCALE_QUAR = 0x2 << 18, 158 + CFG_ALPHAM_MASK = 0x3 << 16, 159 + CFG_ALPHAM_VIDEO = 0x0 << 16, 160 + CFG_ALPHAM_GRA = 0x1 << 16, 161 + CFG_ALPHAM_CFG = 0x2 << 16, 162 + CFG_ALPHA_MASK = 0xff << 8, 163 + CFG_PIXCMD_MASK = 0xff, 164 + }; 165 + 166 + /* For LCD_SPU_SRAM_CTRL */ 167 + enum { 168 + SRAM_READ = 0 << 14, 169 + SRAM_WRITE = 2 << 14, 170 + SRAM_INIT = 3 << 14, 171 + SRAM_HWC32_RAM1 = 0xc << 8, 172 + SRAM_HWC32_RAM2 = 0xd << 8, 173 + SRAM_HWC32_RAMR = SRAM_HWC32_RAM1, 174 + SRAM_HWC32_RAMG = SRAM_HWC32_RAM2, 175 + SRAM_HWC32_RAMB = 0xe << 8, 176 + SRAM_HWC32_TRAN = 0xf << 8, 177 + SRAM_HWC = 0xf << 8, 178 + }; 179 + 180 + /* For LCD_SPU_SRAM_PARA1 */ 181 + enum { 182 + CFG_CSB_256x32 = 1 << 15, /* cursor */ 183 + CFG_CSB_256x24 = 1 << 14, /* palette */ 184 + CFG_CSB_256x8 = 1 << 13, /* gamma */ 185 + CFG_PDWN1920x32 = 1 << 8, /* Armada 510: power down vscale ram */ 186 + CFG_PDWN256x32 = 1 << 7, /* power down cursor */ 187 + CFG_PDWN256x24 = 1 << 6, /* power down palette */ 188 + CFG_PDWN256x8 = 1 << 5, /* power down gamma */ 189 + CFG_PDWNHWC = 1 << 4, /* Armada 510: power down all hwc ram */ 190 + CFG_PDWN32x32 = 1 << 3, /* power down slave->smart ram */ 191 + CFG_PDWN16x66 = 1 << 2, /* power down UV fifo */ 192 + CFG_PDWN32x66 = 1 << 1, /* power down Y fifo */ 193 + CFG_PDWN64x66 = 1 << 0, /* power down graphic fifo */ 194 + }; 195 + 196 + /* For LCD_CFG_SCLK_DIV */ 197 + enum { 198 + /* Armada 510 */ 199 + SCLK_510_AXI = 0x0 << 30, 200 + SCLK_510_EXTCLK0 = 0x1 << 30, 201 + SCLK_510_PLL = 0x2 << 30, 202 + SCLK_510_EXTCLK1 = 0x3 << 30, 203 + SCLK_510_DIV_CHANGE = 1 << 29, 204 + SCLK_510_FRAC_DIV_MASK = 0xfff << 16, 205 + SCLK_510_INT_DIV_MASK = 0xffff << 0, 206 + 207 + /* Armada 16x */ 208 + SCLK_16X_AHB = 0x0 << 28, 209 + SCLK_16X_PCLK = 0x1 << 28, 210 + SCLK_16X_AXI = 0x4 << 28, 211 + SCLK_16X_PLL = 0x8 << 28, 212 + SCLK_16X_FRAC_DIV_MASK = 0xfff << 16, 213 + SCLK_16X_INT_DIV_MASK = 0xffff << 0, 214 + }; 215 + 216 + /* For LCD_SPU_DUMB_CTRL */ 217 + enum { 218 + DUMB16_RGB565_0 = 0x0 << 28, 219 + DUMB16_RGB565_1 = 0x1 << 28, 220 + DUMB18_RGB666_0 = 0x2 << 28, 221 + DUMB18_RGB666_1 = 0x3 << 28, 222 + DUMB12_RGB444_0 = 0x4 << 28, 223 + DUMB12_RGB444_1 = 0x5 << 28, 224 + DUMB24_RGB888_0 = 0x6 << 28, 225 + DUMB_BLANK = 0x7 << 28, 226 + DUMB_MASK = 0xf << 28, 227 + CFG_BIAS_OUT = 1 << 8, 228 + CFG_REV_RGB = 1 << 7, 229 + CFG_INV_CBLANK = 1 << 6, 230 + CFG_INV_CSYNC = 1 << 5, /* Normally active high */ 231 + CFG_INV_HENA = 1 << 4, 232 + CFG_INV_VSYNC = 1 << 3, /* Normally active high */ 233 + CFG_INV_HSYNC = 1 << 2, /* Normally active high */ 234 + CFG_INV_PCLK = 1 << 1, 235 + CFG_DUMB_ENA = 1 << 0, 236 + }; 237 + 238 + /* For LCD_SPU_IOPAD_CONTROL */ 239 + enum { 240 + CFG_VSCALE_LN_EN = 3 << 18, 241 + CFG_GRA_VM_ENA = 1 << 15, 242 + CFG_DMA_VM_ENA = 1 << 13, 243 + CFG_CMD_VM_ENA = 1 << 11, 244 + CFG_CSC_MASK = 3 << 8, 245 + CFG_CSC_YUV_CCIR709 = 1 << 9, 246 + CFG_CSC_YUV_CCIR601 = 0 << 9, 247 + CFG_CSC_RGB_STUDIO = 1 << 8, 248 + CFG_CSC_RGB_COMPUTER = 0 << 8, 249 + CFG_IOPAD_MASK = 0xf << 0, 250 + CFG_IOPAD_DUMB24 = 0x0 << 0, 251 + CFG_IOPAD_DUMB18SPI = 0x1 << 0, 252 + CFG_IOPAD_DUMB18GPIO = 0x2 << 0, 253 + CFG_IOPAD_DUMB16SPI = 0x3 << 0, 254 + CFG_IOPAD_DUMB16GPIO = 0x4 << 0, 255 + CFG_IOPAD_DUMB12GPIO = 0x5 << 0, 256 + CFG_IOPAD_SMART18 = 0x6 << 0, 257 + CFG_IOPAD_SMART16 = 0x7 << 0, 258 + CFG_IOPAD_SMART8 = 0x8 << 0, 259 + }; 260 + 261 + #define IOPAD_DUMB24 0x0 262 + 263 + /* For LCD_SPU_IRQ_ENA */ 264 + enum { 265 + DMA_FRAME_IRQ0_ENA = 1 << 31, 266 + DMA_FRAME_IRQ1_ENA = 1 << 30, 267 + DMA_FRAME_IRQ_ENA = DMA_FRAME_IRQ0_ENA | DMA_FRAME_IRQ1_ENA, 268 + DMA_FF_UNDERFLOW_ENA = 1 << 29, 269 + GRA_FRAME_IRQ0_ENA = 1 << 27, 270 + GRA_FRAME_IRQ1_ENA = 1 << 26, 271 + GRA_FRAME_IRQ_ENA = GRA_FRAME_IRQ0_ENA | GRA_FRAME_IRQ1_ENA, 272 + GRA_FF_UNDERFLOW_ENA = 1 << 25, 273 + VSYNC_IRQ_ENA = 1 << 23, 274 + DUMB_FRAMEDONE_ENA = 1 << 22, 275 + TWC_FRAMEDONE_ENA = 1 << 21, 276 + HWC_FRAMEDONE_ENA = 1 << 20, 277 + SLV_IRQ_ENA = 1 << 19, 278 + SPI_IRQ_ENA = 1 << 18, 279 + PWRDN_IRQ_ENA = 1 << 17, 280 + ERR_IRQ_ENA = 1 << 16, 281 + CLEAN_SPU_IRQ_ISR = 0xffff, 282 + }; 283 + 284 + /* For LCD_SPU_IRQ_ISR */ 285 + enum { 286 + DMA_FRAME_IRQ0 = 1 << 31, 287 + DMA_FRAME_IRQ1 = 1 << 30, 288 + DMA_FRAME_IRQ = DMA_FRAME_IRQ0 | DMA_FRAME_IRQ1, 289 + DMA_FF_UNDERFLOW = 1 << 29, 290 + GRA_FRAME_IRQ0 = 1 << 27, 291 + GRA_FRAME_IRQ1 = 1 << 26, 292 + GRA_FRAME_IRQ = GRA_FRAME_IRQ0 | GRA_FRAME_IRQ1, 293 + GRA_FF_UNDERFLOW = 1 << 25, 294 + VSYNC_IRQ = 1 << 23, 295 + DUMB_FRAMEDONE = 1 << 22, 296 + TWC_FRAMEDONE = 1 << 21, 297 + HWC_FRAMEDONE = 1 << 20, 298 + SLV_IRQ = 1 << 19, 299 + SPI_IRQ = 1 << 18, 300 + PWRDN_IRQ = 1 << 17, 301 + ERR_IRQ = 1 << 16, 302 + DMA_FRAME_IRQ0_LEVEL = 1 << 15, 303 + DMA_FRAME_IRQ1_LEVEL = 1 << 14, 304 + DMA_FRAME_CNT_ISR = 3 << 12, 305 + GRA_FRAME_IRQ0_LEVEL = 1 << 11, 306 + GRA_FRAME_IRQ1_LEVEL = 1 << 10, 307 + GRA_FRAME_CNT_ISR = 3 << 8, 308 + VSYNC_IRQ_LEVEL = 1 << 7, 309 + DUMB_FRAMEDONE_LEVEL = 1 << 6, 310 + TWC_FRAMEDONE_LEVEL = 1 << 5, 311 + HWC_FRAMEDONE_LEVEL = 1 << 4, 312 + SLV_FF_EMPTY = 1 << 3, 313 + DMA_FF_ALLEMPTY = 1 << 2, 314 + GRA_FF_ALLEMPTY = 1 << 1, 315 + PWRDN_IRQ_LEVEL = 1 << 0, 316 + }; 317 + 318 + #endif
+18
drivers/gpu/drm/armada/armada_ioctlP.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #ifndef ARMADA_IOCTLP_H 9 + #define ARMADA_IOCTLP_H 10 + 11 + #define ARMADA_IOCTL_PROTO(name)\ 12 + extern int armada_##name##_ioctl(struct drm_device *, void *, struct drm_file *) 13 + 14 + ARMADA_IOCTL_PROTO(gem_create); 15 + ARMADA_IOCTL_PROTO(gem_mmap); 16 + ARMADA_IOCTL_PROTO(gem_pwrite); 17 + 18 + #endif
+158
drivers/gpu/drm/armada/armada_output.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #include <drm/drmP.h> 9 + #include <drm/drm_crtc_helper.h> 10 + #include <drm/drm_edid.h> 11 + #include <drm/drm_encoder_slave.h> 12 + #include "armada_output.h" 13 + #include "armada_drm.h" 14 + 15 + struct armada_connector { 16 + struct drm_connector conn; 17 + const struct armada_output_type *type; 18 + }; 19 + 20 + #define drm_to_armada_conn(c) container_of(c, struct armada_connector, conn) 21 + 22 + struct drm_encoder *armada_drm_connector_encoder(struct drm_connector *conn) 23 + { 24 + struct drm_encoder *enc = conn->encoder; 25 + 26 + return enc ? enc : drm_encoder_find(conn->dev, conn->encoder_ids[0]); 27 + } 28 + 29 + static enum drm_connector_status armada_drm_connector_detect( 30 + struct drm_connector *conn, bool force) 31 + { 32 + struct armada_connector *dconn = drm_to_armada_conn(conn); 33 + enum drm_connector_status status = connector_status_disconnected; 34 + 35 + if (dconn->type->detect) { 36 + status = dconn->type->detect(conn, force); 37 + } else { 38 + struct drm_encoder *enc = armada_drm_connector_encoder(conn); 39 + 40 + if (enc) 41 + status = encoder_helper_funcs(enc)->detect(enc, conn); 42 + } 43 + 44 + return status; 45 + } 46 + 47 + static void armada_drm_connector_destroy(struct drm_connector *conn) 48 + { 49 + struct armada_connector *dconn = drm_to_armada_conn(conn); 50 + 51 + drm_sysfs_connector_remove(conn); 52 + drm_connector_cleanup(conn); 53 + kfree(dconn); 54 + } 55 + 56 + static int armada_drm_connector_set_property(struct drm_connector *conn, 57 + struct drm_property *property, uint64_t value) 58 + { 59 + struct armada_connector *dconn = drm_to_armada_conn(conn); 60 + 61 + if (!dconn->type->set_property) 62 + return -EINVAL; 63 + 64 + return dconn->type->set_property(conn, property, value); 65 + } 66 + 67 + static const struct drm_connector_funcs armada_drm_conn_funcs = { 68 + .dpms = drm_helper_connector_dpms, 69 + .fill_modes = drm_helper_probe_single_connector_modes, 70 + .detect = armada_drm_connector_detect, 71 + .destroy = armada_drm_connector_destroy, 72 + .set_property = armada_drm_connector_set_property, 73 + }; 74 + 75 + void armada_drm_encoder_prepare(struct drm_encoder *encoder) 76 + { 77 + encoder_helper_funcs(encoder)->dpms(encoder, DRM_MODE_DPMS_OFF); 78 + } 79 + 80 + void armada_drm_encoder_commit(struct drm_encoder *encoder) 81 + { 82 + encoder_helper_funcs(encoder)->dpms(encoder, DRM_MODE_DPMS_ON); 83 + } 84 + 85 + bool armada_drm_encoder_mode_fixup(struct drm_encoder *encoder, 86 + const struct drm_display_mode *mode, struct drm_display_mode *adjusted) 87 + { 88 + return true; 89 + } 90 + 91 + /* Shouldn't this be a generic helper function? */ 92 + int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn, 93 + struct drm_display_mode *mode) 94 + { 95 + struct drm_encoder *encoder = armada_drm_connector_encoder(conn); 96 + int valid = MODE_BAD; 97 + 98 + if (encoder) { 99 + struct drm_encoder_slave *slave = to_encoder_slave(encoder); 100 + 101 + valid = slave->slave_funcs->mode_valid(encoder, mode); 102 + } 103 + return valid; 104 + } 105 + 106 + int armada_drm_slave_encoder_set_property(struct drm_connector *conn, 107 + struct drm_property *property, uint64_t value) 108 + { 109 + struct drm_encoder *encoder = armada_drm_connector_encoder(conn); 110 + int rc = -EINVAL; 111 + 112 + if (encoder) { 113 + struct drm_encoder_slave *slave = to_encoder_slave(encoder); 114 + 115 + rc = slave->slave_funcs->set_property(encoder, conn, property, 116 + value); 117 + } 118 + return rc; 119 + } 120 + 121 + int armada_output_create(struct drm_device *dev, 122 + const struct armada_output_type *type, const void *data) 123 + { 124 + struct armada_connector *dconn; 125 + int ret; 126 + 127 + dconn = kzalloc(sizeof(*dconn), GFP_KERNEL); 128 + if (!dconn) 129 + return -ENOMEM; 130 + 131 + dconn->type = type; 132 + 133 + ret = drm_connector_init(dev, &dconn->conn, &armada_drm_conn_funcs, 134 + type->connector_type); 135 + if (ret) { 136 + DRM_ERROR("unable to init connector\n"); 137 + goto err_destroy_dconn; 138 + } 139 + 140 + ret = type->create(&dconn->conn, data); 141 + if (ret) 142 + goto err_conn; 143 + 144 + ret = drm_sysfs_connector_add(&dconn->conn); 145 + if (ret) 146 + goto err_sysfs; 147 + 148 + return 0; 149 + 150 + err_sysfs: 151 + if (dconn->conn.encoder) 152 + dconn->conn.encoder->funcs->destroy(dconn->conn.encoder); 153 + err_conn: 154 + drm_connector_cleanup(&dconn->conn); 155 + err_destroy_dconn: 156 + kfree(dconn); 157 + return ret; 158 + }
+39
drivers/gpu/drm/armada/armada_output.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #ifndef ARMADA_CONNETOR_H 9 + #define ARMADA_CONNETOR_H 10 + 11 + #define encoder_helper_funcs(encoder) \ 12 + ((struct drm_encoder_helper_funcs *)encoder->helper_private) 13 + 14 + struct armada_output_type { 15 + int connector_type; 16 + enum drm_connector_status (*detect)(struct drm_connector *, bool); 17 + int (*create)(struct drm_connector *, const void *); 18 + int (*set_property)(struct drm_connector *, struct drm_property *, 19 + uint64_t); 20 + }; 21 + 22 + struct drm_encoder *armada_drm_connector_encoder(struct drm_connector *conn); 23 + 24 + void armada_drm_encoder_prepare(struct drm_encoder *encoder); 25 + void armada_drm_encoder_commit(struct drm_encoder *encoder); 26 + 27 + bool armada_drm_encoder_mode_fixup(struct drm_encoder *encoder, 28 + const struct drm_display_mode *mode, struct drm_display_mode *adj); 29 + 30 + int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn, 31 + struct drm_display_mode *mode); 32 + 33 + int armada_drm_slave_encoder_set_property(struct drm_connector *conn, 34 + struct drm_property *property, uint64_t value); 35 + 36 + int armada_output_create(struct drm_device *dev, 37 + const struct armada_output_type *type, const void *data); 38 + 39 + #endif
+477
drivers/gpu/drm/armada/armada_overlay.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * Rewritten from the dovefb driver, and Armada510 manuals. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + #include <drm/drmP.h> 10 + #include "armada_crtc.h" 11 + #include "armada_drm.h" 12 + #include "armada_fb.h" 13 + #include "armada_gem.h" 14 + #include "armada_hw.h" 15 + #include <drm/armada_drm.h> 16 + #include "armada_ioctlP.h" 17 + 18 + struct armada_plane_properties { 19 + uint32_t colorkey_yr; 20 + uint32_t colorkey_ug; 21 + uint32_t colorkey_vb; 22 + #define K2R(val) (((val) >> 0) & 0xff) 23 + #define K2G(val) (((val) >> 8) & 0xff) 24 + #define K2B(val) (((val) >> 16) & 0xff) 25 + int16_t brightness; 26 + uint16_t contrast; 27 + uint16_t saturation; 28 + uint32_t colorkey_mode; 29 + }; 30 + 31 + struct armada_plane { 32 + struct drm_plane base; 33 + spinlock_t lock; 34 + struct drm_framebuffer *old_fb; 35 + uint32_t src_hw; 36 + uint32_t dst_hw; 37 + uint32_t dst_yx; 38 + uint32_t ctrl0; 39 + struct { 40 + struct armada_vbl_event update; 41 + struct armada_regs regs[13]; 42 + wait_queue_head_t wait; 43 + } vbl; 44 + struct armada_plane_properties prop; 45 + }; 46 + #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) 47 + 48 + 49 + static void 50 + armada_ovl_update_attr(struct armada_plane_properties *prop, 51 + struct armada_crtc *dcrtc) 52 + { 53 + writel_relaxed(prop->colorkey_yr, dcrtc->base + LCD_SPU_COLORKEY_Y); 54 + writel_relaxed(prop->colorkey_ug, dcrtc->base + LCD_SPU_COLORKEY_U); 55 + writel_relaxed(prop->colorkey_vb, dcrtc->base + LCD_SPU_COLORKEY_V); 56 + 57 + writel_relaxed(prop->brightness << 16 | prop->contrast, 58 + dcrtc->base + LCD_SPU_CONTRAST); 59 + /* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */ 60 + writel_relaxed(prop->saturation << 16, 61 + dcrtc->base + LCD_SPU_SATURATION); 62 + writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE); 63 + 64 + spin_lock_irq(&dcrtc->irq_lock); 65 + armada_updatel(prop->colorkey_mode | CFG_ALPHAM_GRA, 66 + CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, 67 + dcrtc->base + LCD_SPU_DMA_CTRL1); 68 + 69 + armada_updatel(ADV_GRACOLORKEY, 0, dcrtc->base + LCD_SPU_ADV_REG); 70 + spin_unlock_irq(&dcrtc->irq_lock); 71 + } 72 + 73 + /* === Plane support === */ 74 + static void armada_plane_vbl(struct armada_crtc *dcrtc, void *data) 75 + { 76 + struct armada_plane *dplane = data; 77 + struct drm_framebuffer *fb; 78 + 79 + armada_drm_crtc_update_regs(dcrtc, dplane->vbl.regs); 80 + 81 + spin_lock(&dplane->lock); 82 + fb = dplane->old_fb; 83 + dplane->old_fb = NULL; 84 + spin_unlock(&dplane->lock); 85 + 86 + if (fb) 87 + armada_drm_queue_unref_work(dcrtc->crtc.dev, fb); 88 + } 89 + 90 + static unsigned armada_limit(int start, unsigned size, unsigned max) 91 + { 92 + int end = start + size; 93 + if (end < 0) 94 + return 0; 95 + if (start < 0) 96 + start = 0; 97 + return (unsigned)end > max ? max - start : end - start; 98 + } 99 + 100 + static int 101 + armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, 102 + struct drm_framebuffer *fb, 103 + int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h, 104 + uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) 105 + { 106 + struct armada_plane *dplane = drm_to_armada_plane(plane); 107 + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 108 + uint32_t val, ctrl0; 109 + unsigned idx = 0; 110 + int ret; 111 + 112 + crtc_w = armada_limit(crtc_x, crtc_w, dcrtc->crtc.mode.hdisplay); 113 + crtc_h = armada_limit(crtc_y, crtc_h, dcrtc->crtc.mode.vdisplay); 114 + ctrl0 = CFG_DMA_FMT(drm_fb_to_armada_fb(fb)->fmt) | 115 + CFG_DMA_MOD(drm_fb_to_armada_fb(fb)->mod) | 116 + CFG_CBSH_ENA | CFG_DMA_HSMOOTH | CFG_DMA_ENA; 117 + 118 + /* Does the position/size result in nothing to display? */ 119 + if (crtc_w == 0 || crtc_h == 0) { 120 + ctrl0 &= ~CFG_DMA_ENA; 121 + } 122 + 123 + /* 124 + * FIXME: if the starting point is off screen, we need to 125 + * adjust src_x, src_y, src_w, src_h appropriately, and 126 + * according to the scale. 127 + */ 128 + 129 + if (!dcrtc->plane) { 130 + dcrtc->plane = plane; 131 + armada_ovl_update_attr(&dplane->prop, dcrtc); 132 + } 133 + 134 + /* FIXME: overlay on an interlaced display */ 135 + /* Just updating the position/size? */ 136 + if (plane->fb == fb && dplane->ctrl0 == ctrl0) { 137 + val = (src_h & 0xffff0000) | src_w >> 16; 138 + dplane->src_hw = val; 139 + writel_relaxed(val, dcrtc->base + LCD_SPU_DMA_HPXL_VLN); 140 + val = crtc_h << 16 | crtc_w; 141 + dplane->dst_hw = val; 142 + writel_relaxed(val, dcrtc->base + LCD_SPU_DZM_HPXL_VLN); 143 + val = crtc_y << 16 | crtc_x; 144 + dplane->dst_yx = val; 145 + writel_relaxed(val, dcrtc->base + LCD_SPU_DMA_OVSA_HPXL_VLN); 146 + return 0; 147 + } else if (~dplane->ctrl0 & ctrl0 & CFG_DMA_ENA) { 148 + /* Power up the Y/U/V FIFOs on ENA 0->1 transitions */ 149 + armada_updatel(0, CFG_PDWN16x66 | CFG_PDWN32x66, 150 + dcrtc->base + LCD_SPU_SRAM_PARA1); 151 + } 152 + 153 + ret = wait_event_timeout(dplane->vbl.wait, 154 + list_empty(&dplane->vbl.update.node), 155 + HZ/25); 156 + if (ret < 0) 157 + return ret; 158 + 159 + if (plane->fb != fb) { 160 + struct armada_gem_object *obj = drm_fb_obj(fb); 161 + uint32_t sy, su, sv; 162 + 163 + /* 164 + * Take a reference on the new framebuffer - we want to 165 + * hold on to it while the hardware is displaying it. 166 + */ 167 + drm_framebuffer_reference(fb); 168 + 169 + if (plane->fb) { 170 + struct drm_framebuffer *older_fb; 171 + 172 + spin_lock_irq(&dplane->lock); 173 + older_fb = dplane->old_fb; 174 + dplane->old_fb = plane->fb; 175 + spin_unlock_irq(&dplane->lock); 176 + if (older_fb) 177 + armada_drm_queue_unref_work(dcrtc->crtc.dev, 178 + older_fb); 179 + } 180 + 181 + src_y >>= 16; 182 + src_x >>= 16; 183 + sy = obj->dev_addr + fb->offsets[0] + src_y * fb->pitches[0] + 184 + src_x * fb->bits_per_pixel / 8; 185 + su = obj->dev_addr + fb->offsets[1] + src_y * fb->pitches[1] + 186 + src_x; 187 + sv = obj->dev_addr + fb->offsets[2] + src_y * fb->pitches[2] + 188 + src_x; 189 + 190 + armada_reg_queue_set(dplane->vbl.regs, idx, sy, 191 + LCD_SPU_DMA_START_ADDR_Y0); 192 + armada_reg_queue_set(dplane->vbl.regs, idx, su, 193 + LCD_SPU_DMA_START_ADDR_U0); 194 + armada_reg_queue_set(dplane->vbl.regs, idx, sv, 195 + LCD_SPU_DMA_START_ADDR_V0); 196 + armada_reg_queue_set(dplane->vbl.regs, idx, sy, 197 + LCD_SPU_DMA_START_ADDR_Y1); 198 + armada_reg_queue_set(dplane->vbl.regs, idx, su, 199 + LCD_SPU_DMA_START_ADDR_U1); 200 + armada_reg_queue_set(dplane->vbl.regs, idx, sv, 201 + LCD_SPU_DMA_START_ADDR_V1); 202 + 203 + val = fb->pitches[0] << 16 | fb->pitches[0]; 204 + armada_reg_queue_set(dplane->vbl.regs, idx, val, 205 + LCD_SPU_DMA_PITCH_YC); 206 + val = fb->pitches[1] << 16 | fb->pitches[2]; 207 + armada_reg_queue_set(dplane->vbl.regs, idx, val, 208 + LCD_SPU_DMA_PITCH_UV); 209 + } 210 + 211 + val = (src_h & 0xffff0000) | src_w >> 16; 212 + if (dplane->src_hw != val) { 213 + dplane->src_hw = val; 214 + armada_reg_queue_set(dplane->vbl.regs, idx, val, 215 + LCD_SPU_DMA_HPXL_VLN); 216 + } 217 + val = crtc_h << 16 | crtc_w; 218 + if (dplane->dst_hw != val) { 219 + dplane->dst_hw = val; 220 + armada_reg_queue_set(dplane->vbl.regs, idx, val, 221 + LCD_SPU_DZM_HPXL_VLN); 222 + } 223 + val = crtc_y << 16 | crtc_x; 224 + if (dplane->dst_yx != val) { 225 + dplane->dst_yx = val; 226 + armada_reg_queue_set(dplane->vbl.regs, idx, val, 227 + LCD_SPU_DMA_OVSA_HPXL_VLN); 228 + } 229 + if (dplane->ctrl0 != ctrl0) { 230 + dplane->ctrl0 = ctrl0; 231 + armada_reg_queue_mod(dplane->vbl.regs, idx, ctrl0, 232 + CFG_CBSH_ENA | CFG_DMAFORMAT | CFG_DMA_FTOGGLE | 233 + CFG_DMA_HSMOOTH | CFG_DMA_TSTMODE | 234 + CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | CFG_SWAPYU | 235 + CFG_YUV2RGB) | CFG_DMA_ENA, 236 + LCD_SPU_DMA_CTRL0); 237 + } 238 + if (idx) { 239 + armada_reg_queue_end(dplane->vbl.regs, idx); 240 + armada_drm_vbl_event_add(dcrtc, &dplane->vbl.update); 241 + } 242 + return 0; 243 + } 244 + 245 + static int armada_plane_disable(struct drm_plane *plane) 246 + { 247 + struct armada_plane *dplane = drm_to_armada_plane(plane); 248 + struct drm_framebuffer *fb; 249 + struct armada_crtc *dcrtc; 250 + 251 + if (!dplane->base.crtc) 252 + return 0; 253 + 254 + dcrtc = drm_to_armada_crtc(dplane->base.crtc); 255 + dcrtc->plane = NULL; 256 + 257 + spin_lock_irq(&dcrtc->irq_lock); 258 + armada_drm_vbl_event_remove(dcrtc, &dplane->vbl.update); 259 + armada_updatel(0, CFG_DMA_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0); 260 + dplane->ctrl0 = 0; 261 + spin_unlock_irq(&dcrtc->irq_lock); 262 + 263 + /* Power down the Y/U/V FIFOs */ 264 + armada_updatel(CFG_PDWN16x66 | CFG_PDWN32x66, 0, 265 + dcrtc->base + LCD_SPU_SRAM_PARA1); 266 + 267 + if (plane->fb) 268 + drm_framebuffer_unreference(plane->fb); 269 + 270 + spin_lock_irq(&dplane->lock); 271 + fb = dplane->old_fb; 272 + dplane->old_fb = NULL; 273 + spin_unlock_irq(&dplane->lock); 274 + if (fb) 275 + drm_framebuffer_unreference(fb); 276 + 277 + return 0; 278 + } 279 + 280 + static void armada_plane_destroy(struct drm_plane *plane) 281 + { 282 + kfree(plane); 283 + } 284 + 285 + static int armada_plane_set_property(struct drm_plane *plane, 286 + struct drm_property *property, uint64_t val) 287 + { 288 + struct armada_private *priv = plane->dev->dev_private; 289 + struct armada_plane *dplane = drm_to_armada_plane(plane); 290 + bool update_attr = false; 291 + 292 + if (property == priv->colorkey_prop) { 293 + #define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8) 294 + dplane->prop.colorkey_yr = CCC(K2R(val)); 295 + dplane->prop.colorkey_ug = CCC(K2G(val)); 296 + dplane->prop.colorkey_vb = CCC(K2B(val)); 297 + #undef CCC 298 + update_attr = true; 299 + } else if (property == priv->colorkey_min_prop) { 300 + dplane->prop.colorkey_yr &= ~0x00ff0000; 301 + dplane->prop.colorkey_yr |= K2R(val) << 16; 302 + dplane->prop.colorkey_ug &= ~0x00ff0000; 303 + dplane->prop.colorkey_ug |= K2G(val) << 16; 304 + dplane->prop.colorkey_vb &= ~0x00ff0000; 305 + dplane->prop.colorkey_vb |= K2B(val) << 16; 306 + update_attr = true; 307 + } else if (property == priv->colorkey_max_prop) { 308 + dplane->prop.colorkey_yr &= ~0xff000000; 309 + dplane->prop.colorkey_yr |= K2R(val) << 24; 310 + dplane->prop.colorkey_ug &= ~0xff000000; 311 + dplane->prop.colorkey_ug |= K2G(val) << 24; 312 + dplane->prop.colorkey_vb &= ~0xff000000; 313 + dplane->prop.colorkey_vb |= K2B(val) << 24; 314 + update_attr = true; 315 + } else if (property == priv->colorkey_val_prop) { 316 + dplane->prop.colorkey_yr &= ~0x0000ff00; 317 + dplane->prop.colorkey_yr |= K2R(val) << 8; 318 + dplane->prop.colorkey_ug &= ~0x0000ff00; 319 + dplane->prop.colorkey_ug |= K2G(val) << 8; 320 + dplane->prop.colorkey_vb &= ~0x0000ff00; 321 + dplane->prop.colorkey_vb |= K2B(val) << 8; 322 + update_attr = true; 323 + } else if (property == priv->colorkey_alpha_prop) { 324 + dplane->prop.colorkey_yr &= ~0x000000ff; 325 + dplane->prop.colorkey_yr |= K2R(val); 326 + dplane->prop.colorkey_ug &= ~0x000000ff; 327 + dplane->prop.colorkey_ug |= K2G(val); 328 + dplane->prop.colorkey_vb &= ~0x000000ff; 329 + dplane->prop.colorkey_vb |= K2B(val); 330 + update_attr = true; 331 + } else if (property == priv->colorkey_mode_prop) { 332 + dplane->prop.colorkey_mode &= ~CFG_CKMODE_MASK; 333 + dplane->prop.colorkey_mode |= CFG_CKMODE(val); 334 + update_attr = true; 335 + } else if (property == priv->brightness_prop) { 336 + dplane->prop.brightness = val - 256; 337 + update_attr = true; 338 + } else if (property == priv->contrast_prop) { 339 + dplane->prop.contrast = val; 340 + update_attr = true; 341 + } else if (property == priv->saturation_prop) { 342 + dplane->prop.saturation = val; 343 + update_attr = true; 344 + } 345 + 346 + if (update_attr && dplane->base.crtc) 347 + armada_ovl_update_attr(&dplane->prop, 348 + drm_to_armada_crtc(dplane->base.crtc)); 349 + 350 + return 0; 351 + } 352 + 353 + static const struct drm_plane_funcs armada_plane_funcs = { 354 + .update_plane = armada_plane_update, 355 + .disable_plane = armada_plane_disable, 356 + .destroy = armada_plane_destroy, 357 + .set_property = armada_plane_set_property, 358 + }; 359 + 360 + static const uint32_t armada_formats[] = { 361 + DRM_FORMAT_UYVY, 362 + DRM_FORMAT_YUYV, 363 + DRM_FORMAT_YUV420, 364 + DRM_FORMAT_YVU420, 365 + DRM_FORMAT_YUV422, 366 + DRM_FORMAT_YVU422, 367 + DRM_FORMAT_VYUY, 368 + DRM_FORMAT_YVYU, 369 + DRM_FORMAT_ARGB8888, 370 + DRM_FORMAT_ABGR8888, 371 + DRM_FORMAT_XRGB8888, 372 + DRM_FORMAT_XBGR8888, 373 + DRM_FORMAT_RGB888, 374 + DRM_FORMAT_BGR888, 375 + DRM_FORMAT_ARGB1555, 376 + DRM_FORMAT_ABGR1555, 377 + DRM_FORMAT_RGB565, 378 + DRM_FORMAT_BGR565, 379 + }; 380 + 381 + static struct drm_prop_enum_list armada_drm_colorkey_enum_list[] = { 382 + { CKMODE_DISABLE, "disabled" }, 383 + { CKMODE_Y, "Y component" }, 384 + { CKMODE_U, "U component" }, 385 + { CKMODE_V, "V component" }, 386 + { CKMODE_RGB, "RGB" }, 387 + { CKMODE_R, "R component" }, 388 + { CKMODE_G, "G component" }, 389 + { CKMODE_B, "B component" }, 390 + }; 391 + 392 + static int armada_overlay_create_properties(struct drm_device *dev) 393 + { 394 + struct armada_private *priv = dev->dev_private; 395 + 396 + if (priv->colorkey_prop) 397 + return 0; 398 + 399 + priv->colorkey_prop = drm_property_create_range(dev, 0, 400 + "colorkey", 0, 0xffffff); 401 + priv->colorkey_min_prop = drm_property_create_range(dev, 0, 402 + "colorkey_min", 0, 0xffffff); 403 + priv->colorkey_max_prop = drm_property_create_range(dev, 0, 404 + "colorkey_max", 0, 0xffffff); 405 + priv->colorkey_val_prop = drm_property_create_range(dev, 0, 406 + "colorkey_val", 0, 0xffffff); 407 + priv->colorkey_alpha_prop = drm_property_create_range(dev, 0, 408 + "colorkey_alpha", 0, 0xffffff); 409 + priv->colorkey_mode_prop = drm_property_create_enum(dev, 0, 410 + "colorkey_mode", 411 + armada_drm_colorkey_enum_list, 412 + ARRAY_SIZE(armada_drm_colorkey_enum_list)); 413 + priv->brightness_prop = drm_property_create_range(dev, 0, 414 + "brightness", 0, 256 + 255); 415 + priv->contrast_prop = drm_property_create_range(dev, 0, 416 + "contrast", 0, 0x7fff); 417 + priv->saturation_prop = drm_property_create_range(dev, 0, 418 + "saturation", 0, 0x7fff); 419 + 420 + if (!priv->colorkey_prop) 421 + return -ENOMEM; 422 + 423 + return 0; 424 + } 425 + 426 + int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) 427 + { 428 + struct armada_private *priv = dev->dev_private; 429 + struct drm_mode_object *mobj; 430 + struct armada_plane *dplane; 431 + int ret; 432 + 433 + ret = armada_overlay_create_properties(dev); 434 + if (ret) 435 + return ret; 436 + 437 + dplane = kzalloc(sizeof(*dplane), GFP_KERNEL); 438 + if (!dplane) 439 + return -ENOMEM; 440 + 441 + spin_lock_init(&dplane->lock); 442 + init_waitqueue_head(&dplane->vbl.wait); 443 + armada_drm_vbl_event_init(&dplane->vbl.update, armada_plane_vbl, 444 + dplane); 445 + 446 + drm_plane_init(dev, &dplane->base, crtcs, &armada_plane_funcs, 447 + armada_formats, ARRAY_SIZE(armada_formats), false); 448 + 449 + dplane->prop.colorkey_yr = 0xfefefe00; 450 + dplane->prop.colorkey_ug = 0x01010100; 451 + dplane->prop.colorkey_vb = 0x01010100; 452 + dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB); 453 + dplane->prop.brightness = 0; 454 + dplane->prop.contrast = 0x4000; 455 + dplane->prop.saturation = 0x4000; 456 + 457 + mobj = &dplane->base.base; 458 + drm_object_attach_property(mobj, priv->colorkey_prop, 459 + 0x0101fe); 460 + drm_object_attach_property(mobj, priv->colorkey_min_prop, 461 + 0x0101fe); 462 + drm_object_attach_property(mobj, priv->colorkey_max_prop, 463 + 0x0101fe); 464 + drm_object_attach_property(mobj, priv->colorkey_val_prop, 465 + 0x0101fe); 466 + drm_object_attach_property(mobj, priv->colorkey_alpha_prop, 467 + 0x000000); 468 + drm_object_attach_property(mobj, priv->colorkey_mode_prop, 469 + CKMODE_RGB); 470 + drm_object_attach_property(mobj, priv->brightness_prop, 256); 471 + drm_object_attach_property(mobj, priv->contrast_prop, 472 + dplane->prop.contrast); 473 + drm_object_attach_property(mobj, priv->saturation_prop, 474 + dplane->prop.saturation); 475 + 476 + return 0; 477 + }
+139
drivers/gpu/drm/armada/armada_slave.c
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * Rewritten from the dovefb driver, and Armada510 manuals. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + #include <drm/drmP.h> 10 + #include <drm/drm_crtc_helper.h> 11 + #include <drm/drm_edid.h> 12 + #include <drm/drm_encoder_slave.h> 13 + #include "armada_drm.h" 14 + #include "armada_output.h" 15 + #include "armada_slave.h" 16 + 17 + static int armada_drm_slave_get_modes(struct drm_connector *conn) 18 + { 19 + struct drm_encoder *enc = armada_drm_connector_encoder(conn); 20 + int count = 0; 21 + 22 + if (enc) { 23 + struct drm_encoder_slave *slave = to_encoder_slave(enc); 24 + 25 + count = slave->slave_funcs->get_modes(enc, conn); 26 + } 27 + 28 + return count; 29 + } 30 + 31 + static void armada_drm_slave_destroy(struct drm_encoder *enc) 32 + { 33 + struct drm_encoder_slave *slave = to_encoder_slave(enc); 34 + struct i2c_client *client = drm_i2c_encoder_get_client(enc); 35 + 36 + if (slave->slave_funcs) 37 + slave->slave_funcs->destroy(enc); 38 + if (client) 39 + i2c_put_adapter(client->adapter); 40 + 41 + drm_encoder_cleanup(&slave->base); 42 + kfree(slave); 43 + } 44 + 45 + static const struct drm_encoder_funcs armada_drm_slave_encoder_funcs = { 46 + .destroy = armada_drm_slave_destroy, 47 + }; 48 + 49 + static const struct drm_connector_helper_funcs armada_drm_slave_helper_funcs = { 50 + .get_modes = armada_drm_slave_get_modes, 51 + .mode_valid = armada_drm_slave_encoder_mode_valid, 52 + .best_encoder = armada_drm_connector_encoder, 53 + }; 54 + 55 + static const struct drm_encoder_helper_funcs drm_slave_encoder_helpers = { 56 + .dpms = drm_i2c_encoder_dpms, 57 + .save = drm_i2c_encoder_save, 58 + .restore = drm_i2c_encoder_restore, 59 + .mode_fixup = drm_i2c_encoder_mode_fixup, 60 + .prepare = drm_i2c_encoder_prepare, 61 + .commit = drm_i2c_encoder_commit, 62 + .mode_set = drm_i2c_encoder_mode_set, 63 + .detect = drm_i2c_encoder_detect, 64 + }; 65 + 66 + static int 67 + armada_drm_conn_slave_create(struct drm_connector *conn, const void *data) 68 + { 69 + const struct armada_drm_slave_config *config = data; 70 + struct drm_encoder_slave *slave; 71 + struct i2c_adapter *adap; 72 + int ret; 73 + 74 + conn->interlace_allowed = config->interlace_allowed; 75 + conn->doublescan_allowed = config->doublescan_allowed; 76 + conn->polled = config->polled; 77 + 78 + drm_connector_helper_add(conn, &armada_drm_slave_helper_funcs); 79 + 80 + slave = kzalloc(sizeof(*slave), GFP_KERNEL); 81 + if (!slave) 82 + return -ENOMEM; 83 + 84 + slave->base.possible_crtcs = config->crtcs; 85 + 86 + adap = i2c_get_adapter(config->i2c_adapter_id); 87 + if (!adap) { 88 + kfree(slave); 89 + return -EPROBE_DEFER; 90 + } 91 + 92 + ret = drm_encoder_init(conn->dev, &slave->base, 93 + &armada_drm_slave_encoder_funcs, 94 + DRM_MODE_ENCODER_TMDS); 95 + if (ret) { 96 + DRM_ERROR("unable to init encoder\n"); 97 + i2c_put_adapter(adap); 98 + kfree(slave); 99 + return ret; 100 + } 101 + 102 + ret = drm_i2c_encoder_init(conn->dev, slave, adap, &config->info); 103 + i2c_put_adapter(adap); 104 + if (ret) { 105 + DRM_ERROR("unable to init encoder slave\n"); 106 + armada_drm_slave_destroy(&slave->base); 107 + return ret; 108 + } 109 + 110 + drm_encoder_helper_add(&slave->base, &drm_slave_encoder_helpers); 111 + 112 + ret = slave->slave_funcs->create_resources(&slave->base, conn); 113 + if (ret) { 114 + armada_drm_slave_destroy(&slave->base); 115 + return ret; 116 + } 117 + 118 + ret = drm_mode_connector_attach_encoder(conn, &slave->base); 119 + if (ret) { 120 + armada_drm_slave_destroy(&slave->base); 121 + return ret; 122 + } 123 + 124 + conn->encoder = &slave->base; 125 + 126 + return ret; 127 + } 128 + 129 + static const struct armada_output_type armada_drm_conn_slave = { 130 + .connector_type = DRM_MODE_CONNECTOR_HDMIA, 131 + .create = armada_drm_conn_slave_create, 132 + .set_property = armada_drm_slave_encoder_set_property, 133 + }; 134 + 135 + int armada_drm_connector_slave_create(struct drm_device *dev, 136 + const struct armada_drm_slave_config *config) 137 + { 138 + return armada_output_create(dev, &armada_drm_conn_slave, config); 139 + }
+26
drivers/gpu/drm/armada/armada_slave.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + #ifndef ARMADA_SLAVE_H 9 + #define ARMADA_SLAVE_H 10 + 11 + #include <linux/i2c.h> 12 + #include <drm/drmP.h> 13 + 14 + struct armada_drm_slave_config { 15 + int i2c_adapter_id; 16 + uint32_t crtcs; 17 + uint8_t polled; 18 + bool interlace_allowed; 19 + bool doublescan_allowed; 20 + struct i2c_board_info info; 21 + }; 22 + 23 + int armada_drm_connector_slave_create(struct drm_device *dev, 24 + const struct armada_drm_slave_config *); 25 + 26 + #endif
+3
drivers/gpu/drm/i2c/tda998x_drv.c
··· 17 17 18 18 19 19 20 + #include <linux/hdmi.h> 20 21 #include <linux/module.h> 21 22 22 23 #include <drm/drmP.h> ··· 550 549 buf[HB(0)] = 0x82; 551 550 buf[HB(1)] = 0x02; 552 551 buf[HB(2)] = 13; 552 + buf[PB(1)] = HDMI_SCAN_MODE_UNDERSCAN; 553 + buf[PB(3)] = HDMI_QUANTIZATION_RANGE_FULL << 2; 553 554 buf[PB(4)] = drm_match_cea_mode(mode); 554 555 555 556 tda998x_write_if(encoder, DIP_IF_FLAGS_IF2, REG_IF2_HB0, buf,
+17
include/drm/drm_crtc.h
··· 1145 1145 extern int drm_format_vert_chroma_subsampling(uint32_t format); 1146 1146 extern const char *drm_get_format_name(uint32_t format); 1147 1147 1148 + /* Helpers */ 1149 + static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, 1150 + uint32_t id) 1151 + { 1152 + struct drm_mode_object *mo; 1153 + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CRTC); 1154 + return mo ? obj_to_crtc(mo) : NULL; 1155 + } 1156 + 1157 + static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, 1158 + uint32_t id) 1159 + { 1160 + struct drm_mode_object *mo; 1161 + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); 1162 + return mo ? obj_to_encoder(mo) : NULL; 1163 + } 1164 + 1148 1165 #endif /* __DRM_CRTC_H__ */
+45
include/uapi/drm/armada_drm.h
··· 1 + /* 2 + * Copyright (C) 2012 Russell King 3 + * With inspiration from the i915 driver 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + #ifndef DRM_ARMADA_IOCTL_H 10 + #define DRM_ARMADA_IOCTL_H 11 + 12 + #define DRM_ARMADA_GEM_CREATE 0x00 13 + #define DRM_ARMADA_GEM_MMAP 0x02 14 + #define DRM_ARMADA_GEM_PWRITE 0x03 15 + 16 + #define ARMADA_IOCTL(dir, name, str) \ 17 + DRM_##dir(DRM_COMMAND_BASE + DRM_ARMADA_##name, struct drm_armada_##str) 18 + 19 + struct drm_armada_gem_create { 20 + uint32_t handle; 21 + uint32_t size; 22 + }; 23 + #define DRM_IOCTL_ARMADA_GEM_CREATE \ 24 + ARMADA_IOCTL(IOWR, GEM_CREATE, gem_create) 25 + 26 + struct drm_armada_gem_mmap { 27 + uint32_t handle; 28 + uint32_t pad; 29 + uint64_t offset; 30 + uint64_t size; 31 + uint64_t addr; 32 + }; 33 + #define DRM_IOCTL_ARMADA_GEM_MMAP \ 34 + ARMADA_IOCTL(IOWR, GEM_MMAP, gem_mmap) 35 + 36 + struct drm_armada_gem_pwrite { 37 + uint64_t ptr; 38 + uint32_t handle; 39 + uint32_t offset; 40 + uint32_t size; 41 + }; 42 + #define DRM_IOCTL_ARMADA_GEM_PWRITE \ 43 + ARMADA_IOCTL(IOW, GEM_PWRITE, gem_pwrite) 44 + 45 + #endif