git: b9f3b63ab21e - main - vt: export RGB offsets with FBIO_GETRGBOFFS

From: Leandro Lupori <luporl_at_FreeBSD.org>
Date: Thu, 25 Nov 2021 19:40:11 UTC
The branch main has been updated by luporl:

URL: https://cgit.FreeBSD.org/src/commit/?id=b9f3b63ab21ed5d1288de1acff511eb733201139

commit b9f3b63ab21ed5d1288de1acff511eb733201139
Author:     Leandro Lupori <luporl@FreeBSD.org>
AuthorDate: 2021-11-25 18:54:11 +0000
Commit:     Leandro Lupori <luporl@FreeBSD.org>
CommitDate: 2021-11-25 19:39:25 +0000

    vt: export RGB offsets with FBIO_GETRGBOFFS
    
    Add a new ioctl to vt to make it possible to export RGB offsets
    set by vt drivers. This is needed to fix colors on X and Mesa
    on some machines, especially on modern PowerPC64 BE ones.
    
    With the appropriate changes in SCFB, to use this ioctl to find
    out the correct RGB offsets, this fixes wrong colors on Talos II
    and Blackbird, when used with their built-in video cards.
    
    Reviewed by:            alfredo
    Sponsored by:           Instituto de Pesquisas Eldorado (eldorado.org.br)
    Differential Revision:  https://reviews.freebsd.org/D29000
---
 sys/arm/broadcom/bcm2835/bcm2835_fbd.c  |  4 ++--
 sys/arm/freescale/imx/imx51_ipuv3_fbd.c | 14 +++++++-------
 sys/dev/vt/colors/vt_termcolors.c       | 18 +++++++++++++++++-
 sys/dev/vt/colors/vt_termcolors.h       |  6 ++++--
 sys/dev/vt/hw/efifb/efifb.c             |  2 +-
 sys/dev/vt/hw/fb/vt_early_fb.c          | 10 +++++-----
 sys/dev/vt/hw/fb/vt_fb.c                | 22 +++++++++++++++-------
 sys/dev/vt/hw/ofwfb/ofwfb.c             | 18 ++++++++----------
 sys/dev/vt/hw/vbefb/vbefb.c             |  2 +-
 sys/dev/vt/vt_core.c                    |  1 +
 sys/powerpc/ps3/ps3_syscons.c           |  2 +-
 sys/sys/fbio.h                          | 14 ++++++++++++++
 12 files changed, 76 insertions(+), 37 deletions(-)

diff --git a/sys/arm/broadcom/bcm2835/bcm2835_fbd.c b/sys/arm/broadcom/bcm2835/bcm2835_fbd.c
index 93849b3551d9..c148235e5c33 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_fbd.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_fbd.c
@@ -137,12 +137,12 @@ bcm_fb_setup_fbd(struct bcmsc_softc *sc)
 	if (sc->fbswap) {
 		switch (sc->info.fb_bpp) {
 		case 24:
-			vt_generate_cons_palette(sc->info.fb_cmap,
+			vt_config_cons_colors(&sc->info,
 			    COLOR_FORMAT_RGB, 0xff, 0, 0xff, 8, 0xff, 16);
 			sc->info.fb_cmsize = 16;
 			break;
 		case 32:
-			vt_generate_cons_palette(sc->info.fb_cmap,
+			vt_config_cons_colors(&sc->info,
 			    COLOR_FORMAT_RGB, 0xff, 16, 0xff, 8, 0xff, 0);
 			sc->info.fb_cmsize = 16;
 			break;
diff --git a/sys/arm/freescale/imx/imx51_ipuv3_fbd.c b/sys/arm/freescale/imx/imx51_ipuv3_fbd.c
index 644664fa8aa3..be1526228bf4 100644
--- a/sys/arm/freescale/imx/imx51_ipuv3_fbd.c
+++ b/sys/arm/freescale/imx/imx51_ipuv3_fbd.c
@@ -156,22 +156,22 @@ ipu3_fb_init(struct ipu3sc_softc *sc)
 
 /* Use own color map, because of different RGB offset. */
 static int
-ipu3_fb_init_cmap(uint32_t *cmap, int bytespp)
+ipu3_fb_init_colors(struct fb_info *info)
 {
 
-	switch (bytespp) {
+	switch (info->fb_depth) {
 	case 8:
-		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
+		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x7, 5, 0x7, 2, 0x3, 0));
 	case 15:
-		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
+		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x1f, 10, 0x1f, 5, 0x1f, 0));
 	case 16:
-		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
+		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x1f, 11, 0x3f, 5, 0x1f, 0));
 	case 24:
 	case 32: /* Ignore alpha. */
-		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
+		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0xff, 0, 0xff, 8, 0xff, 16));
 	default:
 		return (1);
