Skip to content

Commit ba9883e

Browse files
drm: rp1: rp1-dpi: Add "rgb_order" property (to match VC4 DPI)
As on VC4, the OF property overrides the order implied by media bus format. Only 4 of the 6 possible orders are supported. New add-on hardware designs should not rely on this "legacy" feature. Signed-off-by: Nick Hollinghurst <[email protected]>
1 parent 81d1196 commit ba9883e

File tree

3 files changed

+143
-71
lines changed

3 files changed

+143
-71
lines changed

drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c

+15
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
292292
struct device *dev = &pdev->dev;
293293
struct rp1_dpi *dpi;
294294
struct drm_bridge *bridge = NULL;
295+
const char *rgb_order = NULL;
295296
struct drm_panel *panel;
296297
int i, j, ret;
297298

@@ -353,6 +354,20 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
353354
if (ret)
354355
goto done_err;
355356

357+
dpi->rgb_order_override = RP1DPI_ORDER_UNCHANGED;
358+
if (!of_property_read_string(dev->of_node, "rgb_order", &rgb_order)) {
359+
if (!strcmp(rgb_order, "rgb"))
360+
dpi->rgb_order_override = RP1DPI_ORDER_RGB;
361+
else if (!strcmp(rgb_order, "bgr"))
362+
dpi->rgb_order_override = RP1DPI_ORDER_BGR;
363+
else if (!strcmp(rgb_order, "grb"))
364+
dpi->rgb_order_override = RP1DPI_ORDER_GRB;
365+
else if (!strcmp(rgb_order, "brg"))
366+
dpi->rgb_order_override = RP1DPI_ORDER_BRG;
367+
else
368+
DRM_ERROR("Invalid dpi order %s - ignored\n", rgb_order);
369+
}
370+
356371
/* Check if PIO can snoop on or override DPI's GPIO1 */
357372
dpi->gpio1_used = false;
358373
for (i = 0; !dpi->gpio1_used; i++) {

drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@
2525
#define RP1DPI_CLK_PLLCORE 2
2626
#define RP1DPI_NUM_CLOCKS 3
2727

28+
/* Codes (in LE byte order) used for S/W permutation */
29+
#define RP1DPI_ORDER_UNCHANGED 0
30+
#define RP1DPI_ORDER_RGB 0x020100
31+
#define RP1DPI_ORDER_BGR 0x000102
32+
#define RP1DPI_ORDER_GRB 0x020001
33+
#define RP1DPI_ORDER_BRG 0x010002
34+
2835
/* ---------------------------------------------------------------------- */
2936

3037
struct rp1_dpi {
@@ -45,6 +52,7 @@ struct rp1_dpi {
4552
u32 bus_fmt;
4653
bool de_inv, clk_inv;
4754
bool dpi_running, pipe_enabled;
55+
unsigned int rgb_order_override;
4856
struct completion finished;
4957

5058
/* Experimental stuff for interlace follows */

drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c

+120-71
Original file line numberDiff line numberDiff line change
@@ -223,91 +223,120 @@ int rp1dpi_hw_busy(struct rp1_dpi *dpi)
223223
return (rp1dpi_hw_read(dpi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0;
224224
}
225225

226-
/* Table of supported input (in-memory/DMA) pixel formats. */
226+
/*
227+
* Table of supported input (in-memory/DMA) pixel formats.
228+
*
229+
* RP1 DPI describes RGB components in terms of their MS bit position, a 10-bit
230+
* left-aligned bit-mask, and an optional right-shift-and-OR used for scaling.
231+
* To make it easier to permute R, G and B components, we re-pack these fields
232+
* into 32-bit code-words, which don't themselves correspond to any register.
233+
*/
234+
235+
#define RGB_CODE(scale, shift, mask) (((scale) << 24) | ((shift) << 16) | (mask))
236+
#define RGB_SCALE(c) ((c) >> 24)
237+
#define RGB_SHIFT(c) (((c) >> 16) & 31)
238+
#define RGB_MASK(c) ((c) & 0x3ff)
239+
227240
struct rp1dpi_ipixfmt {
228-
u32 format; /* DRM format code */
229-
u32 mask; /* RGB masks (10 bits each, left justified) */
230-
u32 shift; /* RGB MSB positions in the memory word */
231-
u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */
241+
u32 format; /* DRM format code */
242+
u32 rgb_code[3]; /* (width&7), MS bit position, 10-bit mask */
243+
u32 bpp; /* Bytes per pixel minus one */
232244
};
233245

234-
#define IMASK_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_IMASK_R_MASK, r) | \
235-
FIELD_PREP_CONST(DPI_DMA_IMASK_G_MASK, g) | \
236-
FIELD_PREP_CONST(DPI_DMA_IMASK_B_MASK, b))
237-
#define OMASK_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_OMASK_R_MASK, r) | \
238-
FIELD_PREP_CONST(DPI_DMA_OMASK_G_MASK, g) | \
239-
FIELD_PREP_CONST(DPI_DMA_OMASK_B_MASK, b))
240-
#define ISHIFT_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_SHIFT_IR_MASK, r) | \
241-
FIELD_PREP_CONST(DPI_DMA_SHIFT_IG_MASK, g) | \
242-
FIELD_PREP_CONST(DPI_DMA_SHIFT_IB_MASK, b))
243-
#define OSHIFT_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_SHIFT_OR_MASK, r) | \
244-
FIELD_PREP_CONST(DPI_DMA_SHIFT_OG_MASK, g) | \
245-
FIELD_PREP_CONST(DPI_DMA_SHIFT_OB_MASK, b))
246-
247246
static const struct rp1dpi_ipixfmt my_formats[] = {
248247
{
249-
.format = DRM_FORMAT_XRGB8888,
250-
.mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
251-
.shift = ISHIFT_RGB(23, 15, 7),
252-
.rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
248+
.format = DRM_FORMAT_XRGB8888,
249+
.rgb_code = {
250+
RGB_CODE(0, 23, 0x3fc),
251+
RGB_CODE(0, 15, 0x3fc),
252+
RGB_CODE(0, 7, 0x3fc),
253+
},
254+
.bpp = 3,
253255
},
254256
{
255-
.format = DRM_FORMAT_XBGR8888,
256-
.mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
257-
.shift = ISHIFT_RGB(7, 15, 23),
258-
.rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
257+
.format = DRM_FORMAT_XBGR8888,
258+
.rgb_code = {
259+
RGB_CODE(0, 7, 0x3fc),
260+
RGB_CODE(0, 15, 0x3fc),
261+
RGB_CODE(0, 23, 0x3fc),
262+
},
263+
.bpp = 3,
259264
},
260265
{
261-
.format = DRM_FORMAT_ARGB8888,
262-
.mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
263-
.shift = ISHIFT_RGB(23, 15, 7),
264-
.rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
266+
.format = DRM_FORMAT_ARGB8888,
267+
.rgb_code = {
268+
RGB_CODE(0, 23, 0x3fc),
269+
RGB_CODE(0, 15, 0x3fc),
270+
RGB_CODE(0, 7, 0x3fc),
271+
},
272+
.bpp = 3,
265273
},
266274
{
267-
.format = DRM_FORMAT_ABGR8888,
268-
.mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
269-
.shift = ISHIFT_RGB(7, 15, 23),
270-
.rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
275+
.format = DRM_FORMAT_ABGR8888,
276+
.rgb_code = {
277+
RGB_CODE(0, 7, 0x3fc),
278+
RGB_CODE(0, 15, 0x3fc),
279+
RGB_CODE(0, 23, 0x3fc),
280+
},
281+
.bpp = 3,
271282
},
272283
{
273-
.format = DRM_FORMAT_RGB888,
274-
.mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
275-
.shift = ISHIFT_RGB(23, 15, 7),
276-
.rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 2),
284+
.format = DRM_FORMAT_RGB888,
285+
.rgb_code = {
286+
RGB_CODE(0, 23, 0x3fc),
287+
RGB_CODE(0, 15, 0x3fc),
288+
RGB_CODE(0, 7, 0x3fc),
289+
},
290+
.bpp = 2,
277291
},
278292
{
279-
.format = DRM_FORMAT_BGR888,
280-
.mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
281-
.shift = ISHIFT_RGB(7, 15, 23),
282-
.rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 2),
293+
.format = DRM_FORMAT_BGR888,
294+
.rgb_code = {
295+
RGB_CODE(0, 7, 0x3fc),
296+
RGB_CODE(0, 15, 0x3fc),
297+
RGB_CODE(0, 23, 0x3fc),
298+
},
299+
.bpp = 2,
283300
},
284301
{
285-
.format = DRM_FORMAT_RGB565,
286-
.mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0),
287-
.shift = ISHIFT_RGB(15, 10, 4),
288-
.rgbsz = (FIELD_PREP_CONST(DPI_DMA_RGBSZ_R_MASK, 5) |
289-
FIELD_PREP_CONST(DPI_DMA_RGBSZ_G_MASK, 6) |
290-
FIELD_PREP_CONST(DPI_DMA_RGBSZ_B_MASK, 5) |
291-
FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 1)),
302+
.format = DRM_FORMAT_RGB565,
303+
.rgb_code = {
304+
RGB_CODE(5, 15, 0x3e0),
305+
RGB_CODE(6, 10, 0x3f0),
306+
RGB_CODE(5, 4, 0x3e0),
307+
},
308+
.bpp = 1,
292309
},
293-
{
294-
.format = DRM_FORMAT_BGR565,
295-
.mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0),
296-
.shift = ISHIFT_RGB(4, 10, 15),
297-
.rgbsz = (FIELD_PREP_CONST(DPI_DMA_RGBSZ_R_MASK, 5) |
298-
FIELD_PREP_CONST(DPI_DMA_RGBSZ_G_MASK, 6) |
299-
FIELD_PREP_CONST(DPI_DMA_RGBSZ_B_MASK, 5) |
300-
FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 1)),
301-
}
302310
};
303311

