aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2019-07-04 00:08:07 -0400
committerDave Airlie <airlied@redhat.com>2019-07-04 00:09:50 -0400
commitf07b56e7d0b21b49d809b301837c6ba39c27309a (patch)
treee3a5dbe293772c5e79415317f069a5e668ede8c3
parenta22719cce54bc18001a7c8be9c713ba629f5801c (diff)
parent837567c1e9d587c0b438263c9cfd32de46640e16 (diff)
Merge tag 'for-airlie-armada' of git://git.armlinux.org.uk/~rmk/linux-arm into drm-next
Armada DRM updates: - Fix interlace support. - use __drm_atomic_helper_plane_reset in overlay reset. - since the overlay and video planes use essentially the same format registers, precompute their values while validating. - fix a long-standing deficiency with overlay planes and interlace modes - calculate plane starting address at atomic_check stage rather than when we're programming the registers. - add gamma support. - ensure mode adjustments made by other components are properly handled in the driver and applied to the CRTC-programmed mode. - add and use register definitions for the "REG4F" register. - use drm_atomic_helper_shutdown() when tearing down to ensure that the hardware is properly shutdown. - add CRTC-level mode validation to ensure that we don't allow a mode that the CRTC-level hardware can not support. - improve the clocking selection for Armada 510 support. - move CRTC debugfs files into the crtc-specific directory, using the DRM helper to create these files. - patch from Lubomir Rintel to replace a simple framebuffer. - use the OF graph walker rather than open-coding this. - eliminate a useless check for the availability of the remote's parent which isn't required. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Russell King <rmk@armlinux.org.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20190702091313.GA23442@rmk-PC.armlinux.org.uk
-rw-r--r--drivers/gpu/drm/armada/armada_510.c130
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c214
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.h21
-rw-r--r--drivers/gpu/drm/armada/armada_debugfs.c98
-rw-r--r--drivers/gpu/drm/armada/armada_drm.h1
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c38
-rw-r--r--drivers/gpu/drm/armada/armada_hw.h29
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c56
-rw-r--r--drivers/gpu/drm/armada/armada_plane.c124
-rw-r--r--drivers/gpu/drm/armada/armada_plane.h23
10 files changed, 522 insertions, 212 deletions
diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c
index 0e91d27921bd..6f8ad8fb19f1 100644
--- a/drivers/gpu/drm/armada/armada_510.c
+++ b/drivers/gpu/drm/armada/armada_510.c
@@ -14,18 +14,62 @@
14#include "armada_drm.h" 14#include "armada_drm.h"
15#include "armada_hw.h" 15#include "armada_hw.h"
16 16
17struct armada510_variant_data {
18 struct clk *clks[4];
19 struct clk *sel_clk;
20};
21
17static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev) 22static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
18{ 23{
24 struct armada510_variant_data *v;
19 struct clk *clk; 25 struct clk *clk;
26 int idx;
27
28 v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL);
29 if (!v)
30 return -ENOMEM;
31
32 dcrtc->variant_data = v;
33
34 if (dev->of_node) {
35 struct property *prop;
36 const char *s;
37
38 of_property_for_each_string(dev->of_node, "clock-names", prop,
39 s) {
40 if (!strcmp(s, "ext_ref_clk0"))
41 idx = 0;
42 else if (!strcmp(s, "ext_ref_clk1"))
43 idx = 1;
44 else if (!strcmp(s, "plldivider"))
45 idx = 2;
46 else if (!strcmp(s, "axibus"))
47 idx = 3;
48 else
49 continue;
50
51 clk = devm_clk_get(dev, s);
52 if (IS_ERR(clk))
53 return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
54 PTR_ERR(clk);
55 v->clks[idx] = clk;
56 }
57 } else {
58 clk = devm_clk_get(dev, "ext_ref_clk1");
59 if (IS_ERR(clk))
60 return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
61 PTR_ERR(clk);
62
63 v->clks[1] = clk;
64 }
20 65
21 clk = devm_clk_get(dev, "ext_ref_clk1"); 66 /*
22 if (IS_ERR(clk)) 67 * Lower the watermark so to eliminate jitter at higher bandwidths.
23 return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk); 68 * Disable SRAM read wait state to avoid system hang with external
24 69 * clock.
25 dcrtc->extclk[0] = clk; 70 */
26 71 armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK,
27 /* Lower the watermark so to eliminate jitter at higher bandwidths */ 72 dcrtc->base + LCD_CFG_RDREG4F);
28 armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F);
29 73
30 /* Initialise SPU register */ 74 /* Initialise SPU register */
31 writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, 75 writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
@@ -34,65 +78,77 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
34 return 0; 78 return 0;
35} 79}
36 80
81static const u32 armada510_clk_sels[] = {
82 SCLK_510_EXTCLK0,
83 SCLK_510_EXTCLK1,
84 SCLK_510_PLL,
85 SCLK_510_AXI,
86};
87
88static const struct armada_clocking_params armada510_clocking = {
89 /* HDMI requires -0.6%..+0.5% */
90 .permillage_min = 994,
91 .permillage_max = 1005,
92 .settable = BIT(0) | BIT(1),
93 .div_max = SCLK_510_INT_DIV_MASK,
94};
95
37/* 96/*
38 * Armada510 specific SCLK register selection. 97 * Armada510 specific SCLK register selection.
39 * This gets called with sclk = NULL to test whether the mode is 98 * This gets called with sclk = NULL to test whether the mode is
40 * supportable, and again with sclk != NULL to set the clocks up for 99 * supportable, and again with sclk != NULL to set the clocks up for
41 * that. The former can return an error, but the latter is expected 100 * that. The former can return an error, but the latter is expected
42 * not to. 101 * not to.
43 *
44 * We currently are pretty rudimentary here, always selecting
45 * EXT_REF_CLK_1 for LCD0 and erroring LCD1. This needs improvement!
46 */ 102 */
47static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, 103static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
48 const struct drm_display_mode *mode, uint32_t *sclk) 104 const struct drm_display_mode *mode, uint32_t *sclk)
49{ 105{
50 struct clk *clk = dcrtc->extclk[0]; 106 struct armada510_variant_data *v = dcrtc->variant_data;
51 int ret; 107 unsigned long desired_khz = mode->crtc_clock;
108 struct armada_clk_result res;
109 int ret, idx;
52 110
53 if (dcrtc->num == 1) 111 idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking,
54 return -EINVAL; 112 v->clks, ARRAY_SIZE(v->clks),
113 desired_khz);
114 if (idx < 0)
115 return idx;
55 116
56 if (IS_ERR(clk)) 117 ret = clk_prepare_enable(res.clk);
57 return PTR_ERR(clk); 118 if (ret)
58 119 return ret;
59 if (dcrtc->clk != clk) {
60 ret = clk_prepare_enable(clk);
61 if (ret)
62 return ret;
63 dcrtc->clk = clk;
64 }
65 120
66 if (sclk) { 121 if (sclk) {
67 uint32_t rate, ref, div; 122 clk_set_rate(res.clk, res.desired_clk_hz);
68 123
69 rate = mode->clock * 1000; 124 *sclk = res.div | armada510_clk_sels[idx];
70 ref = clk_round_rate(clk, rate);
71 div = DIV_ROUND_UP(ref, rate);
72 if (div < 1)
73 div = 1;
74 125
75 clk_set_rate(clk, ref); 126 /* We are now using this clock */
76 *sclk = div | SCLK_510_EXTCLK1; 127 v->sel_clk = res.clk;
128 swap(dcrtc->clk, res.clk);
77 } 129 }
78 130
131 clk_disable_unprepare(res.clk);
132
79 return 0; 133 return 0;
80} 134}
81 135
82static void armada510_crtc_disable(struct armada_crtc *dcrtc) 136static void armada510_crtc_disable(struct armada_crtc *dcrtc)
83{ 137{
84 if (!IS_ERR(dcrtc->clk)) { 138 if (dcrtc->clk) {
85 clk_disable_unprepare(dcrtc->clk); 139 clk_disable_unprepare(dcrtc->clk);
86 dcrtc->clk = ERR_PTR(-EINVAL); 140 dcrtc->clk = NULL;
87 } 141 }
88} 142}
89 143
90static void armada510_crtc_enable(struct armada_crtc *dcrtc, 144static void armada510_crtc_enable(struct armada_crtc *dcrtc,
91 const struct drm_display_mode *mode) 145 const struct drm_display_mode *mode)
92{ 146{
93 if (IS_ERR(dcrtc->clk)) { 147 struct armada510_variant_data *v = dcrtc->variant_data;
94 dcrtc->clk = dcrtc->extclk[0]; 148
95 WARN_ON(clk_prepare_enable(dcrtc->clk)); 149 if (!dcrtc->clk && v->sel_clk) {
150 if (!WARN_ON(clk_prepare_enable(v->sel_clk)))
151 dcrtc->clk = v->sel_clk;
96 } 152 }
97} 153}
98 154
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index ba4a3fab7745..2e17d7e72eeb 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -130,6 +130,70 @@ static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc)
130 } 130 }
131} 131}
132 132
133static void armada_drm_update_gamma(struct drm_crtc *crtc)
134{
135 struct drm_property_blob *blob = crtc->state->gamma_lut;
136 void __iomem *base = drm_to_armada_crtc(crtc)->base;
137 int i;
138
139 if (blob) {
140 struct drm_color_lut *lut = blob->data;
141
142 armada_updatel(CFG_CSB_256x8, CFG_CSB_256x8 | CFG_PDWN256x8,
143 base + LCD_SPU_SRAM_PARA1);
144
145 for (i = 0; i < 256; i++) {
146 writel_relaxed(drm_color_lut_extract(lut[i].red, 8),
147 base + LCD_SPU_SRAM_WRDAT);
148 writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_YR,
149 base + LCD_SPU_SRAM_CTRL);
150 readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
151 writel_relaxed(drm_color_lut_extract(lut[i].green, 8),
152 base + LCD_SPU_SRAM_WRDAT);
153 writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_UG,
154 base + LCD_SPU_SRAM_CTRL);
155 readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
156 writel_relaxed(drm_color_lut_extract(lut[i].blue, 8),
157 base + LCD_SPU_SRAM_WRDAT);
158 writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_VB,
159 base + LCD_SPU_SRAM_CTRL);
160 readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
161 }
162 armada_updatel(CFG_GAMMA_ENA, CFG_GAMMA_ENA,
163 base + LCD_SPU_DMA_CTRL0);
164 } else {
165 armada_updatel(0, CFG_GAMMA_ENA, base + LCD_SPU_DMA_CTRL0);
166 armada_updatel(CFG_PDWN256x8, CFG_CSB_256x8 | CFG_PDWN256x8,
167 base + LCD_SPU_SRAM_PARA1);
168 }
169}
170
171static enum drm_mode_status armada_drm_crtc_mode_valid(struct drm_crtc *crtc,
172 const struct drm_display_mode *mode)
173{
174 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
175
176 if (mode->vscan > 1)
177 return MODE_NO_VSCAN;
178
179 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
180 return MODE_NO_DBLESCAN;
181
182 if (mode->flags & DRM_MODE_FLAG_HSKEW)
183 return MODE_H_ILLEGAL;
184
185 /* We can't do interlaced modes if we don't have the SPU_ADV_REG */
186 if (!dcrtc->variant->has_spu_adv_reg &&
187 mode->flags & DRM_MODE_FLAG_INTERLACE)
188 return MODE_NO_INTERLACE;
189
190 if (mode->flags & (DRM_MODE_FLAG_BCAST | DRM_MODE_FLAG_PIXMUX |
191 DRM_MODE_FLAG_CLKDIV2))
192 return MODE_BAD;
193
194 return MODE_OK;
195}
196
133/* The mode_config.mutex will be held for this call */ 197/* The mode_config.mutex will be held for this call */
134static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, 198static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
135 const struct drm_display_mode *mode, struct drm_display_mode *adj) 199 const struct drm_display_mode *mode, struct drm_display_mode *adj)
@@ -137,9 +201,18 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
137 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 201 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
138 int ret; 202 int ret;
139 203
140 /* We can't do interlaced modes if we don't have the SPU_ADV_REG */ 204 /*
141 if (!dcrtc->variant->has_spu_adv_reg && 205 * Set CRTC modesetting parameters for the adjusted mode. This is
142 adj->flags & DRM_MODE_FLAG_INTERLACE) 206 * applied after the connectors, bridges, and encoders have fixed up
207 * this mode, as described above drm_atomic_helper_check_modeset().
208 */
209 drm_mode_set_crtcinfo(adj, CRTC_INTERLACE_HALVE_V);
210
211 /*
212 * Validate the adjusted mode in case an encoder/bridge has set
213 * something we don't support.
214 */
215 if (armada_drm_crtc_mode_valid(crtc, adj) != MODE_OK)
143 return false; 216 return false;
144 217
145 /* Check whether the display mode is possible */ 218 /* Check whether the display mode is possible */
@@ -278,16 +351,9 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
278 351
279 armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV); 352 armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV);
280 353
281 if (interlaced ^ dcrtc->interlaced) {
282 if (adj->flags & DRM_MODE_FLAG_INTERLACE)
283 drm_crtc_vblank_get(&dcrtc->crtc);
284 else
285 drm_crtc_vblank_put(&dcrtc->crtc);
286 dcrtc->interlaced = interlaced;
287 }
288
289 spin_lock_irqsave(&dcrtc->irq_lock, flags); 354 spin_lock_irqsave(&dcrtc->irq_lock, flags);
290 355
356 dcrtc->interlaced = interlaced;
291 /* Even interlaced/progressive frame */ 357 /* Even interlaced/progressive frame */
292 dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 | 358 dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 |
293 adj->crtc_htotal; 359 adj->crtc_htotal;
@@ -345,6 +411,20 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
345 spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 411 spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
346} 412}
347 413
414static int armada_drm_crtc_atomic_check(struct drm_crtc *crtc,
415 struct drm_crtc_state *state)
416{
417 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
418
419 if (state->gamma_lut && drm_color_lut_size(state->gamma_lut) != 256)
420 return -EINVAL;
421
422 if (state->color_mgmt_changed)
423 state->planes_changed = true;
424
425 return 0;
426}
427
348static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc, 428static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
349 struct drm_crtc_state *old_crtc_state) 429 struct drm_crtc_state *old_crtc_state)
350{ 430{
@@ -352,6 +432,9 @@ static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
352 432
353 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); 433 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
354 434
435 if (crtc->state->color_mgmt_changed)
436 armada_drm_update_gamma(crtc);
437
355 dcrtc->regs_idx = 0; 438 dcrtc->regs_idx = 0;
356 dcrtc->regs = dcrtc->atomic_regs; 439 dcrtc->regs = dcrtc->atomic_regs;
357} 440}
@@ -390,6 +473,9 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc,
390 473
391 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); 474 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
392 475
476 if (old_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
477 drm_crtc_vblank_put(crtc);
478
393 drm_crtc_vblank_off(crtc); 479 drm_crtc_vblank_off(crtc);
394 armada_drm_crtc_update(dcrtc, false); 480 armada_drm_crtc_update(dcrtc, false);
395 481
@@ -434,12 +520,17 @@ static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc,
434 armada_drm_crtc_update(dcrtc, true); 520 armada_drm_crtc_update(dcrtc, true);
435 drm_crtc_vblank_on(crtc); 521 drm_crtc_vblank_on(crtc);
436 522
523 if (crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
524 WARN_ON(drm_crtc_vblank_get(crtc));
525
437 armada_drm_crtc_queue_state_event(crtc); 526 armada_drm_crtc_queue_state_event(crtc);
438} 527}
439 528
440static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { 529static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
530 .mode_valid = armada_drm_crtc_mode_valid,
441 .mode_fixup = armada_drm_crtc_mode_fixup, 531 .mode_fixup = armada_drm_crtc_mode_fixup,
442 .mode_set_nofb = armada_drm_crtc_mode_set_nofb, 532 .mode_set_nofb = armada_drm_crtc_mode_set_nofb,
533 .atomic_check = armada_drm_crtc_atomic_check,
443 .atomic_begin = armada_drm_crtc_atomic_begin, 534 .atomic_begin = armada_drm_crtc_atomic_begin,
444 .atomic_flush = armada_drm_crtc_atomic_flush, 535 .atomic_flush = armada_drm_crtc_atomic_flush,
445 .atomic_disable = armada_drm_crtc_atomic_disable, 536 .atomic_disable = armada_drm_crtc_atomic_disable,
@@ -460,6 +551,13 @@ static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,
460 for (x = 0; x < width; x++, p++) { 551 for (x = 0; x < width; x++, p++) {
461 uint32_t val = *p; 552 uint32_t val = *p;
462 553
554 /*
555 * In "ARGB888" (HWC32) mode, writing to the SRAM
556 * requires these bits to contain:
557 * 31:24 = alpha 23:16 = blue 15:8 = green 7:0 = red
558 * So, it's actually ABGR8888. This is independent
559 * of the SWAPRB bits in DMA control register 0.
560 */
463 val = (val & 0xff00ff00) | 561 val = (val & 0xff00ff00) |
464 (val & 0x000000ff) << 16 | 562 (val & 0x000000ff) << 16 |
465 (val & 0x00ff0000) >> 16; 563 (val & 0x00ff0000) >> 16;
@@ -676,6 +774,14 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
676 kfree(dcrtc); 774 kfree(dcrtc);
677} 775}
678 776
777static int armada_drm_crtc_late_register(struct drm_crtc *crtc)
778{
779 if (IS_ENABLED(CONFIG_DEBUG_FS))
780 armada_drm_crtc_debugfs_init(drm_to_armada_crtc(crtc));
781
782 return 0;
783}
784
679/* These are called under the vbl_lock. */ 785/* These are called under the vbl_lock. */
680static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc) 786static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc)
681{ 787{
@@ -703,14 +809,93 @@ static const struct drm_crtc_funcs armada_crtc_funcs = {
703 .cursor_set = armada_drm_crtc_cursor_set, 809 .cursor_set = armada_drm_crtc_cursor_set,
704 .cursor_move = armada_drm_crtc_cursor_move, 810 .cursor_move = armada_drm_crtc_cursor_move,
705 .destroy = armada_drm_crtc_destroy, 811 .destroy = armada_drm_crtc_destroy,
812 .gamma_set = drm_atomic_helper_legacy_gamma_set,
706 .set_config = drm_atomic_helper_set_config, 813 .set_config = drm_atomic_helper_set_config,
707 .page_flip = drm_atomic_helper_page_flip, 814 .page_flip = drm_atomic_helper_page_flip,
708 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 815 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
709 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 816 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
817 .late_register = armada_drm_crtc_late_register,
710 .enable_vblank = armada_drm_crtc_enable_vblank, 818 .enable_vblank = armada_drm_crtc_enable_vblank,
711 .disable_vblank = armada_drm_crtc_disable_vblank, 819 .disable_vblank = armada_drm_crtc_disable_vblank,
712}; 820};
713 821
822int armada_crtc_select_clock(struct armada_crtc *dcrtc,
823 struct armada_clk_result *res,
824 const struct armada_clocking_params *params,
825 struct clk *clks[], size_t num_clks,
826 unsigned long desired_khz)
827{
828 unsigned long desired_hz = desired_khz * 1000;
829 unsigned long desired_clk_hz; // requested clk input
830 unsigned long real_clk_hz; // actual clk input
831 unsigned long real_hz; // actual pixel clk
832 unsigned long permillage;
833 struct clk *clk;
834 u32 div;
835 int i;
836
837 DRM_DEBUG_KMS("[CRTC:%u:%s] desired clock=%luHz\n",
838 dcrtc->crtc.base.id, dcrtc->crtc.name, desired_hz);
839
840 for (i = 0; i < num_clks; i++) {
841 clk = clks[i];
842 if (!clk)
843 continue;
844
845 if (params->settable & BIT(i)) {
846 real_clk_hz = clk_round_rate(clk, desired_hz);
847 desired_clk_hz = desired_hz;
848 } else {
849 real_clk_hz = clk_get_rate(clk);
850 desired_clk_hz = real_clk_hz;
851 }
852
853 /* If the clock can do exactly the desired rate, we're done */
854 if (real_clk_hz == desired_hz) {
855 real_hz = real_clk_hz;
856 div = 1;
857 goto found;
858 }
859
860 /* Calculate the divider - if invalid, we can't do this rate */
861 div = DIV_ROUND_CLOSEST(real_clk_hz, desired_hz);
862 if (div == 0 || div > params->div_max)
863 continue;
864
865 /* Calculate the actual rate - HDMI requires -0.6%..+0.5% */
866 real_hz = DIV_ROUND_CLOSEST(real_clk_hz, div);
867
868 DRM_DEBUG_KMS("[CRTC:%u:%s] clk=%u %luHz div=%u real=%luHz\n",
869 dcrtc->crtc.base.id, dcrtc->crtc.name,
870 i, real_clk_hz, div, real_hz);
871
872 /* Avoid repeated division */
873 if (real_hz < desired_hz) {
874 permillage = real_hz / desired_khz;
875 if (permillage < params->permillage_min)
876 continue;
877 } else {
878 permillage = DIV_ROUND_UP(real_hz, desired_khz);
879 if (permillage > params->permillage_max)
880 continue;
881 }
882 goto found;
883 }
884
885 return -ERANGE;
886
887found:
888 DRM_DEBUG_KMS("[CRTC:%u:%s] selected clk=%u %luHz div=%u real=%luHz\n",
889 dcrtc->crtc.base.id, dcrtc->crtc.name,
890 i, real_clk_hz, div, real_hz);
891
892 res->desired_clk_hz = desired_clk_hz;
893 res->clk = clk;
894 res->div = div;
895
896 return i;
897}
898
714static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, 899static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
715 struct resource *res, int irq, const struct armada_variant *variant, 900 struct resource *res, int irq, const struct armada_variant *variant,
716 struct device_node *port) 901 struct device_node *port)
@@ -737,7 +922,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
737 dcrtc->variant = variant; 922 dcrtc->variant = variant;
738 dcrtc->base = base; 923 dcrtc->base = base;
739 dcrtc->num = drm->mode_config.num_crtc; 924 dcrtc->num = drm->mode_config.num_crtc;
740 dcrtc->clk = ERR_PTR(-EINVAL);
741 dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0; 925 dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0;
742 dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24; 926 dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;
743 spin_lock_init(&dcrtc->irq_lock); 927 spin_lock_init(&dcrtc->irq_lock);
@@ -794,6 +978,12 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
794 978
795 drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); 979 drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
796 980
981 ret = drm_mode_crtc_set_gamma_size(&dcrtc->crtc, 256);
982 if (ret)
983 return ret;
984
985 drm_crtc_enable_color_mgmt(&dcrtc->crtc, 0, false, 256);
986
797 return armada_overlay_plane_create(drm, 1 << dcrtc->num); 987 return armada_overlay_plane_create(drm, 1 << dcrtc->num);
798 988
799err_crtc_init: 989err_crtc_init:
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
index 08761ff01739..fb4aa48da60c 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -39,10 +39,10 @@ struct armada_variant;
39struct armada_crtc { 39struct armada_crtc {
40 struct drm_crtc crtc; 40 struct drm_crtc crtc;
41 const struct armada_variant *variant; 41 const struct armada_variant *variant;
42 void *variant_data;
42 unsigned num; 43 unsigned num;
43 void __iomem *base; 44 void __iomem *base;
44 struct clk *clk; 45 struct clk *clk;
45 struct clk *extclk[2];
46 struct { 46 struct {
47 uint32_t spu_v_h_total; 47 uint32_t spu_v_h_total;
48 uint32_t spu_v_porch; 48 uint32_t spu_v_porch;
@@ -75,6 +75,25 @@ struct armada_crtc {
75 75
76void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); 76void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
77 77
78struct armada_clocking_params {
79 unsigned long permillage_min;
80 unsigned long permillage_max;
81 u32 settable;
82 u32 div_max;
83};
84
85struct armada_clk_result {
86 unsigned long desired_clk_hz;
87 struct clk *clk;
88 u32 div;
89};
90
91int armada_crtc_select_clock(struct armada_crtc *dcrtc,
92 struct armada_clk_result *res,
93 const struct armada_clocking_params *params,
94 struct clk *clks[], size_t num_clks,
95 unsigned long desired_khz);
96
78extern struct platform_driver armada_lcd_platform_driver; 97extern struct platform_driver armada_lcd_platform_driver;
79 98
80#endif 99#endif
diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c
index 6758c3a83de2..4dcce002ea2a 100644
--- a/drivers/gpu/drm/armada/armada_debugfs.c
+++ b/drivers/gpu/drm/armada/armada_debugfs.c
@@ -28,50 +28,33 @@ static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data)
28 return 0; 28 return 0;
29} 29}
30 30
31static int armada_debugfs_reg_show(struct seq_file *m, void *data) 31static int armada_debugfs_crtc_reg_show(struct seq_file *m, void *data)
32{ 32{
33 struct drm_device *dev = m->private; 33 struct armada_crtc *dcrtc = m->private;
34 struct armada_private *priv = dev->dev_private; 34 int i;
35 int n, i; 35
36 36 for (i = 0x84; i <= 0x1c4; i += 4) {
37 if (priv) { 37 u32 v = readl_relaxed(dcrtc->base + i);
38 for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { 38 seq_printf(m, "0x%04x: 0x%08x\n", i, v);
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 } 39 }
49 40
50 return 0; 41 return 0;
51} 42}
52 43
53static int armada_debugfs_reg_r_open(struct inode *inode, struct file *file) 44static int armada_debugfs_crtc_reg_open(struct inode *inode, struct file *file)
54{ 45{
55 return single_open(file, armada_debugfs_reg_show, inode->i_private); 46 return single_open(file, armada_debugfs_crtc_reg_show,
47 inode->i_private);
56} 48}
57 49
58static const struct file_operations fops_reg_r = { 50static int armada_debugfs_crtc_reg_write(struct file *file,
59 .owner = THIS_MODULE, 51 const char __user *ptr, size_t len, loff_t *off)
60 .open = armada_debugfs_reg_r_open,
61 .read = seq_read,
62 .llseek = seq_lseek,
63 .release = single_release,
64};
65
66static int armada_debugfs_write(struct file *file, const char __user *ptr,
67 size_t len, loff_t *off)
68{ 52{
69 struct drm_device *dev = file->private_data; 53 struct armada_crtc *dcrtc;
70 struct armada_private *priv = dev->dev_private; 54 unsigned long reg, mask, val;
71 struct armada_crtc *dcrtc = priv->dcrtc[0]; 55 char buf[32];
72 char buf[32], *p;
73 uint32_t reg, val;
74 int ret; 56 int ret;
57 u32 v;
75 58
76 if (*off != 0) 59 if (*off != 0)
77 return 0; 60 return 0;
@@ -84,24 +67,35 @@ static int armada_debugfs_write(struct file *file, const char __user *ptr,
84 return ret; 67 return ret;
85 buf[len] = '\0'; 68 buf[len] = '\0';
86 69
87 reg = simple_strtoul(buf, &p, 16); 70 if (sscanf(buf, "%lx %lx %lx", &reg, &mask, &val) != 3)
88 if (!isspace(*p))
89 return -EINVAL; 71 return -EINVAL;
90 val = simple_strtoul(p + 1, NULL, 16); 72 if (reg < 0x84 || reg > 0x1c4 || reg & 3)
73 return -ERANGE;
91 74
92 if (reg >= 0x84 && reg <= 0x1c4) 75 dcrtc = ((struct seq_file *)file->private_data)->private;
93 writel(val, dcrtc->base + reg); 76 v = readl(dcrtc->base + reg);
77 v &= ~mask;
78 v |= val & mask;
79 writel(v, dcrtc->base + reg);
94 80
95 return len; 81 return len;
96} 82}
97 83
98static const struct file_operations fops_reg_w = { 84static const struct file_operations armada_debugfs_crtc_reg_fops = {
99 .owner = THIS_MODULE, 85 .owner = THIS_MODULE,
100 .open = simple_open, 86 .open = armada_debugfs_crtc_reg_open,
101 .write = armada_debugfs_write, 87 .read = seq_read,
102 .llseek = noop_llseek, 88 .write = armada_debugfs_crtc_reg_write,
89 .llseek = seq_lseek,
90 .release = single_release,
103}; 91};
104 92
93void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc)
94{
95 debugfs_create_file("armada-regs", 0600, dcrtc->crtc.debugfs_entry,
96 dcrtc, &armada_debugfs_crtc_reg_fops);
97}
98
105static struct drm_info_list armada_debugfs_list[] = { 99static struct drm_info_list armada_debugfs_list[] = {
106 { "gem_linear", armada_debugfs_gem_linear_show, 0 }, 100 { "gem_linear", armada_debugfs_gem_linear_show, 0 },
107}; 101};
@@ -109,24 +103,8 @@ static struct drm_info_list armada_debugfs_list[] = {
109 103
110int armada_drm_debugfs_init(struct drm_minor *minor) 104int armada_drm_debugfs_init(struct drm_minor *minor)
111{ 105{
112 struct dentry *de; 106 drm_debugfs_create_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES,
113 int ret; 107 minor->debugfs_root, minor);
114
115 ret = drm_debugfs_create_files(armada_debugfs_list,
116 ARMADA_DEBUGFS_ENTRIES,
117 minor->debugfs_root, minor);
118 if (ret)
119 return ret;
120
121 de = debugfs_create_file("reg", S_IFREG | S_IRUSR,
122 minor->debugfs_root, minor->dev, &fops_reg_r);
123 if (!de)
124 return -ENOMEM;
125
126 de = debugfs_create_file("reg_wr", S_IFREG | S_IWUSR,
127 minor->debugfs_root, minor->dev, &fops_reg_w);
128 if (!de)
129 return -ENOMEM;
130 108
131 return 0; 109 return 0;
132} 110}
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h
index f09083ff15d3..b6307235f320 100644
--- a/drivers/gpu/drm/armada/armada_drm.h
+++ b/drivers/gpu/drm/armada/armada_drm.h
@@ -78,6 +78,7 @@ void armada_fbdev_fini(struct drm_device *);
78 78
79int armada_overlay_plane_create(struct drm_device *, unsigned long); 79int armada_overlay_plane_create(struct drm_device *, unsigned long);
80 80
81void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc);
81int armada_drm_debugfs_init(struct drm_minor *); 82int armada_drm_debugfs_init(struct drm_minor *);
82 83
83#endif 84#endif
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index e660c5ca52ae..f1729398b1bd 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -100,6 +100,17 @@ static int armada_drm_bind(struct device *dev)
100 return ret; 100 return ret;
101 } 101 }
102 102
103 /* Remove early framebuffers */
104 ret = drm_fb_helper_remove_conflicting_framebuffers(NULL,
105 "armada-drm-fb",
106 false);
107 if (ret) {
108 dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n",
109 __func__, ret);
110 kfree(priv);
111 return ret;
112 }
113
103 priv->drm.dev_private = priv; 114 priv->drm.dev_private = priv;
104 115
105 dev_set_drvdata(dev, &priv->drm); 116 dev_set_drvdata(dev, &priv->drm);
@@ -171,6 +182,8 @@ static void armada_drm_unbind(struct device *dev)
171 182
172 drm_dev_unregister(&priv->drm); 183 drm_dev_unregister(&priv->drm);
173 184
185 drm_atomic_helper_shutdown(&priv->drm);
186
174 component_unbind_all(dev, &priv->drm); 187 component_unbind_all(dev, &priv->drm);
175 188
176 drm_mode_config_cleanup(&priv->drm); 189 drm_mode_config_cleanup(&priv->drm);
@@ -191,23 +204,15 @@ static int compare_dev_name(struct device *dev, void *data)
191} 204}
192 205
193static void armada_add_endpoints(struct device *dev, 206static void armada_add_endpoints(struct device *dev,
194 struct component_match **match, struct device_node *port) 207 struct component_match **match, struct device_node *dev_node)
195{ 208{
196 struct device_node *ep, *remote; 209 struct device_node *ep, *remote;
197 210
198 for_each_child_of_node(port, ep) { 211 for_each_endpoint_of_node(dev_node, ep) {
199 remote = of_graph_get_remote_port_parent(ep); 212 remote = of_graph_get_remote_port_parent(ep);
200 if (!remote || !of_device_is_available(remote)) { 213 if (remote && of_device_is_available(remote))
201 of_node_put(remote); 214 drm_of_component_match_add(dev, match, compare_of,
202 continue; 215 remote);
203 } else if (!of_device_is_available(remote->parent)) {
204 dev_warn(dev, "parent device of %pOF is not available\n",
205 remote);
206 of_node_put(remote);
207 continue;
208 }
209
210 drm_of_component_match_add(dev, match, compare_of, remote);
211 of_node_put(remote); 216 of_node_put(remote);
212 } 217 }
213} 218}
@@ -229,7 +234,6 @@ static int armada_drm_probe(struct platform_device *pdev)
229 234
230 if (dev->platform_data) { 235 if (dev->platform_data) {
231 char **devices = dev->platform_data; 236 char **devices = dev->platform_data;
232 struct device_node *port;
233 struct device *d; 237 struct device *d;
234 int i; 238 int i;
235 239
@@ -245,10 +249,8 @@ static int armada_drm_probe(struct platform_device *pdev)
245 for (i = 0; devices[i]; i++) { 249 for (i = 0; devices[i]; i++) {
246 d = bus_find_device_by_name(&platform_bus_type, NULL, 250 d = bus_find_device_by_name(&platform_bus_type, NULL,
247 devices[i]); 251 devices[i]);
248 if (d && d->of_node) { 252 if (d && d->of_node)
249 for_each_child_of_node(d->of_node, port) 253 armada_add_endpoints(dev, &match, d->of_node);
250 armada_add_endpoints(dev, &match, port);
251 }
252 put_device(d); 254 put_device(d);
253 } 255 }
254 } 256 }
diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h
index 277580b36758..5b1af0cc9f50 100644
--- a/drivers/gpu/drm/armada/armada_hw.h
+++ b/drivers/gpu/drm/armada/armada_hw.h
@@ -88,6 +88,16 @@ enum {
88 ADV_VSYNC_H_OFF = 0xfff << 0, 88 ADV_VSYNC_H_OFF = 0xfff << 0,
89}; 89};
90 90
91/* LCD_CFG_RDREG4F - Armada 510 only */
92enum {
93 CFG_SRAM_WAIT = BIT(11),
94 CFG_SMPN_FASTTX = BIT(10),
95 CFG_DMA_ARB = BIT(9),
96 CFG_DMA_WM_EN = BIT(8),
97 CFG_DMA_WM_MASK = 0xff,
98#define CFG_DMA_WM(x) ((x) & CFG_DMA_WM_MASK)
99};
100
91enum { 101enum {
92 CFG_565 = 0, 102 CFG_565 = 0,
93 CFG_1555 = 1, 103 CFG_1555 = 1,
@@ -169,6 +179,10 @@ enum {
169 SRAM_READ = 0 << 14, 179 SRAM_READ = 0 << 14,
170 SRAM_WRITE = 2 << 14, 180 SRAM_WRITE = 2 << 14,
171 SRAM_INIT = 3 << 14, 181 SRAM_INIT = 3 << 14,
182 SRAM_GAMMA_YR = 0x0 << 8,
183 SRAM_GAMMA_UG = 0x1 << 8,
184 SRAM_GAMMA_VB = 0x2 << 8,
185 SRAM_PALETTE = 0x3 << 8,
172 SRAM_HWC32_RAM1 = 0xc << 8, 186 SRAM_HWC32_RAM1 = 0xc << 8,
173 SRAM_HWC32_RAM2 = 0xd << 8, 187 SRAM_HWC32_RAM2 = 0xd << 8,
174 SRAM_HWC32_RAMR = SRAM_HWC32_RAM1, 188 SRAM_HWC32_RAMR = SRAM_HWC32_RAM1,
@@ -316,19 +330,4 @@ enum {
316 PWRDN_IRQ_LEVEL = 1 << 0, 330 PWRDN_IRQ_LEVEL = 1 << 0,
317}; 331};
318 332
319static inline u32 armada_rect_hw_fp(struct drm_rect *r)
320{
321 return (drm_rect_height(r) & 0xffff0000) | drm_rect_width(r) >> 16;
322}
323
324static inline u32 armada_rect_hw(struct drm_rect *r)
325{
326 return drm_rect_height(r) << 16 | (drm_rect_width(r) & 0x0000ffff);
327}
328
329static inline u32 armada_rect_yx(struct drm_rect *r)
330{
331 return (r)->y1 << 16 | ((r)->x1 & 0x0000ffff);
332}
333
334#endif 333#endif
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index 8d770641fcc4..a79d6e940435 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -27,7 +27,7 @@
27#define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601 27#define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601
28 28
29struct armada_overlay_state { 29struct armada_overlay_state {
30 struct drm_plane_state base; 30 struct armada_plane_state base;
31 u32 colorkey_yr; 31 u32 colorkey_yr;
32 u32 colorkey_ug; 32 u32 colorkey_ug;
33 u32 colorkey_vb; 33 u32 colorkey_vb;
@@ -38,7 +38,7 @@ struct armada_overlay_state {
38 u16 saturation; 38 u16 saturation;
39}; 39};
40#define drm_to_overlay_state(s) \ 40#define drm_to_overlay_state(s) \
41 container_of(s, struct armada_overlay_state, base) 41 container_of(s, struct armada_overlay_state, base.base)
42 42
43static inline u32 armada_spu_contrast(struct drm_plane_state *state) 43static inline u32 armada_spu_contrast(struct drm_plane_state *state)
44{ 44{
@@ -94,41 +94,39 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
94 armada_reg_queue_mod(regs, idx, 94 armada_reg_queue_mod(regs, idx,
95 0, CFG_PDWN16x66 | CFG_PDWN32x66, 95 0, CFG_PDWN16x66 | CFG_PDWN32x66,
96 LCD_SPU_SRAM_PARA1); 96 LCD_SPU_SRAM_PARA1);
97 val = armada_rect_hw_fp(&state->src); 97 val = armada_src_hw(state);
98 if (armada_rect_hw_fp(&old_state->src) != val) 98 if (armada_src_hw(old_state) != val)
99 armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN); 99 armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN);
100 val = armada_rect_yx(&state->dst); 100 val = armada_dst_yx(state);
101 if (armada_rect_yx(&old_state->dst) != val) 101 if (armada_dst_yx(old_state) != val)
102 armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN); 102 armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN);
103 val = armada_rect_hw(&state->dst); 103 val = armada_dst_hw(state);
104 if (armada_rect_hw(&old_state->dst) != val) 104 if (armada_dst_hw(old_state) != val)
105 armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN); 105 armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);
106 /* FIXME: overlay on an interlaced display */ 106 /* FIXME: overlay on an interlaced display */
107 if (old_state->src.x1 != state->src.x1 || 107 if (old_state->src.x1 != state->src.x1 ||
108 old_state->src.y1 != state->src.y1 || 108 old_state->src.y1 != state->src.y1 ||
109 old_state->fb != state->fb) { 109 old_state->fb != state->fb ||
110 state->crtc->state->mode_changed) {
110 const struct drm_format_info *format; 111 const struct drm_format_info *format;
111 u16 src_x, pitches[3]; 112 u16 src_x;
112 u32 addrs[2][3];
113 113
114 armada_drm_plane_calc(state, addrs, pitches, false); 114 armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
115
116 armada_reg_queue_set(regs, idx, addrs[0][0],
117 LCD_SPU_DMA_START_ADDR_Y0); 115 LCD_SPU_DMA_START_ADDR_Y0);
118 armada_reg_queue_set(regs, idx, addrs[0][1], 116 armada_reg_queue_set(regs, idx, armada_addr(state, 0, 1),
119 LCD_SPU_DMA_START_ADDR_U0); 117 LCD_SPU_DMA_START_ADDR_U0);
120 armada_reg_queue_set(regs, idx, addrs[0][2], 118 armada_reg_queue_set(regs, idx, armada_addr(state, 0, 2),
121 LCD_SPU_DMA_START_ADDR_V0); 119 LCD_SPU_DMA_START_ADDR_V0);
122 armada_reg_queue_set(regs, idx, addrs[1][0], 120 armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),
123 LCD_SPU_DMA_START_ADDR_Y1); 121 LCD_SPU_DMA_START_ADDR_Y1);
124 armada_reg_queue_set(regs, idx, addrs[1][1], 122 armada_reg_queue_set(regs, idx, armada_addr(state, 1, 1),
125 LCD_SPU_DMA_START_ADDR_U1); 123 LCD_SPU_DMA_START_ADDR_U1);
126 armada_reg_queue_set(regs, idx, addrs[1][2], 124 armada_reg_queue_set(regs, idx, armada_addr(state, 1, 2),
127 LCD_SPU_DMA_START_ADDR_V1); 125 LCD_SPU_DMA_START_ADDR_V1);
128 126
129 val = pitches[0] << 16 | pitches[0]; 127 val = armada_pitch(state, 0) << 16 | armada_pitch(state, 0);
130 armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC); 128 armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC);
131 val = pitches[1] << 16 | pitches[2]; 129 val = armada_pitch(state, 1) << 16 | armada_pitch(state, 2);
132 armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV); 130 armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);
133 131
134 cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | 132 cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
@@ -146,6 +144,8 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
146 src_x = state->src.x1 >> 16; 144 src_x = state->src.x1 >> 16;
147 if (format->num_planes == 1 && src_x & (format->hsub - 1)) 145 if (format->num_planes == 1 && src_x & (format->hsub - 1))
148 cfg ^= CFG_DMA_MOD(CFG_SWAPUV); 146 cfg ^= CFG_DMA_MOD(CFG_SWAPUV);
147 if (to_armada_plane_state(state)->interlace)
148 cfg |= CFG_DMA_FTOGGLE;
149 cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT | 149 cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |
150 CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | 150 CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |
151 CFG_SWAPYU | CFG_YUV2RGB) | 151 CFG_SWAPYU | CFG_YUV2RGB) |
@@ -307,13 +307,10 @@ static void armada_overlay_reset(struct drm_plane *plane)
307 if (plane->state) 307 if (plane->state)
308 __drm_atomic_helper_plane_destroy_state(plane->state); 308 __drm_atomic_helper_plane_destroy_state(plane->state);
309 kfree(plane->state); 309 kfree(plane->state);
310 plane->state = NULL;
310 311
311 state = kzalloc(sizeof(*state), GFP_KERNEL); 312 state = kzalloc(sizeof(*state), GFP_KERNEL);
312 if (state) { 313 if (state) {
313 state->base.plane = plane;
314 state->base.color_encoding = DEFAULT_ENCODING;
315 state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
316 state->base.rotation = DRM_MODE_ROTATE_0;
317 state->colorkey_yr = 0xfefefe00; 314 state->colorkey_yr = 0xfefefe00;
318 state->colorkey_ug = 0x01010100; 315 state->colorkey_ug = 0x01010100;
319 state->colorkey_vb = 0x01010100; 316 state->colorkey_vb = 0x01010100;
@@ -323,8 +320,10 @@ static void armada_overlay_reset(struct drm_plane *plane)
323 state->brightness = DEFAULT_BRIGHTNESS; 320 state->brightness = DEFAULT_BRIGHTNESS;
324 state->contrast = DEFAULT_CONTRAST; 321 state->contrast = DEFAULT_CONTRAST;
325 state->saturation = DEFAULT_SATURATION; 322 state->saturation = DEFAULT_SATURATION;
323 __drm_atomic_helper_plane_reset(plane, &state->base.base);
324 state->base.base.color_encoding = DEFAULT_ENCODING;
325 state->base.base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
326 } 326 }
327 plane->state = &state->base;
328} 327}
329 328
330struct drm_plane_state * 329struct drm_plane_state *
@@ -337,8 +336,9 @@ armada_overlay_duplicate_state(struct drm_plane *plane)
337 336
338 state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL); 337 state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
339 if (state) 338 if (state)
340 __drm_atomic_helper_plane_duplicate_state(plane, &state->base); 339 __drm_atomic_helper_plane_duplicate_state(plane,
341 return &state->base; 340 &state->base.base);
341 return &state->base.base;
342} 342}
343 343
344static int armada_overlay_set_property(struct drm_plane *plane, 344static int armada_overlay_set_property(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c
index 9f36423dd394..dbd4d52e8a32 100644
--- a/drivers/gpu/drm/armada/armada_plane.c
+++ b/drivers/gpu/drm/armada/armada_plane.c
@@ -79,23 +79,6 @@ void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
79 } 79 }
80} 80}
81 81
82static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state,
83 struct armada_regs *regs, bool interlaced)
84{
85 u16 pitches[3];
86 u32 addrs[2][3];
87 unsigned i = 0;
88
89 armada_drm_plane_calc(state, addrs, pitches, interlaced);
90
91 /* write offset, base, and pitch */
92 armada_reg_queue_set(regs, i, addrs[0][0], LCD_CFG_GRA_START_ADDR0);
93 armada_reg_queue_set(regs, i, addrs[1][0], LCD_CFG_GRA_START_ADDR1);
94 armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH);
95
96 return i;
97}
98
99int armada_drm_plane_prepare_fb(struct drm_plane *plane, 82int armada_drm_plane_prepare_fb(struct drm_plane *plane,
100 struct drm_plane_state *state) 83 struct drm_plane_state *state)
101{ 84{
@@ -126,20 +109,50 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
126int armada_drm_plane_atomic_check(struct drm_plane *plane, 109int armada_drm_plane_atomic_check(struct drm_plane *plane,
127 struct drm_plane_state *state) 110 struct drm_plane_state *state)
128{ 111{
129 if (state->fb && !WARN_ON(!state->crtc)) { 112 struct armada_plane_state *st = to_armada_plane_state(state);
130 struct drm_crtc *crtc = state->crtc; 113 struct drm_crtc *crtc = state->crtc;
131 struct drm_crtc_state *crtc_state; 114 struct drm_crtc_state *crtc_state;
132 115 bool interlace;
133 if (state->state) 116 int ret;
134 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); 117
135 else 118 if (!state->fb || WARN_ON(!state->crtc)) {
136 crtc_state = crtc->state;
137 return drm_atomic_helper_check_plane_state(state, crtc_state,
138 0, INT_MAX,
139 true, false);
140 } else {
141 state->visible = false; 119 state->visible = false;
120 return 0;
121 }
122
123 if (state->state)
124 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
125 else
126 crtc_state = crtc->state;
127
128 ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0,
129 INT_MAX, true, false);
130 if (ret)
131 return ret;
132
133 interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
134 if (interlace) {
135 if ((state->dst.y1 | state->dst.y2) & 1)
136 return -EINVAL;
137 st->src_hw = drm_rect_height(&state->src) >> 17;
138 st->dst_yx = state->dst.y1 >> 1;
139 st->dst_hw = drm_rect_height(&state->dst) >> 1;
140 } else {
141 st->src_hw = drm_rect_height(&state->src) >> 16;
142 st->dst_yx = state->dst.y1;
143 st->dst_hw = drm_rect_height(&state->dst);
142 } 144 }
145
146 st->src_hw <<= 16;
147 st->src_hw |= drm_rect_width(&state->src) >> 16;
148 st->dst_yx <<= 16;
149 st->dst_yx |= state->dst.x1 & 0x0000ffff;
150 st->dst_hw <<= 16;
151 st->dst_hw |= drm_rect_width(&state->dst) & 0x0000ffff;
152
153 armada_drm_plane_calc(state, st->addrs, st->pitches, interlace);
154 st->interlace = interlace;
155
143 return 0; 156 return 0;
144} 157}
145 158
@@ -173,21 +186,25 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
173 val |= CFG_PDWN256x24; 186 val |= CFG_PDWN256x24;
174 armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1); 187 armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
175 } 188 }
176 val = armada_rect_hw_fp(&state->src); 189 val = armada_src_hw(state);
177 if (armada_rect_hw_fp(&old_state->src) != val) 190 if (armada_src_hw(old_state) != val)
178 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN); 191 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
179 val = armada_rect_yx(&state->dst); 192 val = armada_dst_yx(state);
180 if (armada_rect_yx(&old_state->dst) != val) 193 if (armada_dst_yx(old_state) != val)
181 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN); 194 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
182 val = armada_rect_hw(&state->dst); 195 val = armada_dst_hw(state);
183 if (armada_rect_hw(&old_state->dst) != val) 196 if (armada_dst_hw(old_state) != val)
184 armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN); 197 armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
185 if (old_state->src.x1 != state->src.x1 || 198 if (old_state->src.x1 != state->src.x1 ||
186 old_state->src.y1 != state->src.y1 || 199 old_state->src.y1 != state->src.y1 ||
187 old_state->fb != state->fb || 200 old_state->fb != state->fb ||
188 state->crtc->state->mode_changed) { 201 state->crtc->state->mode_changed) {
189 idx += armada_drm_crtc_calc_fb(state, regs + idx, 202 armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
190 dcrtc->interlaced); 203 LCD_CFG_GRA_START_ADDR0);
204 armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),
205 LCD_CFG_GRA_START_ADDR1);
206 armada_reg_queue_mod(regs, idx, armada_pitch(state, 0), 0xffff,
207 LCD_CFG_GRA_PITCH);
191 } 208 }
192 if (old_state->fb != state->fb || 209 if (old_state->fb != state->fb ||
193 state->crtc->state->mode_changed) { 210 state->crtc->state->mode_changed) {
@@ -197,7 +214,7 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
197 cfg |= CFG_PALETTE_ENA; 214 cfg |= CFG_PALETTE_ENA;
198 if (state->visible) 215 if (state->visible)
199 cfg |= CFG_GRA_ENA; 216 cfg |= CFG_GRA_ENA;
200 if (dcrtc->interlaced) 217 if (to_armada_plane_state(state)->interlace)
201 cfg |= CFG_GRA_FTOGGLE; 218 cfg |= CFG_GRA_FTOGGLE;
202 cfg_mask = CFG_GRAFORMAT | 219 cfg_mask = CFG_GRAFORMAT |
203 CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | 220 CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
@@ -248,7 +265,7 @@ static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
248 /* Disable plane and power down most RAMs and FIFOs */ 265 /* Disable plane and power down most RAMs and FIFOs */
249 armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0); 266 armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
250 armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 | 267 armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
251 CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66, 268 CFG_PDWN32x32 | CFG_PDWN64x66,
252 0, LCD_SPU_SRAM_PARA1); 269 0, LCD_SPU_SRAM_PARA1);
253 270
254 dcrtc->regs_idx += idx; 271 dcrtc->regs_idx += idx;
@@ -262,12 +279,37 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
262 .atomic_disable = armada_drm_primary_plane_atomic_disable, 279 .atomic_disable = armada_drm_primary_plane_atomic_disable,
263}; 280};
264 281
282void armada_plane_reset(struct drm_plane *plane)
283{
284 struct armada_plane_state *st;
285 if (plane->state)
286 __drm_atomic_helper_plane_destroy_state(plane->state);
287 kfree(plane->state);
288 st = kzalloc(sizeof(*st), GFP_KERNEL);
289 if (st)
290 __drm_atomic_helper_plane_reset(plane, &st->base);
291}
292
293struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
294{
295 struct armada_plane_state *st;
296
297 if (WARN_ON(!plane->state))
298 return NULL;
299
300 st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
301 if (st)
302 __drm_atomic_helper_plane_duplicate_state(plane, &st->base);
303
304 return &st->base;
305}
306
265static const struct drm_plane_funcs armada_primary_plane_funcs = { 307static const struct drm_plane_funcs armada_primary_plane_funcs = {
266 .update_plane = drm_atomic_helper_update_plane, 308 .update_plane = drm_atomic_helper_update_plane,
267 .disable_plane = drm_atomic_helper_disable_plane, 309 .disable_plane = drm_atomic_helper_disable_plane,
268 .destroy = drm_primary_helper_destroy, 310 .destroy = drm_primary_helper_destroy,
269 .reset = drm_atomic_helper_plane_reset, 311 .reset = armada_plane_reset,
270 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 312 .atomic_duplicate_state = armada_plane_duplicate_state,
271 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 313 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
272}; 314};
273 315
diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h
index ff4281ba7fad..2707ec781941 100644
--- a/drivers/gpu/drm/armada/armada_plane.h
+++ b/drivers/gpu/drm/armada/armada_plane.h
@@ -1,6 +1,24 @@
1#ifndef ARMADA_PLANE_H 1#ifndef ARMADA_PLANE_H
2#define ARMADA_PLANE_H 2#define ARMADA_PLANE_H
3 3
4struct armada_plane_state {
5 struct drm_plane_state base;
6 u32 src_hw;
7 u32 dst_yx;
8 u32 dst_hw;
9 u32 addrs[2][3];
10 u16 pitches[3];
11 bool interlace;
12};
13
14#define to_armada_plane_state(st) \
15 container_of(st, struct armada_plane_state, base)
16#define armada_src_hw(state) to_armada_plane_state(state)->src_hw
17#define armada_dst_yx(state) to_armada_plane_state(state)->dst_yx
18#define armada_dst_hw(state) to_armada_plane_state(state)->dst_hw
19#define armada_addr(state, f, p) to_armada_plane_state(state)->addrs[f][p]
20#define armada_pitch(state, n) to_armada_plane_state(state)->pitches[n]
21
4void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3], 22void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
5 u16 pitches[3], bool interlaced); 23 u16 pitches[3], bool interlaced);
6int armada_drm_plane_prepare_fb(struct drm_plane *plane, 24int armada_drm_plane_prepare_fb(struct drm_plane *plane,
@@ -9,6 +27,11 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
9 struct drm_plane_state *old_state); 27 struct drm_plane_state *old_state);
10int armada_drm_plane_atomic_check(struct drm_plane *plane, 28int armada_drm_plane_atomic_check(struct drm_plane *plane,
11 struct drm_plane_state *state); 29 struct drm_plane_state *state);
30void armada_plane_reset(struct drm_plane *plane);
31struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane);
32void armada_plane_destroy_state(struct drm_plane *plane,
33 struct drm_plane_state *state);
34
12int armada_drm_primary_plane_init(struct drm_device *drm, 35int armada_drm_primary_plane_init(struct drm_device *drm,
13 struct drm_plane *primary); 36 struct drm_plane *primary);
14 37