@@ -303,7 +303,7 @@ ipu3_fb_attach(device_t dev)
 
 	sc->sc_info.fb_name = device_get_nameunit(dev);
 
-	ipu3_fb_init_cmap(sc->sc_info.fb_cmap, sc->sc_info.fb_depth);
+	ipu3_fb_init_colors(&sc->sc_info);
 	sc->sc_info.fb_cmsize = 16;
 
 	/* Ask newbus to attach framebuffer device to me. */
diff --git a/sys/dev/vt/colors/vt_termcolors.c b/sys/dev/vt/colors/vt_termcolors.c
index dff276a86100..fe340eeae518 100644
--- a/sys/dev/vt/colors/vt_termcolors.c
+++ b/sys/dev/vt/colors/vt_termcolors.c
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/libkern.h>
+#include <sys/fbio.h>
 
 #include <dev/vt/colors/vt_termcolors.h>
 
@@ -152,7 +153,7 @@ vt_palette_init(void)
 	}
 }
 
-int
+static int
 vt_generate_cons_palette(uint32_t *palette, int format, uint32_t rmax,
     int roffset, uint32_t gmax, int goffset, uint32_t bmax, int boffset)
 {
@@ -176,3 +177,18 @@ vt_generate_cons_palette(uint32_t *palette, int format, uint32_t rmax,
 
 	return (0);
 }
+
+int
+vt_config_cons_colors(struct fb_info *info, int format, uint32_t rmax,
+    int roffset, uint32_t gmax, int goffset, uint32_t bmax, int boffset)
+{
+	if (format == COLOR_FORMAT_RGB) {
+		info->fb_rgboffs.red = roffset;
+		info->fb_rgboffs.green = goffset;
+		info->fb_rgboffs.blue = boffset;
+	} else
+		memset(&info->fb_rgboffs, 0, sizeof(info->fb_rgboffs));
+
+	return (vt_generate_cons_palette(info->fb_cmap, format, rmax,
+	    roffset, gmax, goffset, bmax, boffset));
+}
diff --git a/sys/dev/vt/colors/vt_termcolors.h b/sys/dev/vt/colors/vt_termcolors.h
index 3fc99ee9743f..32521eebaf31 100644
--- a/sys/dev/vt/colors/vt_termcolors.h
+++ b/sys/dev/vt/colors/vt_termcolors.h
@@ -30,6 +30,8 @@
  * $FreeBSD$
  */
 
+struct fb_info;
+
 enum vt_color_format {
 	COLOR_FORMAT_BW = 0,
 	COLOR_FORMAT_GRAY,
@@ -57,6 +59,6 @@ static const int cons_to_vga_colors[NCOLORS] = {
 	8, 12, 10, 14,  9, 13, 11, 15
 };
 
-/* Helper to fill color map used by driver */
-int vt_generate_cons_palette(uint32_t *palette, int format, uint32_t rmax,
+/* Helper to fill color map and set RGB offsets used by driver */
+int vt_config_cons_colors(struct fb_info *info, int format, uint32_t rmax,
     int roffset, uint32_t gmax, int goffset, uint32_t bmax, int boffset);
diff --git a/sys/dev/vt/hw/efifb/efifb.c b/sys/dev/vt/hw/efifb/efifb.c
index e4deb1b9d9e5..de361ea45b97 100644
--- a/sys/dev/vt/hw/efifb/efifb.c
+++ b/sys/dev/vt/hw/efifb/efifb.c
@@ -131,7 +131,7 @@ vt_efifb_init(struct vt_device *vd)
 	roff = ffs(efifb->fb_mask_red) - 1;
 	goff = ffs(efifb->fb_mask_green) - 1;
 	boff = ffs(efifb->fb_mask_blue) - 1;
-	vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB,
+	vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 	    efifb->fb_mask_red >> roff, roff,
 	    efifb->fb_mask_green >> goff, goff,
 	    efifb->fb_mask_blue >> boff, boff);
diff --git a/sys/dev/vt/hw/fb/vt_early_fb.c b/sys/dev/vt/hw/fb/vt_early_fb.c
index 9d9635835202..e3dace2d5092 100644
--- a/sys/dev/vt/hw/fb/vt_early_fb.c
+++ b/sys/dev/vt/hw/fb/vt_early_fb.c
@@ -93,24 +93,24 @@ vt_efb_initialize(struct fb_info *info)
 	 */
 	switch (info->fb_depth) {
 	case 8:
-		vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB,
+		vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x7, 5, 0x7, 2, 0x3, 0);
 		break;
 	case 15:
-		vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB,
+		vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x1f, 10, 0x1f, 5, 0x1f, 0);
 		break;
 	case 16:
-		vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB,
+		vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x1f, 11, 0x3f, 5, 0x1f, 0);
 		break;
 	case 24:
 	case 32:
 #if BYTE_ORDER == BIG_ENDIAN
