aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h8
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c47
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.h1
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c238
-rw-r--r--drivers/gpu/drm/arm/malidp_regs.h11
5 files changed, 296 insertions, 9 deletions
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index e3eb0cb1f385..b76c86f18a56 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -55,6 +55,12 @@ struct malidp_plane {
55 const struct malidp_layer *layer; 55 const struct malidp_layer *layer;
56}; 56};
57 57
58enum mmu_prefetch_mode {
59 MALIDP_PREFETCH_MODE_NONE,
60 MALIDP_PREFETCH_MODE_PARTIAL,
61 MALIDP_PREFETCH_MODE_FULL,
62};
63
58struct malidp_plane_state { 64struct malidp_plane_state {
59 struct drm_plane_state base; 65 struct drm_plane_state base;
60 66
@@ -63,6 +69,8 @@ struct malidp_plane_state {
63 /* internal format ID */ 69 /* internal format ID */
64 u8 format; 70 u8 format;
65 u8 n_planes; 71 u8 n_planes;
72 enum mmu_prefetch_mode mmu_prefetch_mode;
73 u32 mmu_prefetch_pgsize;
66}; 74};
67 75
68#define to_malidp_plane(x) container_of(x, struct malidp_plane, base) 76#define to_malidp_plane(x) container_of(x, struct malidp_plane, base)
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index 2781e462c1ed..c874ef4ac005 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -84,16 +84,45 @@ static const struct malidp_format_id malidp550_de_formats[] = {
84}; 84};
85 85
86static const struct malidp_layer malidp500_layers[] = { 86static const struct malidp_layer malidp500_layers[] = {
87 { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB }, 87 /* id, base address, fb pointer address base, stride offset,
88 { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 88 * yuv2rgb matrix offset, mmu control register offset
89 { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 89 */
90 { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
91 MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0 },
92 { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
93 MALIDP_DE_LG_STRIDE, 0, 0 },
94 { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
95 MALIDP_DE_LG_STRIDE, 0, 0 },
90}; 96};
91 97
92static const struct malidp_layer malidp550_layers[] = { 98static const struct malidp_layer malidp550_layers[] = {
93 { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB }, 99 /* id, base address, fb pointer address base, stride offset,
94 { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 100 * yuv2rgb matrix offset, mmu control register offset
95 { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB }, 101 */
96 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 }, 102 { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
103 MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0 },
104 { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
105 MALIDP_DE_LG_STRIDE, 0, 0 },
106 { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
107 MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0 },
108 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
109 MALIDP550_DE_LS_R1_STRIDE, 0, 0 },
110};
111
112static const struct malidp_layer malidp650_layers[] = {
113 /* id, base address, fb pointer address base, stride offset,
114 * yuv2rgb matrix offset, mmu control register offset
115 */
116 { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
117 MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
118 MALIDP650_DE_LV_MMU_CTRL },
119 { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
120 MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL },
121 { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
122 MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
123 MALIDP650_DE_LV_MMU_CTRL },
124 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
125 MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL },
97}; 126};
98 127
99#define SE_N_SCALING_COEFFS 96 128#define SE_N_SCALING_COEFFS 96
@@ -853,8 +882,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
853 .dc_base = MALIDP550_DC_BASE, 882 .dc_base = MALIDP550_DC_BASE,
854 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 883 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
855 .features = MALIDP_REGMAP_HAS_CLEARIRQ, 884 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
856 .n_layers = ARRAY_SIZE(malidp550_layers), 885 .n_layers = ARRAY_SIZE(malidp650_layers),
857 .layers = malidp550_layers, 886 .layers = malidp650_layers,
858 .de_irq_map = { 887 .de_irq_map = {
859 .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 888 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
860 MALIDP650_DE_IRQ_DRIFT | 889 MALIDP650_DE_IRQ_DRIFT |
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index 9fc94c08190f..0d7f9ea0ade8 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -62,6 +62,7 @@ struct malidp_layer {
62 u16 ptr; /* address offset for the pointer register */ 62 u16 ptr; /* address offset for the pointer register */
63 u16 stride_offset; /* offset to the first stride register. */ 63 u16 stride_offset; /* offset to the first stride register. */
64 s16 yuv2rgb_offset; /* offset to the YUV->RGB matrix entries */ 64 s16 yuv2rgb_offset; /* offset to the YUV->RGB matrix entries */
65 u16 mmu_ctrl_offset; /* offset to the MMU control register */
65}; 66};
66 67
67enum malidp_scaling_coeff_set { 68enum malidp_scaling_coeff_set {
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 39416bcd880e..76aafc296e1b 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -10,11 +10,14 @@
10 * ARM Mali DP plane manipulation routines. 10 * ARM Mali DP plane manipulation routines.
11 */ 11 */
12 12
13#include <linux/iommu.h>
14
13#include <drm/drmP.h> 15#include <drm/drmP.h>
14#include <drm/drm_atomic.h> 16#include <drm/drm_atomic.h>
15#include <drm/drm_atomic_helper.h> 17#include <drm/drm_atomic_helper.h>
16#include <drm/drm_fb_cma_helper.h> 18#include <drm/drm_fb_cma_helper.h>
17#include <drm/drm_gem_cma_helper.h> 19#include <drm/drm_gem_cma_helper.h>
20#include <drm/drm_gem_framebuffer_helper.h>
18#include <drm/drm_plane_helper.h> 21#include <drm/drm_plane_helper.h>
19#include <drm/drm_print.h> 22#include <drm/drm_print.h>
20 23
@@ -57,6 +60,13 @@
57 */ 60 */
58#define MALIDP_ALPHA_LUT 0xffaa5500 61#define MALIDP_ALPHA_LUT 0xffaa5500
59 62
63/* page sizes the MMU prefetcher can support */
64#define MALIDP_MMU_PREFETCH_PARTIAL_PGSIZES (SZ_4K | SZ_64K)
65#define MALIDP_MMU_PREFETCH_FULL_PGSIZES (SZ_1M | SZ_2M)
66
67/* readahead for partial-frame prefetch */
68#define MALIDP_MMU_PREFETCH_READAHEAD 8
69
60static void malidp_de_plane_destroy(struct drm_plane *plane) 70static void malidp_de_plane_destroy(struct drm_plane *plane)
61{ 71{
62 struct malidp_plane *mp = to_malidp_plane(plane); 72 struct malidp_plane *mp = to_malidp_plane(plane);
@@ -101,6 +111,9 @@ drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
101 state->format = m_state->format; 111 state->format = m_state->format;
102 state->n_planes = m_state->n_planes; 112 state->n_planes = m_state->n_planes;
103 113
114 state->mmu_prefetch_mode = m_state->mmu_prefetch_mode;
115 state->mmu_prefetch_pgsize = m_state->mmu_prefetch_pgsize;
116
104 return &state->base; 117 return &state->base;
105} 118}
106 119
@@ -113,6 +126,12 @@ static void malidp_destroy_plane_state(struct drm_plane *plane,
113 kfree(m_state); 126 kfree(m_state);
114} 127}
115 128
129static const char * const prefetch_mode_names[] = {
130 [MALIDP_PREFETCH_MODE_NONE] = "MMU_PREFETCH_NONE",
131 [MALIDP_PREFETCH_MODE_PARTIAL] = "MMU_PREFETCH_PARTIAL",
132 [MALIDP_PREFETCH_MODE_FULL] = "MMU_PREFETCH_FULL",
133};
134
116static void malidp_plane_atomic_print_state(struct drm_printer *p, 135static void malidp_plane_atomic_print_state(struct drm_printer *p,
117 const struct drm_plane_state *state) 136 const struct drm_plane_state *state)
118{ 137{
@@ -121,6 +140,9 @@ static void malidp_plane_atomic_print_state(struct drm_printer *p,
121 drm_printf(p, "\trotmem_size=%u\n", ms->rotmem_size); 140 drm_printf(p, "\trotmem_size=%u\n", ms->rotmem_size);
122 drm_printf(p, "\tformat_id=%u\n", ms->format); 141 drm_printf(p, "\tformat_id=%u\n", ms->format);
123 drm_printf(p, "\tn_planes=%u\n", ms->n_planes); 142 drm_printf(p, "\tn_planes=%u\n", ms->n_planes);
143 drm_printf(p, "\tmmu_prefetch_mode=%s\n",
144 prefetch_mode_names[ms->mmu_prefetch_mode]);
145 drm_printf(p, "\tmmu_prefetch_pgsize=%d\n", ms->mmu_prefetch_pgsize);
124} 146}
125 147
126static const struct drm_plane_funcs malidp_de_plane_funcs = { 148static const struct drm_plane_funcs malidp_de_plane_funcs = {
@@ -174,6 +196,199 @@ static int malidp_se_check_scaling(struct malidp_plane *mp,
174 return 0; 196 return 0;
175} 197}
176 198
199static u32 malidp_get_pgsize_bitmap(struct malidp_plane *mp)
200{
201 u32 pgsize_bitmap = 0;
202
203 if (iommu_present(&platform_bus_type)) {
204 struct iommu_domain *mmu_dom =
205 iommu_get_domain_for_dev(mp->base.dev->dev);
206
207 if (mmu_dom)
208 pgsize_bitmap = mmu_dom->pgsize_bitmap;
209 }
210
211 return pgsize_bitmap;
212}
213
214/*
215 * Check if the framebuffer is entirely made up of pages at least pgsize in
216 * size. Only a heuristic: assumes that each scatterlist entry has been aligned
217 * to the largest page size smaller than its length and that the MMU maps to
218 * the largest page size possible.
219 */
220static bool malidp_check_pages_threshold(struct malidp_plane_state *ms,
221 u32 pgsize)
222{
223 int i;
224
225 for (i = 0; i < ms->n_planes; i++) {
226 struct drm_gem_object *obj;
227 struct drm_gem_cma_object *cma_obj;
228 struct sg_table *sgt;
229 struct scatterlist *sgl;
230
231 obj = drm_gem_fb_get_obj(ms->base.fb, i);
232 cma_obj = to_drm_gem_cma_obj(obj);
233
234 if (cma_obj->sgt)
235 sgt = cma_obj->sgt;
236 else
237 sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
238
239 if (!sgt)
240 return false;
241
242 sgl = sgt->sgl;
243
244 while (sgl) {
245 if (sgl->length < pgsize) {
246 if (!cma_obj->sgt)
247 kfree(sgt);
248 return false;
249 }
250
251 sgl = sg_next(sgl);
252 }
253 if (!cma_obj->sgt)
254 kfree(sgt);
255 }
256
257 return true;
258}
259
260/*
261 * Check if it is possible to enable partial-frame MMU prefetch given the
262 * current format, AFBC state and rotation.
263 */
264static bool malidp_partial_prefetch_supported(u32 format, u64 modifier,
265 unsigned int rotation)
266{
267 bool afbc, sparse;
268
269 /* rotation and horizontal flip not supported for partial prefetch */
270 if (rotation & (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
271 DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X))
272 return false;
273
274 afbc = modifier & DRM_FORMAT_MOD_ARM_AFBC(0);
275 sparse = modifier & AFBC_FORMAT_MOD_SPARSE;
276
277 switch (format) {
278 case DRM_FORMAT_ARGB2101010:
279 case DRM_FORMAT_RGBA1010102:
280 case DRM_FORMAT_BGRA1010102:
281 case DRM_FORMAT_ARGB8888:
282 case DRM_FORMAT_RGBA8888:
283 case DRM_FORMAT_BGRA8888:
284 case DRM_FORMAT_XRGB8888:
285 case DRM_FORMAT_XBGR8888:
286 case DRM_FORMAT_RGBX8888:
287 case DRM_FORMAT_BGRX8888:
288 case DRM_FORMAT_RGB888:
289 case DRM_FORMAT_RGBA5551:
290 case DRM_FORMAT_RGB565:
291 /* always supported */
292 return true;
293
294 case DRM_FORMAT_ABGR2101010:
295 case DRM_FORMAT_ABGR8888:
296 case DRM_FORMAT_ABGR1555:
297 case DRM_FORMAT_BGR565:
298 /* supported, but if AFBC then must be sparse mode */
299 return (!afbc) || (afbc && sparse);
300
301 case DRM_FORMAT_BGR888:
302 /* supported, but not for AFBC */
303 return !afbc;
304
305 case DRM_FORMAT_YUYV:
306 case DRM_FORMAT_UYVY:
307 case DRM_FORMAT_NV12:
308 case DRM_FORMAT_YUV420:
309 /* not supported */
310 return false;
311
312 default:
313 return false;
314 }
315}
316
317/*
318 * Select the preferred MMU prefetch mode. Full-frame prefetch is preferred as
319 * long as the framebuffer is all large pages. Otherwise partial-frame prefetch
320 * is selected as long as it is supported for the current format. The selected
321 * page size for prefetch is returned in pgsize_bitmap.
322 */
323static enum mmu_prefetch_mode malidp_mmu_prefetch_select_mode
324 (struct malidp_plane_state *ms, u32 *pgsize_bitmap)
325{
326 u32 pgsizes;
327
328 /* get the full-frame prefetch page size(s) supported by the MMU */
329 pgsizes = *pgsize_bitmap & MALIDP_MMU_PREFETCH_FULL_PGSIZES;
330
331 while (pgsizes) {
332 u32 largest_pgsize = 1 << __fls(pgsizes);
333
334 if (malidp_check_pages_threshold(ms, largest_pgsize)) {
335 *pgsize_bitmap = largest_pgsize;
336 return MALIDP_PREFETCH_MODE_FULL;
337 }
338
339 pgsizes -= largest_pgsize;
340 }
341
342 /* get the partial-frame prefetch page size(s) supported by the MMU */
343 pgsizes = *pgsize_bitmap & MALIDP_MMU_PREFETCH_PARTIAL_PGSIZES;
344
345 if (malidp_partial_prefetch_supported(ms->base.fb->format->format,
346 ms->base.fb->modifier,
347 ms->base.rotation)) {
348 /* partial prefetch using the smallest page size */
349 *pgsize_bitmap = 1 << __ffs(pgsizes);
350 return MALIDP_PREFETCH_MODE_PARTIAL;
351 }
352 *pgsize_bitmap = 0;
353 return MALIDP_PREFETCH_MODE_NONE;
354}
355
356static u32 malidp_calc_mmu_control_value(enum mmu_prefetch_mode mode,
357 u8 readahead, u8 n_planes, u32 pgsize)
358{
359 u32 mmu_ctrl = 0;
360
361 if (mode != MALIDP_PREFETCH_MODE_NONE) {
362 mmu_ctrl |= MALIDP_MMU_CTRL_EN;
363
364 if (mode == MALIDP_PREFETCH_MODE_PARTIAL) {
365 mmu_ctrl |= MALIDP_MMU_CTRL_MODE;
366 mmu_ctrl |= MALIDP_MMU_CTRL_PP_NUM_REQ(readahead);
367 }
368
369 if (pgsize == SZ_64K || pgsize == SZ_2M) {
370 int i;
371
372 for (i = 0; i < n_planes; i++)
373 mmu_ctrl |= MALIDP_MMU_CTRL_PX_PS(i);
374 }
375 }
376
377 return mmu_ctrl;
378}
379
380static void malidp_de_prefetch_settings(struct malidp_plane *mp,
381 struct malidp_plane_state *ms)
382{
383 if (!mp->layer->mmu_ctrl_offset)
384 return;
385
386 /* get the page sizes supported by the MMU */
387 ms->mmu_prefetch_pgsize = malidp_get_pgsize_bitmap(mp);
388 ms->mmu_prefetch_mode =
389 malidp_mmu_prefetch_select_mode(ms, &ms->mmu_prefetch_pgsize);
390}
391
177static int malidp_de_plane_check(struct drm_plane *plane, 392static int malidp_de_plane_check(struct drm_plane *plane,
178 struct drm_plane_state *state) 393 struct drm_plane_state *state)
179{ 394{
@@ -250,6 +465,8 @@ static int malidp_de_plane_check(struct drm_plane *plane,
250 fb->format->has_alpha) 465 fb->format->has_alpha)
251 return -EINVAL; 466 return -EINVAL;
252 467
468 malidp_de_prefetch_settings(mp, ms);
469
253 return 0; 470 return 0;
254} 471}
255 472
@@ -326,6 +543,24 @@ static void malidp_de_set_color_encoding(struct malidp_plane *plane,
326 } 543 }
327} 544}
328 545
546static void malidp_de_set_mmu_control(struct malidp_plane *mp,
547 struct malidp_plane_state *ms)
548{
549 u32 mmu_ctrl;
550
551 /* check hardware supports MMU prefetch */
552 if (!mp->layer->mmu_ctrl_offset)
553 return;
554
555 mmu_ctrl = malidp_calc_mmu_control_value(ms->mmu_prefetch_mode,
556 MALIDP_MMU_PREFETCH_READAHEAD,
557 ms->n_planes,
558 ms->mmu_prefetch_pgsize);
559
560 malidp_hw_write(mp->hwdev, mmu_ctrl,
561 mp->layer->base + mp->layer->mmu_ctrl_offset);
562}
563
329static void malidp_de_plane_update(struct drm_plane *plane, 564static void malidp_de_plane_update(struct drm_plane *plane,
330 struct drm_plane_state *old_state) 565 struct drm_plane_state *old_state)
331{ 566{
@@ -358,6 +593,9 @@ static void malidp_de_plane_update(struct drm_plane *plane,
358 malidp_hw_write(mp->hwdev, lower_32_bits(fb_addr), ptr); 593 malidp_hw_write(mp->hwdev, lower_32_bits(fb_addr), ptr);
359 malidp_hw_write(mp->hwdev, upper_32_bits(fb_addr), ptr + 4); 594 malidp_hw_write(mp->hwdev, upper_32_bits(fb_addr), ptr + 4);
360 } 595 }
596
597 malidp_de_set_mmu_control(mp, ms);
598
361 malidp_de_set_plane_pitches(mp, ms->n_planes, 599 malidp_de_set_plane_pitches(mp, ms->n_planes,
362 state->fb->pitches); 600 state->fb->pitches);
363 601
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
index 6ffe849774f2..7ce3e141464d 100644
--- a/drivers/gpu/drm/arm/malidp_regs.h
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -247,6 +247,17 @@
247#define MALIDP550_CONFIG_VALID 0x0c014 247#define MALIDP550_CONFIG_VALID 0x0c014
248#define MALIDP550_CONFIG_ID 0x0ffd4 248#define MALIDP550_CONFIG_ID 0x0ffd4
249 249
250/* register offsets specific to DP650 */
251#define MALIDP650_DE_LV_MMU_CTRL 0x000D0
252#define MALIDP650_DE_LG_MMU_CTRL 0x00048
253#define MALIDP650_DE_LS_MMU_CTRL 0x00078
254
255/* bit masks to set the MMU control register */
256#define MALIDP_MMU_CTRL_EN (1 << 0)
257#define MALIDP_MMU_CTRL_MODE (1 << 4)
258#define MALIDP_MMU_CTRL_PX_PS(x) (1 << (8 + (x)))
259#define MALIDP_MMU_CTRL_PP_NUM_REQ(x) (((x) & 0x7f) << 12)
260
250/* 261/*
251 * Starting with DP550 the register map blocks has been standardised to the 262 * Starting with DP550 the register map blocks has been standardised to the
252 * following layout: 263 * following layout: