History

DRM: Armada: Add Armada DRM driver

This patch adds support for the pair of LCD controllers on the Marvell Armada 510 SoCs. This driver supports: - multiple contiguous scanout buffers for video and graphics - shm backed cacheable buffer objects for X pixmaps for Vivante GPU acceleration - dual lcd0 and lcd1 crt operation - video overlay on each LCD crt via DRM planes - page flipping of the main scanout buffers - DRM prime for buffer export/import This driver is trivial to extend to other Armada SoCs. Included in this commit is the core driver with no output support; output support is platform and encoder driver dependent.

Russell King committed 14 years ago

Commit 96f60e31 parent 15c03dd24 files · +4015 −0Browse files

Unified · Split

24 files
  1. drivers/gpu/drm/Kconfig +2 −0
  2. drivers/gpu/drm/Makefile +1 −0
  3. drivers/gpu/drm/armada/Kconfig +15 −0
  4. drivers/gpu/drm/armada/Makefile +7 −0
  5. drivers/gpu/drm/armada/armada_510.c +86 −0
  6. drivers/gpu/drm/armada/armada_crtc.c +861 −0
  7. drivers/gpu/drm/armada/armada_crtc.h +74 −0
  8. drivers/gpu/drm/armada/armada_debugfs.c +183 −0
  9. drivers/gpu/drm/armada/armada_drm.h +112 −0
  10. drivers/gpu/drm/armada/armada_drv.c +380 −0
  11. drivers/gpu/drm/armada/armada_fb.c +170 −0
  12. drivers/gpu/drm/armada/armada_fb.h +24 −0
  13. drivers/gpu/drm/armada/armada_fbdev.c +202 −0
  14. drivers/gpu/drm/armada/armada_gem.c +611 −0
  15. drivers/gpu/drm/armada/armada_gem.h +52 −0
  16. drivers/gpu/drm/armada/armada_hw.h +316 −0
  17. drivers/gpu/drm/armada/armada_ioctlP.h +18 −0
  18. drivers/gpu/drm/armada/armada_output.c +158 −0
  19. drivers/gpu/drm/armada/armada_output.h +39 −0
  20. drivers/gpu/drm/armada/armada_overlay.c +477 −0
  21. drivers/gpu/drm/armada/armada_slave.c +139 −0
  22. drivers/gpu/drm/armada/armada_slave.h +26 −0
  23. include/drm/drm_crtc.h +17 −0
  24. include/uapi/drm/armada_drm.h +45 −0