-		vt_generate_cons_palette(info->fb_cmap,
+		vt_config_cons_colors(info,
 		    COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
 #else
-		vt_generate_cons_palette(info->fb_cmap,
+		vt_config_cons_colors(info,
 		    COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
 #endif
 #ifdef	FDT
diff --git a/sys/dev/vt/hw/fb/vt_fb.c b/sys/dev/vt/hw/fb/vt_fb.c
index 2f6c4c3939d5..093bf35ac6ba 100644
--- a/sys/dev/vt/hw/fb/vt_fb.c
+++ b/sys/dev/vt/hw/fb/vt_fb.c
@@ -120,6 +120,14 @@ vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td)
 		vd->vd_driver->vd_blank(vd, TC_BLACK);
 		break;
 
+	case FBIO_GETRGBOFFS:	/* get RGB offsets */
+		if (info->fb_rgboffs.red == 0 && info->fb_rgboffs.green == 0 &&
+		    info->fb_rgboffs.blue == 0)
+			return (ENOTTY);
+		memcpy((struct fb_rgboffs *)data, &info->fb_rgboffs,
+		    sizeof(struct fb_rgboffs));
+		break;
+
 	default:
 		error = ENOIOCTL;
 		break;
@@ -432,22 +440,22 @@ vt_fb_postswitch(struct vt_device *vd)
 }
 
 static int
-vt_fb_init_cmap(uint32_t *cmap, int depth)
+vt_fb_init_colors(struct fb_info *info)
 {
 
-	switch (depth) {
+	switch (FBTYPE_GET_BPP(info)) {
 	case 8:
-		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
+		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x7, 5, 0x7, 2, 0x3, 0));
 	case 15:
-		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
+		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x1f, 10, 0x1f, 5, 0x1f, 0));
 	case 16:
-		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
+		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0x1f, 11, 0x3f, 5, 0x1f, 0));
 	case 24:
 	case 32: /* Ignore alpha. */
-		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
+		return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
 		    0xff, 16, 0xff, 8, 0xff, 0));
 	default:
 		return (1);
