openwrt-cghmn-mt300n/target/linux/bcm27xx/patches-6.6/950-1519-drm-rp1-rp1-dpi-Add-rgb_order-property-to-match-VC4-.patch
Álvaro Fernández Rojas 251f76c1c6 bcm27xx: pull 6.6 patches from RPi repo
Adds latest 6.6 patches from the Raspberry Pi repository.

These patches were generated from:
https://github.com/raspberrypi/linux/commits/rpi-6.6.y/
With the following command:
git format-patch -N v6.6.83..HEAD
(HEAD -> 08d4e8f52256bd422d8a1f876411603f627d0a82)

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2025-03-16 08:04:48 +01:00

326 lines
11 KiB
Diff

From ba9883e3b667e4f1fbeacc4346f6e9179a3a5479 Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Mon, 20 Jan 2025 11:20:48 +0000
Subject: [PATCH] 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 <nick.hollinghurst@raspberrypi.com>
---
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 15 ++
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h | 8 +
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 191 ++++++++++++++---------
3 files changed, 143 insertions(+), 71 deletions(-)
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
@@ -292,6 +292,7 @@ static int rp1dpi_platform_probe(struct
struct device *dev = &pdev->dev;
struct rp1_dpi *dpi;
struct drm_bridge *bridge = NULL;
+ const char *rgb_order = NULL;
struct drm_panel *panel;
int i, j, ret;
@@ -353,6 +354,20 @@ static int rp1dpi_platform_probe(struct
if (ret)
goto done_err;
+ dpi->rgb_order_override = RP1DPI_ORDER_UNCHANGED;
+ if (!of_property_read_string(dev->of_node, "rgb_order", &rgb_order)) {
+ if (!strcmp(rgb_order, "rgb"))
+ dpi->rgb_order_override = RP1DPI_ORDER_RGB;
+ else if (!strcmp(rgb_order, "bgr"))
+ dpi->rgb_order_override = RP1DPI_ORDER_BGR;
+ else if (!strcmp(rgb_order, "grb"))
+ dpi->rgb_order_override = RP1DPI_ORDER_GRB;
+ else if (!strcmp(rgb_order, "brg"))
+ dpi->rgb_order_override = RP1DPI_ORDER_BRG;
+ else
+ DRM_ERROR("Invalid dpi order %s - ignored\n", rgb_order);
+ }
+
/* Check if PIO can snoop on or override DPI's GPIO1 */
dpi->gpio1_used = false;
for (i = 0; !dpi->gpio1_used; i++) {
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h
@@ -25,6 +25,13 @@
#define RP1DPI_CLK_PLLCORE 2
#define RP1DPI_NUM_CLOCKS 3
+/* Codes (in LE byte order) used for S/W permutation */
+#define RP1DPI_ORDER_UNCHANGED 0
+#define RP1DPI_ORDER_RGB 0x020100
+#define RP1DPI_ORDER_BGR 0x000102
+#define RP1DPI_ORDER_GRB 0x020001
+#define RP1DPI_ORDER_BRG 0x010002
+
/* ---------------------------------------------------------------------- */
struct rp1_dpi {
@@ -45,6 +52,7 @@ struct rp1_dpi {
u32 bus_fmt;
bool de_inv, clk_inv;
bool dpi_running, pipe_enabled;
+ unsigned int rgb_order_override;
struct completion finished;
/* Experimental stuff for interlace follows */
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c
@@ -223,12 +223,90 @@ int rp1dpi_hw_busy(struct rp1_dpi *dpi)
return (rp1dpi_hw_read(dpi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0;
}
-/* Table of supported input (in-memory/DMA) pixel formats. */
+/*
+ * Table of supported input (in-memory/DMA) pixel formats.
+ *
+ * RP1 DPI describes RGB components in terms of their MS bit position, a 10-bit
+ * left-aligned bit-mask, and an optional right-shift-and-OR used for scaling.
+ * To make it easier to permute R, G and B components, we re-pack these fields
+ * into 32-bit code-words, which don't themselves correspond to any register.
+ */
+
+#define RGB_CODE(scale, shift, mask) (((scale) << 24) | ((shift) << 16) | (mask))
+#define RGB_SCALE(c) ((c) >> 24)
+#define RGB_SHIFT(c) (((c) >> 16) & 31)
+#define RGB_MASK(c) ((c) & 0x3ff)
+
struct rp1dpi_ipixfmt {
- u32 format; /* DRM format code */
- u32 mask; /* RGB masks (10 bits each, left justified) */
- u32 shift; /* RGB MSB positions in the memory word */
- u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */
+ u32 format; /* DRM format code */
+ u32 rgb_code[3]; /* (width&7), MS bit position, 10-bit mask */
+ u32 bpp; /* Bytes per pixel minus one */
+};
+
+static const struct rp1dpi_ipixfmt my_formats[] = {
+ {
+ .format = DRM_FORMAT_XRGB8888,
+ .rgb_code = {
+ RGB_CODE(0, 23, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 7, 0x3fc),
+ },
+ .bpp = 3,
+ },
+ {
+ .format = DRM_FORMAT_XBGR8888,
+ .rgb_code = {
+ RGB_CODE(0, 7, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 23, 0x3fc),
+ },
+ .bpp = 3,
+ },
+ {
+ .format = DRM_FORMAT_ARGB8888,
+ .rgb_code = {
+ RGB_CODE(0, 23, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 7, 0x3fc),
+ },
+ .bpp = 3,
+ },
+ {
+ .format = DRM_FORMAT_ABGR8888,
+ .rgb_code = {
+ RGB_CODE(0, 7, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 23, 0x3fc),
+ },
+ .bpp = 3,
+ },
+ {
+ .format = DRM_FORMAT_RGB888,
+ .rgb_code = {
+ RGB_CODE(0, 23, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 7, 0x3fc),
+ },
+ .bpp = 2,
+ },
+ {
+ .format = DRM_FORMAT_BGR888,
+ .rgb_code = {
+ RGB_CODE(0, 7, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 23, 0x3fc),
+ },
+ .bpp = 2,
+ },
+ {
+ .format = DRM_FORMAT_RGB565,
+ .rgb_code = {
+ RGB_CODE(5, 15, 0x3e0),
+ RGB_CODE(6, 10, 0x3f0),
+ RGB_CODE(5, 4, 0x3e0),
+ },
+ .bpp = 1,
+ },
};
#define IMASK_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_IMASK_R_MASK, r) | \
@@ -244,63 +322,13 @@ struct rp1dpi_ipixfmt {
FIELD_PREP_CONST(DPI_DMA_SHIFT_OG_MASK, g) | \
FIELD_PREP_CONST(DPI_DMA_SHIFT_OB_MASK, b))
-static const struct rp1dpi_ipixfmt my_formats[] = {
- {
- .format = DRM_FORMAT_XRGB8888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(23, 15, 7),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
- },
- {
- .format = DRM_FORMAT_XBGR8888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(7, 15, 23),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
- },
- {
- .format = DRM_FORMAT_ARGB8888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(23, 15, 7),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
- },
- {
- .format = DRM_FORMAT_ABGR8888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(7, 15, 23),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
- },
- {
- .format = DRM_FORMAT_RGB888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(23, 15, 7),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 2),
- },
- {
- .format = DRM_FORMAT_BGR888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(7, 15, 23),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 2),
- },
- {
- .format = DRM_FORMAT_RGB565,
- .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0),
- .shift = ISHIFT_RGB(15, 10, 4),
- .rgbsz = (FIELD_PREP_CONST(DPI_DMA_RGBSZ_R_MASK, 5) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_G_MASK, 6) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_B_MASK, 5) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 1)),
- },
- {
- .format = DRM_FORMAT_BGR565,
- .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0),
- .shift = ISHIFT_RGB(4, 10, 15),
- .rgbsz = (FIELD_PREP_CONST(DPI_DMA_RGBSZ_R_MASK, 5) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_G_MASK, 6) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_B_MASK, 5) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 1)),
- }
-};
-
+/*
+ * Function to update *shift with output positions, and return output RGB masks.
+ * By the time we get here, RGB order has been normalized to RGB (R most significant).
+ * Note that an internal bus is 30 bits wide: bits [21:20], [11:10], [1:0] are dropped.
+ * This makes the packed RGB5656 and RGB666 formats problematic, as colour components
+ * need to straddle the gaps; we mitigate this by hijacking input masks and scaling.
+ */
static u32 set_output_format(u32 bus_format, u32 *shift, u32 *imask, u32 *rgbsz)
{
switch (bus_format) {
@@ -308,6 +336,7 @@ static u32 set_output_format(u32 bus_for
if (*shift == ISHIFT_RGB(15, 10, 4)) {
/* When framebuffer is RGB565, we can output RGB565 */
*shift = ISHIFT_RGB(15, 7, 0) | OSHIFT_RGB(19, 9, 0);
+ *imask = IMASK_RGB(0x3fc, 0x3fc, 0);
*rgbsz &= DPI_DMA_RGBSZ_BPP_MASK;
return OMASK_RGB(0x3fc, 0x3fc, 0);
}
@@ -322,7 +351,7 @@ static u32 set_output_format(u32 bus_for
case MEDIA_BUS_FMT_BGR666_1X18:
/* due to a HW limitation, bit-depth is effectively RGB444 */
*shift |= OSHIFT_RGB(23, 15, 7);
- *imask &= IMASK_RGB(0x3c0, 0x3c0, 0x3c0);
+ *imask = IMASK_RGB(0x3c0, 0x3c0, 0x3c0);
*rgbsz = BITS(DPI_DMA_RGBSZ_R, 2) | (*rgbsz & DPI_DMA_RGBSZ_BPP_MASK);
return OMASK_RGB(0x330, 0x3c0, 0x3c0);
@@ -359,7 +388,8 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi
struct drm_display_mode const *mode)
{
u32 shift, imask, omask, rgbsz, vctrl;
- int i;
+ u32 rgb_code[3];
+ int order, i;
drm_info(&dpi->drm,
"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
de_inv ? '-' : '+',
dpi->clk_inv ? '-' : '+');
- /*
- * Configure all DPI/DMA block registers, except base address.
- * DMA will not actually start until a FB base address is specified
- * using rp1dpi_hw_update().
- */
+ /* Look up the input (in-memory) pixel format */
for (i = 0; i < ARRAY_SIZE(my_formats); ++i) {
if (my_formats[i].format == in_format)
break;
}
if (i >= ARRAY_SIZE(my_formats)) {
pr_err("%s: bad input format\n", __func__);
- i = 4;
+ i = ARRAY_SIZE(my_formats) - 1;
}
- if (BUS_FMT_IS_BGR(bus_format))
- i ^= 1;
- shift = my_formats[i].shift;
- imask = my_formats[i].mask;
- rgbsz = my_formats[i].rgbsz;
+
+ /*
+ * Although these RGB orderings refer to the output (DPI bus) format,
+ * here we permute the *input* components. After this point, "Red"
+ * will be most significant (highest numbered GPIOs), regardless
+ * of rgb_order or bus_format. This simplifies later workarounds.
+ */
+ order = dpi->rgb_order_override;
+ if (order == RP1DPI_ORDER_UNCHANGED)
+ order = BUS_FMT_IS_BGR(bus_format) ? RP1DPI_ORDER_BGR : RP1DPI_ORDER_RGB;
+ rgb_code[0] = my_formats[i].rgb_code[order & 3];
+ rgb_code[1] = my_formats[i].rgb_code[(order >> 8) & 3];
+ rgb_code[2] = my_formats[i].rgb_code[(order >> 16) & 3];
+ rgbsz = FIELD_PREP(DPI_DMA_RGBSZ_BPP_MASK, my_formats[i].bpp) |
+ FIELD_PREP(DPI_DMA_RGBSZ_R_MASK, RGB_SCALE(rgb_code[0])) |
+ FIELD_PREP(DPI_DMA_RGBSZ_G_MASK, RGB_SCALE(rgb_code[1])) |
+ FIELD_PREP(DPI_DMA_RGBSZ_B_MASK, RGB_SCALE(rgb_code[2]));
+ shift = FIELD_PREP(DPI_DMA_SHIFT_IR_MASK, RGB_SHIFT(rgb_code[0])) |
+ FIELD_PREP(DPI_DMA_SHIFT_IG_MASK, RGB_SHIFT(rgb_code[1])) |
+ FIELD_PREP(DPI_DMA_SHIFT_IB_MASK, RGB_SHIFT(rgb_code[2]));
+ imask = FIELD_PREP(DPI_DMA_IMASK_R_MASK, RGB_MASK(rgb_code[0])) |
+ FIELD_PREP(DPI_DMA_IMASK_G_MASK, RGB_MASK(rgb_code[1])) |
+ FIELD_PREP(DPI_DMA_IMASK_B_MASK, RGB_MASK(rgb_code[2]));
omask = set_output_format(bus_format, &shift, &imask, &rgbsz);
+ /*
+ * Configure all DPI/DMA block registers, except base address.
+ * DMA will not actually start until a FB base address is specified
+ * using rp1dpi_hw_update().
+ */
rp1dpi_hw_write(dpi, DPI_DMA_IMASK, imask);
rp1dpi_hw_write(dpi, DPI_DMA_OMASK, omask);
rp1dpi_hw_write(dpi, DPI_DMA_SHIFT, shift);