drivers/gpu/drm/Kconfig+2−0
@@ -225,6 +225,8 @@ source "drivers/gpu/drm/mgag200/Kconfig" · 224 unmodified lines
225225
226226 source "drivers/gpu/drm/cirrus/Kconfig"
227227
228+source "drivers/gpu/drm/armada/Kconfig"
229+
228230 source "drivers/gpu/drm/rcar-du/Kconfig"
229231
230232 source "drivers/gpu/drm/shmobile/Kconfig"
drivers/gpu/drm/Makefile+1−0
@@ -49,6 +49,7 @@ obj-$(CONFIG_DRM_EXYNOS) +=exynos/ · 48 unmodified lines
4949 obj-$(CONFIG_DRM_GMA500) += gma500/
5050 obj-$(CONFIG_DRM_UDL) += udl/
5151 obj-$(CONFIG_DRM_AST) += ast/
52+obj-$(CONFIG_DRM_ARMADA) += armada/
5253 obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
5354 obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
5455 obj-$(CONFIG_DRM_OMAP) += omapdrm/
drivers/gpu/drm/armada/Kconfig+15−0
@@ -0,0 +1,15 @@
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.
drivers/gpu/drm/armada/Makefile+7−0
@@ -0,0 +1,7 @@
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
drivers/gpu/drm/armada/armada_510.c+86−0
@@ -0,0 +1,86 @@
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+ .init = armada510_init,
84+ .crtc_init = armada510_crtc_init,
85+ .crtc_compute_clock = armada510_crtc_compute_clock,
86+};
drivers/gpu/drm/armada/armada_crtc.c+861−0
@@ -0,0 +1,861 @@
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, dcrtc->base + LCD_SPU_ADV_REG);
385+ }
386+ spin_unlock(&dcrtc->irq_lock);
387+
388+ if (stat & GRA_FRAME_IRQ) {
389+ struct drm_device *dev = dcrtc->crtc.dev;
390+
391+ spin_lock(&dev->event_lock);
392+ if (dcrtc->frame_work)
393+ armada_drm_crtc_complete_frame_work(dcrtc);
394+ spin_unlock(&dev->event_lock);
395+
396+ wake_up(&dcrtc->frame_wait);
397+ }
398+}
399+
400+/* These are locked by dev->vbl_lock */
401+void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask)
402+{
403+ if (dcrtc->irq_ena & mask) {
404+ dcrtc->irq_ena &= ~mask;
405+ writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
406+ }
407+}
408+
409+void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask)
410+{
411+ if ((dcrtc->irq_ena & mask) != mask) {
412+ dcrtc->irq_ena |= mask;
413+ writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
414+ if (readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR) & mask)
415+ writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
416+ }
417+}
418+
419+static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc)
420+{
421+ struct drm_display_mode *adj = &dcrtc->crtc.mode;
422+ uint32_t val = 0;
423+
424+ if (dcrtc->csc_yuv_mode == CSC_YUV_CCIR709)
425+ val |= CFG_CSC_YUV_CCIR709;
426+ if (dcrtc->csc_rgb_mode == CSC_RGB_STUDIO)
427+ val |= CFG_CSC_RGB_STUDIO;
428+
429+ /*
430+ * In auto mode, set the colorimetry, based upon the HDMI spec.
431+ * 1280x720p, 1920x1080p and 1920x1080i use ITU709, others use
432+ * ITU601. It may be more appropriate to set this depending on
433+ * the source - but what if the graphic frame is YUV and the
434+ * video frame is RGB?
435+ */
436+ if ((adj->hdisplay == 1280 && adj->vdisplay == 720 &&
437+ !(adj->flags & DRM_MODE_FLAG_INTERLACE)) ||
438+ (adj->hdisplay == 1920 && adj->vdisplay == 1080)) {
439+ if (dcrtc->csc_yuv_mode == CSC_AUTO)
440+ val |= CFG_CSC_YUV_CCIR709;
441+ }
442+
443+ /*
444+ * We assume we're connected to a TV-like device, so the YUV->RGB
445+ * conversion should produce a limited range. We should set this
446+ * depending on the connectors attached to this CRTC, and what
447+ * kind of device they report being connected.
448+ */
449+ if (dcrtc->csc_rgb_mode == CSC_AUTO)
450+ val |= CFG_CSC_RGB_STUDIO;
451+
452+ return val;
453+}
454+
455+/* The mode_config.mutex will be held for this call */
456+static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
457+ struct drm_display_mode *mode, struct drm_display_mode *adj,
458+ int x, int y, struct drm_framebuffer *old_fb)
459+{
460+ struct armada_private *priv = crtc->dev->dev_private;
461+ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
462+ struct armada_regs regs[17];
463+ uint32_t lm, rm, tm, bm, val, sclk;
464+ unsigned long flags;
465+ unsigned i;
466+ bool interlaced;
467+
468+ drm_framebuffer_reference(crtc->fb);
469+
470+ interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
471+
472+ i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced);
473+
474+ rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
475+ lm = adj->crtc_htotal - adj->crtc_hsync_end;
476+ bm = adj->crtc_vsync_start - adj->crtc_vdisplay;
477+ tm = adj->crtc_vtotal - adj->crtc_vsync_end;
478+
479+ DRM_DEBUG_DRIVER("H: %d %d %d %d lm %d rm %d\n",
480+ adj->crtc_hdisplay,
481+ adj->crtc_hsync_start,
482+ adj->crtc_hsync_end,
483+ adj->crtc_htotal, lm, rm);
484+ DRM_DEBUG_DRIVER("V: %d %d %d %d tm %d bm %d\n",
485+ adj->crtc_vdisplay,
486+ adj->crtc_vsync_start,
487+ adj->crtc_vsync_end,
488+ adj->crtc_vtotal, tm, bm);
489+
490+ /* Wait for pending flips to complete */
491+ wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
492+
493+ drm_vblank_pre_modeset(crtc->dev, dcrtc->num);
494+
495+ crtc->mode = *adj;
496+
497+ val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA;
498+ if (val != dcrtc->dumb_ctrl) {
499+ dcrtc->dumb_ctrl = val;
500+ writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL);
501+ }
502+
503+ /* Now compute the divider for real */
504+ priv->variant->crtc_compute_clock(dcrtc, adj, &sclk);
505+
506+ /* Ensure graphic fifo is enabled */
507+ armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1);
508+ armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV);
509+
510+ if (interlaced ^ dcrtc->interlaced) {
511+ if (adj->flags & DRM_MODE_FLAG_INTERLACE)
512+ drm_vblank_get(dcrtc->crtc.dev, dcrtc->num);
513+ else
514+ drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
515+ dcrtc->interlaced = interlaced;
516+ }
517+
518+ spin_lock_irqsave(&dcrtc->irq_lock, flags);
519+
520+ /* Even interlaced/progressive frame */
521+ dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 |
522+ adj->crtc_htotal;
523+ dcrtc->v[1].spu_v_porch = tm << 16 | bm;
524+ val = adj->crtc_hsync_start;
525+ dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN;
526+
527+ if (interlaced) {
528+ /* Odd interlaced frame */
529+ dcrtc->v[0].spu_v_h_total = dcrtc->v[1].spu_v_h_total +
530+ (1 << 16);
531+ dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1;
532+ val = adj->crtc_hsync_start - adj->crtc_htotal / 2;
533+ dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN;
534+ } else {
535+ dcrtc->v[0] = dcrtc->v[1];
536+ }
537+
538+ val = adj->crtc_vdisplay << 16 | adj->crtc_hdisplay;
539+
540+ armada_reg_queue_set(regs, i, val, LCD_SPU_V_H_ACTIVE);
541+ armada_reg_queue_set(regs, i, val, LCD_SPU_GRA_HPXL_VLN);
542+ armada_reg_queue_set(regs, i, val, LCD_SPU_GZM_HPXL_VLN);
543+ armada_reg_queue_set(regs, i, (lm << 16) | rm, LCD_SPU_H_PORCH);
544+ armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_porch, LCD_SPU_V_PORCH);
545+ armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total,
546+ LCD_SPUT_V_H_TOTAL);
547+
548+ if (priv->variant->has_spu_adv_reg)
549+ armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg,
550+ ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF |
551+ ADV_VSYNCOFFEN, LCD_SPU_ADV_REG);
552+
553+ val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
554+ val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt);
555+ val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod);
556+
557+ if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420)
558+ val |= CFG_PALETTE_ENA;
559+
560+ if (interlaced)
561+ val |= CFG_GRA_FTOGGLE;
562+
563+ armada_reg_queue_mod(regs, i, val, CFG_GRAFORMAT |
564+ CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
565+ CFG_SWAPYU | CFG_YUV2RGB) |
566+ CFG_PALETTE_ENA | CFG_GRA_FTOGGLE,
567+ LCD_SPU_DMA_CTRL0);
568+
569+ val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0;
570+ armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1);
571+
572+ val = dcrtc->spu_iopad_ctrl | armada_drm_crtc_calculate_csc(dcrtc);
573+ armada_reg_queue_set(regs, i, val, LCD_SPU_IOPAD_CONTROL);
574+ armada_reg_queue_end(regs, i);
575+
576+ armada_drm_crtc_update_regs(dcrtc, regs);
577+ spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
578+
579+ armada_drm_crtc_update(dcrtc);
580+
581+ drm_vblank_post_modeset(crtc->dev, dcrtc->num);
582+ armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms));
583+
584+ return 0;
585+}
586+
587+/* The mode_config.mutex will be held for this call */
588+static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
589+ struct drm_framebuffer *old_fb)
590+{
591+ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
592+ struct armada_regs regs[4];
593+ unsigned i;
594+
595+ i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs,
596+ dcrtc->interlaced);
597+ armada_reg_queue_end(regs, i);
598+
599+ /* Wait for pending flips to complete */
600+ wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
601+
602+ /* Take a reference to the new fb as we're using it */
603+ drm_framebuffer_reference(crtc->fb);
604+
605+ /* Update the base in the CRTC */
606+ armada_drm_crtc_update_regs(dcrtc, regs);
607+
608+ /* Drop our previously held reference */
609+ armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms));
610+
611+ return 0;
612+}
613+
614+static void armada_drm_crtc_load_lut(struct drm_crtc *crtc)
615+{
616+}
617+
618+/* The mode_config.mutex will be held for this call */
619+static void armada_drm_crtc_disable(struct drm_crtc *crtc)
620+{
621+ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
622+
623+ armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
624+ armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true);
625+
626+ /* Power down most RAMs and FIFOs */
627+ writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
628+ CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 |
629+ CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1);
630+}
631+
632+static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
633+ .dpms = armada_drm_crtc_dpms,
634+ .prepare = armada_drm_crtc_prepare,
635+ .commit = armada_drm_crtc_commit,
636+ .mode_fixup = armada_drm_crtc_mode_fixup,
637+ .mode_set = armada_drm_crtc_mode_set,
638+ .mode_set_base = armada_drm_crtc_mode_set_base,
639+ .load_lut = armada_drm_crtc_load_lut,
640+ .disable = armada_drm_crtc_disable,
641+};
642+
643+static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
644+{
645+ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
646+ struct armada_private *priv = crtc->dev->dev_private;
647+
648+ priv->dcrtc[dcrtc->num] = NULL;
649+ drm_crtc_cleanup(&dcrtc->crtc);
650+
651+ if (!IS_ERR(dcrtc->clk))
652+ clk_disable_unprepare(dcrtc->clk);
653+
654+ kfree(dcrtc);
655+}
656+
657+/*
658+ * The mode_config lock is held here, to prevent races between this
659+ * and a mode_set.
660+ */
661+static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
662+ struct drm_framebuffer *fb, struct drm_pending_vblank_event *event)
663+{
664+ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
665+ struct armada_frame_work *work;
666+ struct drm_device *dev = crtc->dev;
667+ unsigned long flags;
668+ unsigned i;
669+ int ret;
670+
671+ /* We don't support changing the pixel format */
672+ if (fb->pixel_format != crtc->fb->pixel_format)
673+ return -EINVAL;
674+
675+ work = kmalloc(sizeof(*work), GFP_KERNEL);
676+ if (!work)
677+ return -ENOMEM;
678+
679+ work->event = event;
680+ work->old_fb = dcrtc->crtc.fb;
681+
682+ i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs,
683+ dcrtc->interlaced);
684+ armada_reg_queue_end(work->regs, i);
685+
686+ /*
687+ * Hold the old framebuffer for the work - DRM appears to drop our
688+ * reference to the old framebuffer in drm_mode_page_flip_ioctl().
689+ */
690+ drm_framebuffer_reference(work->old_fb);
691+
692+ ret = armada_drm_crtc_queue_frame_work(dcrtc, work);
693+ if (ret) {
694+ /*
695+ * Undo our reference above; DRM does not drop the reference
696+ * to this object on error, so that's okay.
697+ */
698+ drm_framebuffer_unreference(work->old_fb);
699+ kfree(work);
700+ return ret;
701+ }
702+
703+ /*
704+ * Don't take a reference on the new framebuffer;
705+ * drm_mode_page_flip_ioctl() has already grabbed a reference and
706+ * will _not_ drop that reference on successful return from this
707+ * function. Simply mark this new framebuffer as the current one.
708+ */
709+ dcrtc->crtc.fb = fb;
710+
711+ /*
712+ * Finally, if the display is blanked, we won't receive an
713+ * interrupt, so complete it now.
714+ */
715+ if (dpms_blanked(dcrtc->dpms)) {
716+ spin_lock_irqsave(&dev->event_lock, flags);
717+ if (dcrtc->frame_work)
718+ armada_drm_crtc_complete_frame_work(dcrtc);
719+ spin_unlock_irqrestore(&dev->event_lock, flags);
720+ }
721+
722+ return 0;
723+}
724+
725+static int
726+armada_drm_crtc_set_property(struct drm_crtc *crtc,
727+ struct drm_property *property, uint64_t val)
728+{
729+ struct armada_private *priv = crtc->dev->dev_private;
730+ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
731+ bool update_csc = false;
732+
733+ if (property == priv->csc_yuv_prop) {
734+ dcrtc->csc_yuv_mode = val;
735+ update_csc = true;
736+ } else if (property == priv->csc_rgb_prop) {
737+ dcrtc->csc_rgb_mode = val;
738+ update_csc = true;
739+ }
740+
741+ if (update_csc) {
742+ uint32_t val;
743+
744+ val = dcrtc->spu_iopad_ctrl |
745+ armada_drm_crtc_calculate_csc(dcrtc);
746+ writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL);
747+ }
748+
749+ return 0;
750+}
751+
752+static struct drm_crtc_funcs armada_crtc_funcs = {
753+ .destroy = armada_drm_crtc_destroy,
754+ .set_config = drm_crtc_helper_set_config,
755+ .page_flip = armada_drm_crtc_page_flip,
756+ .set_property = armada_drm_crtc_set_property,
757+};
758+
759+static struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = {
760+ { CSC_AUTO, "Auto" },
761+ { CSC_YUV_CCIR601, "CCIR601" },
762+ { CSC_YUV_CCIR709, "CCIR709" },
763+};
764+
765+static struct drm_prop_enum_list armada_drm_csc_rgb_enum_list[] = {
766+ { CSC_AUTO, "Auto" },
767+ { CSC_RGB_COMPUTER, "Computer system" },
768+ { CSC_RGB_STUDIO, "Studio" },
769+};
770+
771+static int armada_drm_crtc_create_properties(struct drm_device *dev)
772+{
773+ struct armada_private *priv = dev->dev_private;
774+
775+ if (priv->csc_yuv_prop)
776+ return 0;
777+
778+ priv->csc_yuv_prop = drm_property_create_enum(dev, 0,
779+ "CSC_YUV", armada_drm_csc_yuv_enum_list,
780+ ARRAY_SIZE(armada_drm_csc_yuv_enum_list));
781+ priv->csc_rgb_prop = drm_property_create_enum(dev, 0,
782+ "CSC_RGB", armada_drm_csc_rgb_enum_list,
783+ ARRAY_SIZE(armada_drm_csc_rgb_enum_list));
784+
785+ if (!priv->csc_yuv_prop || !priv->csc_rgb_prop)
786+ return -ENOMEM;
787+
788+ return 0;
789+}
790+
791+int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
792+ struct resource *res)
793+{
794+ struct armada_private *priv = dev->dev_private;
795+ struct armada_crtc *dcrtc;
796+ void __iomem *base;
797+ int ret;
798+
799+ ret = armada_drm_crtc_create_properties(dev);
800+ if (ret)
801+ return ret;
802+
803+ base = devm_request_and_ioremap(dev->dev, res);
804+ if (!base) {
805+ DRM_ERROR("failed to ioremap register\n");
806+ return -ENOMEM;
807+ }
808+
809+ dcrtc = kzalloc(sizeof(*dcrtc), GFP_KERNEL);
810+ if (!dcrtc) {
811+ DRM_ERROR("failed to allocate Armada crtc\n");
812+ return -ENOMEM;
813+ }
814+
815+ dcrtc->base = base;
816+ dcrtc->num = num;
817+ dcrtc->clk = ERR_PTR(-EINVAL);
818+ dcrtc->csc_yuv_mode = CSC_AUTO;
819+ dcrtc->csc_rgb_mode = CSC_AUTO;
820+ dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0;
821+ dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;
822+ spin_lock_init(&dcrtc->irq_lock);
823+ dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR;
824+ INIT_LIST_HEAD(&dcrtc->vbl_list);
825+ init_waitqueue_head(&dcrtc->frame_wait);
826+
827+ /* Initialize some registers which we don't otherwise set */
828+ writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV);
829+ writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_BLANKCOLOR);
830+ writel_relaxed(dcrtc->spu_iopad_ctrl,
831+ dcrtc->base + LCD_SPU_IOPAD_CONTROL);
832+ writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_SRAM_PARA0);
833+ writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
834+ CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 |
835+ CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1);
836+ writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1);
837+ writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN);
838+
839+ if (priv->variant->crtc_init) {
840+ ret = priv->variant->crtc_init(dcrtc);
841+ if (ret) {
842+ kfree(dcrtc);
843+ return ret;
844+ }
845+ }
846+
847+ /* Ensure AXI pipeline is enabled */
848+ armada_updatel(CFG_ARBFAST_ENA, 0, dcrtc->base + LCD_SPU_DMA_CTRL0);
849+
850+ priv->dcrtc[dcrtc->num] = dcrtc;
851+
852+ drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs);
853+ drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
854+
855+ drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
856+ dcrtc->csc_yuv_mode);
857+ drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop,
858+ dcrtc->csc_rgb_mode);
859+
860+ return armada_overlay_plane_create(dev, 1 << dcrtc->num);
861+}
drivers/gpu/drm/armada/armada_crtc.h+74−0
@@ -0,0 +1,74 @@
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+ uint8_t csc_yuv_mode;
48+ uint8_t csc_rgb_mode;
49+
50+ struct drm_plane *plane;
51+
52+ int dpms;
53+ uint32_t cfg_dumb_ctrl;
54+ uint32_t dumb_ctrl;
55+ uint32_t spu_iopad_ctrl;
56+
57+ wait_queue_head_t frame_wait;
58+ struct armada_frame_work *frame_work;
59+
60+ spinlock_t irq_lock;
61+ uint32_t irq_ena;
62+ struct list_head vbl_list;
63+};
64+#define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc)
65+
66+int armada_drm_crtc_create(struct drm_device *, unsigned, struct resource *);
67+void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int);
68+void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int);
69+void armada_drm_crtc_irq(struct armada_crtc *, u32);
70+void armada_drm_crtc_disable_irq(struct armada_crtc *, u32);
71+void armada_drm_crtc_enable_irq(struct armada_crtc *, u32);
72+void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
73+
74+#endif
drivers/gpu/drm/armada/armada_debugfs.c+183−0
@@ -0,0 +1,183 @@
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+}
drivers/gpu/drm/armada/armada_drm.h+112−0
@@ -0,0 +1,112 @@
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+ int (*init)(struct armada_private *, struct device *);
64+ int (*crtc_init)(struct armada_crtc *);
65+ int (*crtc_compute_clock)(struct armada_crtc *,
66+ const struct drm_display_mode *,
67+ uint32_t *);
68+};
69+
70+/* Variant ops */
71+extern const struct armada_variant armada510_ops;
72+
73+struct armada_private {
74+ const struct armada_variant *variant;
75+ struct work_struct fb_unref_work;
76+ DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8);
77+ struct drm_fb_helper *fbdev;
78+ struct armada_crtc *dcrtc[2];
79+ struct drm_mm linear;
80+ struct clk *extclk[2];
81+ struct drm_property *csc_yuv_prop;
82+ struct drm_property *csc_rgb_prop;
83+ struct drm_property *colorkey_prop;
84+ struct drm_property *colorkey_min_prop;
85+ struct drm_property *colorkey_max_prop;
86+ struct drm_property *colorkey_val_prop;
87+ struct drm_property *colorkey_alpha_prop;
88+ struct drm_property *colorkey_mode_prop;
89+ struct drm_property *brightness_prop;
90+ struct drm_property *contrast_prop;
91+ struct drm_property *saturation_prop;
92+#ifdef CONFIG_DEBUG_FS
93+ struct dentry *de;
94+#endif
95+};
96+
97+void __armada_drm_queue_unref_work(struct drm_device *,
98+ struct drm_framebuffer *);
99+void armada_drm_queue_unref_work(struct drm_device *,
100+ struct drm_framebuffer *);
101+
102+extern const struct drm_mode_config_funcs armada_drm_mode_config_funcs;
103+
104+int armada_fbdev_init(struct drm_device *);
105+void armada_fbdev_fini(struct drm_device *);
106+
107+int armada_overlay_plane_create(struct drm_device *, unsigned long);
108+
109+int armada_drm_debugfs_init(struct drm_minor *);
110+void armada_drm_debugfs_cleanup(struct drm_minor *);
111+
112+#endif
drivers/gpu/drm/armada/armada_drv.c+380−0
@@ -0,0 +1,380 @@
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+static void armada_drm_unref_work(struct work_struct *work)
20+{
21+ struct armada_private *priv =
22+ container_of(work, struct armada_private, fb_unref_work);
23+ struct drm_framebuffer *fb;
24+
25+ while (kfifo_get(&priv->fb_unref, &fb))
26+ drm_framebuffer_unreference(fb);
27+}
28+
29+/* Must be called with dev->event_lock held */
30+void __armada_drm_queue_unref_work(struct drm_device *dev,
31+ struct drm_framebuffer *fb)
32+{
33+ struct armada_private *priv = dev->dev_private;
34+
35+ /*
36+ * Yes, we really must jump through these hoops just to store a
37+ * _pointer_ to something into the kfifo. This is utterly insane
38+ * and idiotic, because it kfifo requires the _data_ pointed to by
39+ * the pointer const, not the pointer itself. Not only that, but
40+ * you have to pass a pointer _to_ the pointer you want stored.
41+ */
42+ const struct drm_framebuffer *silly_api_alert = fb;
43+ WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert));
44+ schedule_work(&priv->fb_unref_work);
45+}
46+
47+void armada_drm_queue_unref_work(struct drm_device *dev,
48+ struct drm_framebuffer *fb)
49+{
50+ unsigned long flags;
51+
52+ spin_lock_irqsave(&dev->event_lock, flags);
53+ __armada_drm_queue_unref_work(dev, fb);
54+ spin_unlock_irqrestore(&dev->event_lock, flags);
55+}
56+
57+static int armada_drm_load(struct drm_device *dev, unsigned long flags)
58+{
59+ const struct platform_device_id *id;
60+ struct armada_private *priv;
61+ struct resource *res[ARRAY_SIZE(priv->dcrtc)];
62+ struct resource *mem = NULL;
63+ int ret, n, i;
64+
65+ memset(res, 0, sizeof(res));
66+
67+ for (n = i = 0; ; n++) {
68+ struct resource *r = platform_get_resource(dev->platformdev,
69+ IORESOURCE_MEM, n);
70+ if (!r)
71+ break;
72+
73+ /* Resources above 64K are graphics memory */
74+ if (resource_size(r) > SZ_64K)
75+ mem = r;
76+ else if (i < ARRAY_SIZE(priv->dcrtc))
77+ res[i++] = r;
78+ else
79+ return -EINVAL;
80+ }
81+
82+ if (!res[0] || !mem)
83+ return -ENXIO;
84+
85+ if (!devm_request_mem_region(dev->dev, mem->start,
86+ resource_size(mem), "armada-drm"))
87+ return -EBUSY;
88+
89+ priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
90+ if (!priv) {
91+ DRM_ERROR("failed to allocate private\n");
92+ return -ENOMEM;
93+ }
94+
95+ dev->dev_private = priv;
96+
97+ /* Get the implementation specific driver data. */
98+ id = platform_get_device_id(dev->platformdev);
99+ if (!id)
100+ return -ENXIO;
101+
102+ priv->variant = (struct armada_variant *)id->driver_data;
103+
104+ ret = priv->variant->init(priv, dev->dev);
105+ if (ret)
106+ return ret;
107+
108+ INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work);
109+ INIT_KFIFO(priv->fb_unref);
110+
111+ /* Mode setting support */
112+ drm_mode_config_init(dev);
113+ dev->mode_config.min_width = 320;
114+ dev->mode_config.min_height = 200;
115+
116+ /*
117+ * With vscale enabled, the maximum width is 1920 due to the
118+ * 1920 by 3 lines RAM
119+ */
120+ dev->mode_config.max_width = 1920;
121+ dev->mode_config.max_height = 2048;
122+
123+ dev->mode_config.preferred_depth = 24;
124+ dev->mode_config.funcs = &armada_drm_mode_config_funcs;
125+ drm_mm_init(&priv->linear, mem->start, resource_size(mem));
126+
127+ /* Create all LCD controllers */
128+ for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) {
129+ if (!res[n])
130+ break;
131+
132+ ret = armada_drm_crtc_create(dev, n, res[n]);
133+ if (ret)
134+ goto err_kms;
135+ }
136+
137+ ret = drm_vblank_init(dev, n);
138+ if (ret)
139+ goto err_kms;
140+
141+ ret = drm_irq_install(dev);
142+ if (ret)
143+ goto err_kms;
144+
145+ dev->vblank_disable_allowed = 1;
146+
147+ ret = armada_fbdev_init(dev);
148+ if (ret)
149+ goto err_irq;
150+
151+ drm_kms_helper_poll_init(dev);
152+
153+ return 0;
154+
155+ err_irq:
156+ drm_irq_uninstall(dev);
157+ err_kms:
158+ drm_mode_config_cleanup(dev);
159+ drm_mm_takedown(&priv->linear);
160+ flush_work(&priv->fb_unref_work);
161+
162+ return ret;
163+}
164+
165+static int armada_drm_unload(struct drm_device *dev)
166+{
167+ struct armada_private *priv = dev->dev_private;
168+
169+ drm_kms_helper_poll_fini(dev);
170+ armada_fbdev_fini(dev);
171+ drm_irq_uninstall(dev);
172+ drm_mode_config_cleanup(dev);
173+ drm_mm_takedown(&priv->linear);
174+ flush_work(&priv->fb_unref_work);
175+ dev->dev_private = NULL;
176+
177+ return 0;
178+}
179+
180+void armada_drm_vbl_event_add(struct armada_crtc *dcrtc,
181+ struct armada_vbl_event *evt)
182+{
183+ unsigned long flags;
184+
185+ spin_lock_irqsave(&dcrtc->irq_lock, flags);
186+ if (list_empty(&evt->node)) {
187+ list_add_tail(&evt->node, &dcrtc->vbl_list);
188+
189+ drm_vblank_get(dcrtc->crtc.dev, dcrtc->num);
190+ }
191+ spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
192+}
193+
194+void armada_drm_vbl_event_remove(struct armada_crtc *dcrtc,
195+ struct armada_vbl_event *evt)
196+{
197+ if (!list_empty(&evt->node)) {
198+ list_del_init(&evt->node);
199+ drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
200+ }
201+}
202+
203+void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *dcrtc,
204+ struct armada_vbl_event *evt)
205+{
206+ unsigned long flags;
207+
208+ spin_lock_irqsave(&dcrtc->irq_lock, flags);
209+ armada_drm_vbl_event_remove(dcrtc, evt);
210+ spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
211+}
212+
213+/* These are called under the vbl_lock. */
214+static int armada_drm_enable_vblank(struct drm_device *dev, int crtc)
215+{
216+ struct armada_private *priv = dev->dev_private;
217+ armada_drm_crtc_enable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA);
218+ return 0;
219+}
220+
221+static void armada_drm_disable_vblank(struct drm_device *dev, int crtc)
222+{
223+ struct armada_private *priv = dev->dev_private;
224+ armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA);
225+}
226+
227+static irqreturn_t armada_drm_irq_handler(int irq, void *arg)
228+{
229+ struct drm_device *dev = arg;
230+ struct armada_private *priv = dev->dev_private;
231+ struct armada_crtc *dcrtc = priv->dcrtc[0];
232+ uint32_t v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR);
233+ irqreturn_t handled = IRQ_NONE;
234+
235+ /*
236+ * This is rediculous - rather than writing bits to clear, we
237+ * have to set the actual status register value. This is racy.
238+ */
239+ writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
240+
241+ /* Mask out those interrupts we haven't enabled */
242+ v = stat & dcrtc->irq_ena;
243+
244+ if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) {
245+ armada_drm_crtc_irq(dcrtc, stat);
246+ handled = IRQ_HANDLED;
247+ }
248+
249+ return handled;
250+}
251+
252+static int armada_drm_irq_postinstall(struct drm_device *dev)
253+{
254+ struct armada_private *priv = dev->dev_private;
255+ struct armada_crtc *dcrtc = priv->dcrtc[0];
256+
257+ spin_lock_irq(&dev->vbl_lock);
258+ writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
259+ writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
260+ spin_unlock_irq(&dev->vbl_lock);
261+
262+ return 0;
263+}
264+
265+static void armada_drm_irq_uninstall(struct drm_device *dev)
266+{
267+ struct armada_private *priv = dev->dev_private;
268+ struct armada_crtc *dcrtc = priv->dcrtc[0];
269+
270+ writel(0, dcrtc->base + LCD_SPU_IRQ_ENA);
271+}
272+
273+static struct drm_ioctl_desc armada_ioctls[] = {
274+ DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,
275+ DRM_UNLOCKED),
276+ DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl,
277+ DRM_UNLOCKED),
278+ DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl,
279+ DRM_UNLOCKED),
280+};
281+
282+static const struct file_operations armada_drm_fops = {
283+ .owner = THIS_MODULE,
284+ .llseek = no_llseek,
285+ .read = drm_read,
286+ .poll = drm_poll,
287+ .unlocked_ioctl = drm_ioctl,
288+ .mmap = drm_gem_mmap,
289+ .open = drm_open,
290+ .release = drm_release,
291+};
292+
293+static struct drm_driver armada_drm_driver = {
294+ .load = armada_drm_load,
295+ .open = NULL,
296+ .preclose = NULL,
297+ .postclose = NULL,
298+ .lastclose = NULL,
299+ .unload = armada_drm_unload,
300+ .get_vblank_counter = drm_vblank_count,
301+ .enable_vblank = armada_drm_enable_vblank,
302+ .disable_vblank = armada_drm_disable_vblank,
303+ .irq_handler = armada_drm_irq_handler,
304+ .irq_postinstall = armada_drm_irq_postinstall,
305+ .irq_uninstall = armada_drm_irq_uninstall,
306+#ifdef CONFIG_DEBUG_FS
307+ .debugfs_init = armada_drm_debugfs_init,
308+ .debugfs_cleanup = armada_drm_debugfs_cleanup,
309+#endif
310+ .gem_init_object = NULL,
311+ .gem_free_object = armada_gem_free_object,
312+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
313+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
314+ .gem_prime_export = armada_gem_prime_export,
315+ .gem_prime_import = armada_gem_prime_import,
316+ .dumb_create = armada_gem_dumb_create,
317+ .dumb_map_offset = armada_gem_dumb_map_offset,
318+ .dumb_destroy = armada_gem_dumb_destroy,
319+ .gem_vm_ops = &armada_gem_vm_ops,
320+ .major = 1,
321+ .minor = 0,
322+ .name = "armada-drm",
323+ .desc = "Armada SoC DRM",
324+ .date = "20120730",
325+ .driver_features = DRIVER_GEM | DRIVER_MODESET |
326+ DRIVER_HAVE_IRQ | DRIVER_PRIME,
327+ .ioctls = armada_ioctls,
328+ .fops = &armada_drm_fops,
329+};
330+
331+static int armada_drm_probe(struct platform_device *pdev)
332+{
333+ return drm_platform_init(&armada_drm_driver, pdev);
334+}
335+
336+static int armada_drm_remove(struct platform_device *pdev)
337+{
338+ drm_platform_exit(&armada_drm_driver, pdev);
339+ return 0;
340+}
341+
342+static const struct platform_device_id armada_drm_platform_ids[] = {
343+ {
344+ .name = "armada-drm",
345+ .driver_data = (unsigned long)&armada510_ops,
346+ }, {
347+ .name = "armada-510-drm",
348+ .driver_data = (unsigned long)&armada510_ops,
349+ },
350+ { },
351+};
352+MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids);
353+
354+static struct platform_driver armada_drm_platform_driver = {
355+ .probe = armada_drm_probe,
356+ .remove = armada_drm_remove,
357+ .driver = {
358+ .name = "armada-drm",
359+ .owner = THIS_MODULE,
360+ },
361+ .id_table = armada_drm_platform_ids,
362+};
363+
364+static int __init armada_drm_init(void)
365+{
366+ armada_drm_driver.num_ioctls = DRM_ARRAY_SIZE(armada_ioctls);
367+ return platform_driver_register(&armada_drm_platform_driver);
368+}
369+module_init(armada_drm_init);
370+
371+static void __exit armada_drm_exit(void)
372+{
373+ platform_driver_unregister(&armada_drm_platform_driver);
374+}
375+module_exit(armada_drm_exit);
376+
377+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
378+MODULE_DESCRIPTION("Armada DRM Driver");
379+MODULE_LICENSE("GPL");
380+MODULE_ALIAS("platform:armada-drm");
drivers/gpu/drm/armada/armada_fb.c+170−0
@@ -0,0 +1,170 @@
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+};
drivers/gpu/drm/armada/armada_fb.h+24−0
@@ -0,0 +1,24 @@
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
drivers/gpu/drm/armada/armada_fbdev.c+202−0
@@ -0,0 +1,202 @@
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+}
drivers/gpu/drm/armada/armada_gem.c+611−0
@@ -0,0 +1,611 @@
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+}
drivers/gpu/drm/armada/armada_gem.h+52−0
@@ -0,0 +1,52 @@
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
drivers/gpu/drm/armada/armada_hw.h+316−0
@@ -0,0 +1,316 @@
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_RAMR = 0xc << 8,
172+ SRAM_HWC32_RAMG = 0xd << 8,
173+ SRAM_HWC32_RAMB = 0xe << 8,
174+ SRAM_HWC32_TRAN = 0xf << 8,
175+ SRAM_HWC = 0xf << 8,
176+};
177+
178+/* For LCD_SPU_SRAM_PARA1 */
179+enum {
180+ CFG_CSB_256x32 = 1 << 15, /* cursor */
181+ CFG_CSB_256x24 = 1 << 14, /* palette */
182+ CFG_CSB_256x8 = 1 << 13, /* gamma */
183+ CFG_PDWN1920x32 = 1 << 8, /* Armada 510: power down vscale ram */
184+ CFG_PDWN256x32 = 1 << 7, /* power down cursor */
185+ CFG_PDWN256x24 = 1 << 6, /* power down palette */
186+ CFG_PDWN256x8 = 1 << 5, /* power down gamma */
187+ CFG_PDWNHWC = 1 << 4, /* Armada 510: power down all hwc ram */
188+ CFG_PDWN32x32 = 1 << 3, /* power down slave->smart ram */
189+ CFG_PDWN16x66 = 1 << 2, /* power down UV fifo */
190+ CFG_PDWN32x66 = 1 << 1, /* power down Y fifo */
191+ CFG_PDWN64x66 = 1 << 0, /* power down graphic fifo */
192+};
193+
194+/* For LCD_CFG_SCLK_DIV */
195+enum {
196+ /* Armada 510 */
197+ SCLK_510_AXI = 0x0 << 30,
198+ SCLK_510_EXTCLK0 = 0x1 << 30,
199+ SCLK_510_PLL = 0x2 << 30,
200+ SCLK_510_EXTCLK1 = 0x3 << 30,
201+ SCLK_510_DIV_CHANGE = 1 << 29,
202+ SCLK_510_FRAC_DIV_MASK = 0xfff << 16,
203+ SCLK_510_INT_DIV_MASK = 0xffff << 0,
204+
205+ /* Armada 16x */
206+ SCLK_16X_AHB = 0x0 << 28,
207+ SCLK_16X_PCLK = 0x1 << 28,
208+ SCLK_16X_AXI = 0x4 << 28,
209+ SCLK_16X_PLL = 0x8 << 28,
210+ SCLK_16X_FRAC_DIV_MASK = 0xfff << 16,
211+ SCLK_16X_INT_DIV_MASK = 0xffff << 0,
212+};
213+
214+/* For LCD_SPU_DUMB_CTRL */
215+enum {
216+ DUMB16_RGB565_0 = 0x0 << 28,
217+ DUMB16_RGB565_1 = 0x1 << 28,
218+ DUMB18_RGB666_0 = 0x2 << 28,
219+ DUMB18_RGB666_1 = 0x3 << 28,
220+ DUMB12_RGB444_0 = 0x4 << 28,
221+ DUMB12_RGB444_1 = 0x5 << 28,
222+ DUMB24_RGB888_0 = 0x6 << 28,
223+ DUMB_BLANK = 0x7 << 28,
224+ DUMB_MASK = 0xf << 28,
225+ CFG_BIAS_OUT = 1 << 8,
226+ CFG_REV_RGB = 1 << 7,
227+ CFG_INV_CBLANK = 1 << 6,
228+ CFG_INV_CSYNC = 1 << 5, /* Normally active high */
229+ CFG_INV_HENA = 1 << 4,
230+ CFG_INV_VSYNC = 1 << 3, /* Normally active high */
231+ CFG_INV_HSYNC = 1 << 2, /* Normally active high */
232+ CFG_INV_PCLK = 1 << 1,
233+ CFG_DUMB_ENA = 1 << 0,
234+};
235+
236+/* For LCD_SPU_IOPAD_CONTROL */
237+enum {
238+ CFG_VSCALE_LN_EN = 3 << 18,
239+ CFG_GRA_VM_ENA = 1 << 15,
240+ CFG_DMA_VM_ENA = 1 << 13,
241+ CFG_CMD_VM_ENA = 1 << 11,
242+ CFG_CSC_MASK = 3 << 8,
243+ CFG_CSC_YUV_CCIR709 = 1 << 9,
244+ CFG_CSC_YUV_CCIR601 = 0 << 9,
245+ CFG_CSC_RGB_STUDIO = 1 << 8,
246+ CFG_CSC_RGB_COMPUTER = 0 << 8,
247+ CFG_IOPAD_MASK = 0xf << 0,
248+ CFG_IOPAD_DUMB24 = 0x0 << 0,
249+ CFG_IOPAD_DUMB18SPI = 0x1 << 0,
250+ CFG_IOPAD_DUMB18GPIO = 0x2 << 0,
251+ CFG_IOPAD_DUMB16SPI = 0x3 << 0,
252+ CFG_IOPAD_DUMB16GPIO = 0x4 << 0,
253+ CFG_IOPAD_DUMB12GPIO = 0x5 << 0,
254+ CFG_IOPAD_SMART18 = 0x6 << 0,
255+ CFG_IOPAD_SMART16 = 0x7 << 0,
256+ CFG_IOPAD_SMART8 = 0x8 << 0,
257+};
258+
259+#define IOPAD_DUMB24 0x0
260+
261+/* For LCD_SPU_IRQ_ENA */
262+enum {
263+ DMA_FRAME_IRQ0_ENA = 1 << 31,
264+ DMA_FRAME_IRQ1_ENA = 1 << 30,
265+ DMA_FRAME_IRQ_ENA = DMA_FRAME_IRQ0_ENA | DMA_FRAME_IRQ1_ENA,
266+ DMA_FF_UNDERFLOW_ENA = 1 << 29,
267+ GRA_FRAME_IRQ0_ENA = 1 << 27,
268+ GRA_FRAME_IRQ1_ENA = 1 << 26,
269+ GRA_FRAME_IRQ_ENA = GRA_FRAME_IRQ0_ENA | GRA_FRAME_IRQ1_ENA,
270+ GRA_FF_UNDERFLOW_ENA = 1 << 25,
271+ VSYNC_IRQ_ENA = 1 << 23,
272+ DUMB_FRAMEDONE_ENA = 1 << 22,
273+ TWC_FRAMEDONE_ENA = 1 << 21,
274+ HWC_FRAMEDONE_ENA = 1 << 20,
275+ SLV_IRQ_ENA = 1 << 19,
276+ SPI_IRQ_ENA = 1 << 18,
277+ PWRDN_IRQ_ENA = 1 << 17,
278+ ERR_IRQ_ENA = 1 << 16,
279+ CLEAN_SPU_IRQ_ISR = 0xffff,
280+};
281+
282+/* For LCD_SPU_IRQ_ISR */
283+enum {
284+ DMA_FRAME_IRQ0 = 1 << 31,
285+ DMA_FRAME_IRQ1 = 1 << 30,
286+ DMA_FRAME_IRQ = DMA_FRAME_IRQ0 | DMA_FRAME_IRQ1,
287+ DMA_FF_UNDERFLOW = 1 << 29,
288+ GRA_FRAME_IRQ0 = 1 << 27,
289+ GRA_FRAME_IRQ1 = 1 << 26,
290+ GRA_FRAME_IRQ = GRA_FRAME_IRQ0 | GRA_FRAME_IRQ1,
291+ GRA_FF_UNDERFLOW = 1 << 25,
292+ VSYNC_IRQ = 1 << 23,
293+ DUMB_FRAMEDONE = 1 << 22,
294+ TWC_FRAMEDONE = 1 << 21,
295+ HWC_FRAMEDONE = 1 << 20,
296+ SLV_IRQ = 1 << 19,
297+ SPI_IRQ = 1 << 18,
298+ PWRDN_IRQ = 1 << 17,
299+ ERR_IRQ = 1 << 16,
300+ DMA_FRAME_IRQ0_LEVEL = 1 << 15,
301+ DMA_FRAME_IRQ1_LEVEL = 1 << 14,
302+ DMA_FRAME_CNT_ISR = 3 << 12,
303+ GRA_FRAME_IRQ0_LEVEL = 1 << 11,
304+ GRA_FRAME_IRQ1_LEVEL = 1 << 10,
305+ GRA_FRAME_CNT_ISR = 3 << 8,
306+ VSYNC_IRQ_LEVEL = 1 << 7,
307+ DUMB_FRAMEDONE_LEVEL = 1 << 6,
308+ TWC_FRAMEDONE_LEVEL = 1 << 5,
309+ HWC_FRAMEDONE_LEVEL = 1 << 4,
310+ SLV_FF_EMPTY = 1 << 3,
311+ DMA_FF_ALLEMPTY = 1 << 2,
312+ GRA_FF_ALLEMPTY = 1 << 1,
313+ PWRDN_IRQ_LEVEL = 1 << 0,
314+};
315+
316+#endif
drivers/gpu/drm/armada/armada_ioctlP.h+18−0
@@ -0,0 +1,18 @@
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
drivers/gpu/drm/armada/armada_output.c+158−0
@@ -0,0 +1,158 @@
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+}
drivers/gpu/drm/armada/armada_output.h+39−0
@@ -0,0 +1,39 @@
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
drivers/gpu/drm/armada/armada_overlay.c+477−0
@@ -0,0 +1,477 @@
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+}
drivers/gpu/drm/armada/armada_slave.c+139−0
@@ -0,0 +1,139 @@
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+}
drivers/gpu/drm/armada/armada_slave.h+26−0
@@ -0,0 +1,26 @@
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
include/drm/drm_crtc.h+17−0
@@ -1135,4 +1135,21 @@ extern int drm_format_horz_chroma_subsampling(uint32_t format); · 1134 unmodified lines
11351135 extern int drm_format_vert_chroma_subsampling(uint32_t format);
11361136 extern const char *drm_get_format_name(uint32_t format);
11371137
1138+/* Helpers */
1139+static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev,
1140+ uint32_t id)
1141+{
1142+ struct drm_mode_object *mo;
1143+ mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CRTC);
1144+ return mo ? obj_to_crtc(mo) : NULL;
1145+}
1146+
1147+static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
1148+ uint32_t id)
1149+{
1150+ struct drm_mode_object *mo;
1151+ mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
1152+ return mo ? obj_to_encoder(mo) : NULL;
1153+}
1154+
11381155 #endif /* __DRM_CRTC_H__ */
include/uapi/drm/armada_drm.h+45−0
@@ -0,0 +1,45 @@
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

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t