@@ -478,7 +486,7 @@ vt_fb_init(struct vt_device *vd)
 		info->fb_flags |= FB_FLAG_NOMMAP;
 
 	if (info->fb_cmsize <= 0) {
-		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
+		err = vt_fb_init_colors(info);
 		if (err)
 			return (CN_DEAD);
 		info->fb_cmsize = 16;
diff --git a/sys/dev/vt/hw/ofwfb/ofwfb.c b/sys/dev/vt/hw/ofwfb/ofwfb.c
index e388356450d6..4f24c471be1b 100644
--- a/sys/dev/vt/hw/ofwfb/ofwfb.c
+++ b/sys/dev/vt/hw/ofwfb/ofwfb.c
@@ -400,7 +400,7 @@ static void
 ofwfb_initialize(struct vt_device *vd)
 {
 	struct ofwfb_softc *sc = vd->vd_softc;
-	int i, err;
+	int i, err, r, g, b;
 	cell_t retval;
 
 	sc->fb.fb_cmsize = 16;
@@ -419,7 +419,7 @@ ofwfb_initialize(struct vt_device *vd)
 		 * No color format issues here, since we are passing the RGB
 		 * components separately to Open Firmware.
 		 */
-		vt_generate_cons_palette(sc->fb.fb_cmap, COLOR_FORMAT_RGB, 255,
+		vt_config_cons_colors(&sc->fb, COLOR_FORMAT_RGB, 255,
 		    16, 255, 8, 255, 0);
 
 		for (i = 0; i < 16; i++) {
@@ -457,19 +457,17 @@ ofwfb_initialize(struct vt_device *vd)
 		TUNABLE_INT_FETCH("hw.ofwfb.argb32_pixel", &sc->argb);
 		if (sc->endian_flip) {
 			if (sc->argb)
-				vt_generate_cons_palette(sc->fb.fb_cmap,
-				    COLOR_FORMAT_RGB, 255, 8, 255, 16, 255, 24);
+				r = 8, g = 16, b = 24;
 			else
-				vt_generate_cons_palette(sc->fb.fb_cmap,
-				    COLOR_FORMAT_RGB, 255, 24, 255, 16, 255, 8);
+				r = 24, g = 16, b = 8;
 		} else {
 			if (sc->argb)
-				vt_generate_cons_palette(sc->fb.fb_cmap,
-				    COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
+				r = 16, g = 8, b = 0;
 			else
-				vt_generate_cons_palette(sc->fb.fb_cmap,
-				    COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
+				r = 0, g = 8, b = 16;
 		}
+		vt_config_cons_colors(&sc->fb,
+		    COLOR_FORMAT_RGB, 255, r, 255, g, 255, b);
 		break;
 
 	default:
diff --git a/sys/dev/vt/hw/vbefb/vbefb.c b/sys/dev/vt/hw/vbefb/vbefb.c
index 2e8fe8330e56..569a40eb7d95 100644
--- a/sys/dev/vt/hw/vbefb/vbefb.c
+++ b/sys/dev/vt/hw/vbefb/vbefb.c
@@ -135,7 +135,7 @@ vt_vbefb_init(struct vt_device *vd)
 	roff = ffs(vbefb->fb_mask_red) - 1;
 	goff = ffs(vbefb->fb_mask_green) - 1;
 	boff = ffs(vbefb->fb_mask_blue) - 1;
-	vt_generate_cons_palette(info->fb_cmap, format,
+	vt_config_cons_colors(info, format,
 	    vbefb->fb_mask_red >> roff, roff,
 	    vbefb->fb_mask_green >> goff, goff,
 	    vbefb->fb_mask_blue >> boff, boff);
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index 0fab05ff4096..4ce3a48be288 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -2559,6 +2559,7 @@ skip_thunk:
 	case FBIO_GETDISPSTART:	/* get display start address */
 	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
 	case FBIO_BLANK:	/* blank display */
+	case FBIO_GETRGBOFFS:	/* get RGB offsets */
 		if (vd->vd_driver->vd_fb_ioctl)
 			return (vd->vd_driver->vd_fb_ioctl(vd, cmd, data, td));
 		break;
diff --git a/sys/powerpc/ps3/ps3_syscons.c b/sys/powerpc/ps3/ps3_syscons.c
index ed339f199746..30b6ff9bc8a2 100644
--- a/sys/powerpc/ps3/ps3_syscons.c
+++ b/sys/powerpc/ps3/ps3_syscons.c
@@ -228,7 +228,7 @@ ps3fb_init(struct vt_device *vd)
 	sc->fb_info.fb_cmsize = 16;
 
 	/* 32-bit VGA palette */
-	vt_generate_cons_palette(sc->fb_info.fb_cmap, COLOR_FORMAT_RGB,
+	vt_config_cons_colors(&sc->fb_info, COLOR_FORMAT_RGB,
 	    255, 16, 255, 8, 255, 0);
 
 	/* Set correct graphics context */
diff --git a/sys/sys/fbio.h b/sys/sys/fbio.h
index 3b47b11345cf..c44774a766a0 100644
--- a/sys/sys/fbio.h
+++ b/sys/sys/fbio.h
@@ -110,6 +110,15 @@ struct fbtype {
 #define	FBTYPE_GET_BPP(_fb)	((_fb)->fb_bpp)
 #define	FBTYPE_GET_BYTESPP(_fb)	((_fb)->fb_bpp / 8)
 
+/*
+ * RGB offsets as returned by FBIO_GETRGBOFFS.
+ */
+struct fb_rgboffs {
+	int		red;
+	int		green;
+	int		blue;
+};
+
 #ifdef	_KERNEL
 
 struct fb_info;
@@ -148,6 +157,8 @@ struct fb_info {
 	int		fb_stride;
 	int		fb_bpp;		/* bits per pixel */
 	uint32_t	fb_cmap[16];
+
+	struct fb_rgboffs fb_rgboffs;	/* RGB offsets */
 };
 
 int fbd_list(void);
@@ -619,4 +630,7 @@ typedef struct video_color_palette video_color_palette_t;
 
 #define FBIO_BLANK	_IOW('F', 115, int)
 
+/* get RGB offsets */
+#define	FBIO_GETRGBOFFS	_IOR('F', 116, struct fb_rgboffs)
+
 #endif /* !_SYS_FBIO_H_ */