diff options
author | Dave Airlie <airlied@redhat.com> | 2019-07-04 00:08:07 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2019-07-04 00:09:50 -0400 |
commit | f07b56e7d0b21b49d809b301837c6ba39c27309a (patch) | |
tree | e3a5dbe293772c5e79415317f069a5e668ede8c3 | |
parent | a22719cce54bc18001a7c8be9c713ba629f5801c (diff) | |
parent | 837567c1e9d587c0b438263c9cfd32de46640e16 (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.c | 130 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.c | 214 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.h | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_debugfs.c | 98 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_drm.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_drv.c | 38 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_hw.h | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_overlay.c | 56 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_plane.c | 124 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_plane.h | 23 |
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 | ||
17 | struct armada510_variant_data { | ||
18 | struct clk *clks[4]; | ||
19 | struct clk *sel_clk; | ||
20 | }; | ||
21 | |||
17 | static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev) | 22 | static 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 | ||
81 | static const u32 armada510_clk_sels[] = { | ||
82 | SCLK_510_EXTCLK0, | ||
83 | SCLK_510_EXTCLK1, | ||
84 | SCLK_510_PLL, | ||
85 | SCLK_510_AXI, | ||
86 | }; | ||
87 | |||
88 | static 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 | */ |
47 | static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, | 103 | static 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 | ||
82 | static void armada510_crtc_disable(struct armada_crtc *dcrtc) | 136 | static 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 | ||
90 | static void armada510_crtc_enable(struct armada_crtc *dcrtc, | 144 | static 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 | ||
133 | static 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 | |||
171 | static 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 */ |
134 | static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, | 198 | static 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 | ||
414 | static 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 | |||
348 | static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc, | 428 | static 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 | ||
440 | static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { | 529 | static 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 | ||
777 | static 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. */ |
680 | static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc) | 786 | static 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 | ||
822 | int 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 | |||
887 | found: | ||
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 | |||
714 | static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, | 899 | static 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 | ||
799 | err_crtc_init: | 989 | err_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; | |||
39 | struct armada_crtc { | 39 | struct 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 | ||
76 | void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); | 76 | void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); |
77 | 77 | ||
78 | struct armada_clocking_params { | ||
79 | unsigned long permillage_min; | ||
80 | unsigned long permillage_max; | ||
81 | u32 settable; | ||
82 | u32 div_max; | ||
83 | }; | ||
84 | |||
85 | struct armada_clk_result { | ||
86 | unsigned long desired_clk_hz; | ||
87 | struct clk *clk; | ||
88 | u32 div; | ||
89 | }; | ||
90 | |||
91 | int 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 | |||
78 | extern struct platform_driver armada_lcd_platform_driver; | 97 | extern 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 | ||
31 | static int armada_debugfs_reg_show(struct seq_file *m, void *data) | 31 | static 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 | ||
53 | static int armada_debugfs_reg_r_open(struct inode *inode, struct file *file) | 44 | static 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 | ||
58 | static const struct file_operations fops_reg_r = { | 50 | static 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 | |||
66 | static 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", ®, &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 | ||
98 | static const struct file_operations fops_reg_w = { | 84 | static 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 | ||
93 | void 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 | |||
105 | static struct drm_info_list armada_debugfs_list[] = { | 99 | static 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 | ||
110 | int armada_drm_debugfs_init(struct drm_minor *minor) | 104 | int 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 | ||
79 | int armada_overlay_plane_create(struct drm_device *, unsigned long); | 79 | int armada_overlay_plane_create(struct drm_device *, unsigned long); |
80 | 80 | ||
81 | void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc); | ||
81 | int armada_drm_debugfs_init(struct drm_minor *); | 82 | int 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 | ||
193 | static void armada_add_endpoints(struct device *dev, | 206 | static 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 */ | ||
92 | enum { | ||
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 | |||
91 | enum { | 101 | enum { |
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 | ||
319 | static 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 | |||
324 | static inline u32 armada_rect_hw(struct drm_rect *r) | ||
325 | { | ||
326 | return drm_rect_height(r) << 16 | (drm_rect_width(r) & 0x0000ffff); | ||
327 | } | ||
328 | |||
329 | static 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 | ||
29 | struct armada_overlay_state { | 29 | struct 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 | ||
43 | static inline u32 armada_spu_contrast(struct drm_plane_state *state) | 43 | static 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 | ||
330 | struct drm_plane_state * | 329 | struct 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 | ||
344 | static int armada_overlay_set_property(struct drm_plane *plane, | 344 | static 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 | ||
82 | static 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 | |||
99 | int armada_drm_plane_prepare_fb(struct drm_plane *plane, | 82 | int 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, | |||
126 | int armada_drm_plane_atomic_check(struct drm_plane *plane, | 109 | int 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 | ||
282 | void 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 | |||
293 | struct 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 | |||
265 | static const struct drm_plane_funcs armada_primary_plane_funcs = { | 307 | static 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 | ||
4 | struct 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 | |||
4 | void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3], | 22 | void 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); |
6 | int armada_drm_plane_prepare_fb(struct drm_plane *plane, | 24 | int 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); |
10 | int armada_drm_plane_atomic_check(struct drm_plane *plane, | 28 | int armada_drm_plane_atomic_check(struct drm_plane *plane, |
11 | struct drm_plane_state *state); | 29 | struct drm_plane_state *state); |
30 | void armada_plane_reset(struct drm_plane *plane); | ||
31 | struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane); | ||
32 | void armada_plane_destroy_state(struct drm_plane *plane, | ||
33 | struct drm_plane_state *state); | ||
34 | |||
12 | int armada_drm_primary_plane_init(struct drm_device *drm, | 35 | int armada_drm_primary_plane_init(struct drm_device *drm, |
13 | struct drm_plane *primary); | 36 | struct drm_plane *primary); |
14 | 37 | ||