312+
#define IMASK_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_IMASK_R_MASK, r) | \
313+
FIELD_PREP_CONST(DPI_DMA_IMASK_G_MASK, g) | \
314+
FIELD_PREP_CONST(DPI_DMA_IMASK_B_MASK, b))
315+
#define OMASK_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_OMASK_R_MASK, r) | \
316+
FIELD_PREP_CONST(DPI_DMA_OMASK_G_MASK, g) | \
317+
FIELD_PREP_CONST(DPI_DMA_OMASK_B_MASK, b))
318+
#define ISHIFT_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_SHIFT_IR_MASK, r) | \
319+
FIELD_PREP_CONST(DPI_DMA_SHIFT_IG_MASK, g) | \
320+
FIELD_PREP_CONST(DPI_DMA_SHIFT_IB_MASK, b))
321+
#define OSHIFT_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_SHIFT_OR_MASK, r) | \
322+
FIELD_PREP_CONST(DPI_DMA_SHIFT_OG_MASK, g) | \
323+
FIELD_PREP_CONST(DPI_DMA_SHIFT_OB_MASK, b))
324+
325+
/*
326+
* Function to update *shift with output positions, and return output RGB masks.
327+
* By the time we get here, RGB order has been normalized to RGB (R most significant).
328+
* Note that an internal bus is 30 bits wide: bits [21:20], [11:10], [1:0] are dropped.
329+
* This makes the packed RGB5656 and RGB666 formats problematic, as colour components
330+
* need to straddle the gaps; we mitigate this by hijacking input masks and scaling.
331+
*/
304332
static u32 set_output_format(u32 bus_format, u32 *shift, u32 *imask, u32 *rgbsz)
305333
{
306334
switch (bus_format) {
307335
case MEDIA_BUS_FMT_RGB565_1X16:
308336
if (*shift == ISHIFT_RGB(15, 10, 4)) {
309337
/* When framebuffer is RGB565, we can output RGB565 */
310338
*shift = ISHIFT_RGB(15, 7, 0) | OSHIFT_RGB(19, 9, 0);
339+
*imask = IMASK_RGB(0x3fc, 0x3fc, 0);
311340
*rgbsz &= DPI_DMA_RGBSZ_BPP_MASK;
312341
return OMASK_RGB(0x3fc, 0x3fc, 0);
313342
}
@@ -322,7 +351,7 @@ static u32 set_output_format(u32 bus_format, u32 *shift, u32 *imask, u32 *rgbsz)
322351
case MEDIA_BUS_FMT_BGR666_1X18:
323352
/* due to a HW limitation, bit-depth is effectively RGB444 */
324353
*shift |= OSHIFT_RGB(23, 15, 7);
325-
*imask &= IMASK_RGB(0x3c0, 0x3c0, 0x3c0);
354+
*imask = IMASK_RGB(0x3c0, 0x3c0, 0x3c0);
326355
*rgbsz = BITS(DPI_DMA_RGBSZ_R, 2) | (*rgbsz & DPI_DMA_RGBSZ_BPP_MASK);
327356
return OMASK_RGB(0x330, 0x3c0, 0x3c0);
328357

@@ -359,7 +388,8 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi,
359388
struct drm_display_mode const *mode)
360389
{
361390
u32 shift, imask, omask, rgbsz, vctrl;
362-
int i;
391+
u32 rgb_code[3];
392+
int order, i;
363393

364394
drm_info(&dpi->drm,
365395
"in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d%s %dkHz %cH%cV%cD%cC",
@@ -373,26 +403,45 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi,
373403
de_inv ? '-' : '+',
374404
dpi->clk_inv ? '-' : '+');
375405

376-
/*
377-
* Configure all DPI/DMA block registers, except base address.
378-
* DMA will not actually start until a FB base address is specified
379-
* using rp1dpi_hw_update().
380-
*/
406+
/* Look up the input (in-memory) pixel format */
381407
for (i = 0; i < ARRAY_SIZE(my_formats); ++i) {
382408
if (my_formats[i].format == in_format)
383409
break;
384410
}
385411
if (i >= ARRAY_SIZE(my_formats)) {
386412
pr_err("%s: bad input format\n", __func__);
387-
i = 4;
413+
i = ARRAY_SIZE(my_formats) - 1;
388414
}
389-
if (BUS_FMT_IS_BGR(bus_format))
390-
i ^= 1;
391-
shift = my_formats[i].shift;
392-
imask = my_formats[i].mask;
393-
rgbsz = my_formats[i].rgbsz;
415+
416+
/*
417+
* Although these RGB orderings refer to the output (DPI bus) format,
418+
* here we permute the *input* components. After this point, "Red"
419+
* will be most significant (highest numbered GPIOs), regardless
420+
* of rgb_order or bus_format. This simplifies later workarounds.
421+
*/
422+
order = dpi->rgb_order_override;
423+
if (order == RP1DPI_ORDER_UNCHANGED)
424+
order = BUS_FMT_IS_BGR(bus_format) ? RP1DPI_ORDER_BGR : RP1DPI_ORDER_RGB;
425+
rgb_code[0] = my_formats[i].rgb_code[order & 3];
426+
rgb_code[1] = my_formats[i].rgb_code[(order >> 8) & 3];
427+
rgb_code[2] = my_formats[i].rgb_code[(order >> 16) & 3];
428+
rgbsz = FIELD_PREP(DPI_DMA_RGBSZ_BPP_MASK, my_formats[i].bpp) |
429+
FIELD_PREP(DPI_DMA_RGBSZ_R_MASK, RGB_SCALE(rgb_code[0])) |
430+
FIELD_PREP(DPI_DMA_RGBSZ_G_MASK, RGB_SCALE(rgb_code[1])) |
431+
FIELD_PREP(DPI_DMA_RGBSZ_B_MASK, RGB_SCALE(rgb_code[2]));
432+
shift = FIELD_PREP(DPI_DMA_SHIFT_IR_MASK, RGB_SHIFT(rgb_code[0])) |
433+
FIELD_PREP(DPI_DMA_SHIFT_IG_MASK, RGB_SHIFT(rgb_code[1])) |
434+
FIELD_PREP(DPI_DMA_SHIFT_IB_MASK, RGB_SHIFT(rgb_code[2]));
435+
imask = FIELD_PREP(DPI_DMA_IMASK_R_MASK, RGB_MASK(rgb_code[0])) |
436+
FIELD_PREP(DPI_DMA_IMASK_G_MASK, RGB_MASK(rgb_code[1])) |
437+
FIELD_PREP(DPI_DMA_IMASK_B_MASK, RGB_MASK(rgb_code[2]));
394438
omask = set_output_format(bus_format, &shift, &imask, &rgbsz);
395439

440+
/*
441+
* Configure all DPI/DMA block registers, except base address.
442+
* DMA will not actually start until a FB base address is specified
443+
* using rp1dpi_hw_update().
444+
*/
396445
rp1dpi_hw_write(dpi, DPI_DMA_IMASK, imask);
397446
rp1dpi_hw_write(dpi, DPI_DMA_OMASK, omask);
398447
rp1dpi_hw_write(dpi, DPI_DMA_SHIFT, shift);

0 commit comments

Comments
 (0)