From 5836cdc9865b480be90603e3e4f6b2d604952370 Mon Sep 17 00:00:00 2001
From: Jiakun Shuai <shuaijiakun1288@phytium.com.cn>
Date: Mon, 20 May 2024 15:29:26 +0800
Subject: [PATCH] phytium: xfree86: Fixed display error for ps23xx when using
 ast and pe2201 bmc card

bugzilla: https://gitee.com/openeuler/kernel/issues/I9NGXP

Used in conjunction with issue number I9NGXP to fix display error
for ps23xx when using ast and pe2201 bmc card.

Signed-off-by: Jiakun Shuai <shuaijiakun1288@phytium.com.cn>
---
 hw/xfree86/drivers/modesetting/driver.c | 158 +++++++++++++++++++++++-
 1 file changed, 157 insertions(+), 1 deletion(-)

diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index ef4a314..f9555e4 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -1143,6 +1143,162 @@ msUpdateIntersect(modesettingPtr ms, shadowBufPtr pBuf, BoxPtr box,
     return dirty;
 }
 
+static void align_memcpy(void *dest, void *source, size_t size)
+{
+    char *dst1, *dst2, *p, *src, *dst;
+
+    src = (char *)source;
+    dst = (char *)dest;
+
+    dst1 = (char *)(((unsigned long)dst + 0xf) & ~0xf);
+    dst2 = (char *)(((unsigned long)dst + size) & ~0xf);
+    p = dst;
+
+    while((p< dst1) && size){
+        *p++ = *src++;
+        size--;
+    };
+
+    memcpy(dst1, (char *)src, (size & (~0xf)));
+
+    src += (size & (~0xf));
+    size = (size & 0xf);
+
+    p = dst2;
+    while(size--){
+        *p++ = *src++;
+    };
+}
+
+#define AST_BMC_VENDOR_ID 0x1a03
+#define FT_BMC_VENDOR_ID 0x1db7
+#define FT_BMC_DEVICE_ID 0xdc3e
+#define DRM_AST_VRAM_TYPE_DEVICE 0x0
+#define DRM_IOCTL_AST_VRAM_TYPE_DEVICE DRM_IO(DRM_COMMAND_BASE + DRM_AST_VRAM_TYPE_DEVICE)
+#define DRM_PHYTIUM_VRAM_TYPE_DEVICE 0x0
+#define DRM_IOCTL_PHYTIUM_VRAM_TYPE_DEVICE DRM_IO(DRM_COMMAND_BASE + DRM_PHYTIUM_VRAM_TYPE_DEVICE)
+
+static Bool device_is_ast_bmc(struct pci_device *pci)
+{
+	if (pci->vendor_id == AST_BMC_VENDOR_ID) {
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static Bool device_is_ft_bmc(struct pci_device *pci)
+{
+	if (pci->vendor_id == FT_BMC_VENDOR_ID && pci->device_id == FT_BMC_DEVICE_ID) {
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+msshadowUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
+{
+    RegionPtr damage = DamageRegion(pBuf->pDamage);
+    PixmapPtr pShadow = pBuf->pPixmap;
+    int nbox = RegionNumRects(damage);
+    BoxPtr pbox = RegionRects(damage);
+    FbBits *shaBase, *shaLine, *sha;
+    FbStride shaStride;
+    int scrBase, scrLine, scr;
+    int shaBpp;
+    _X_UNUSED int shaXoff, shaYoff;
+    int x, y, w, h, width;
+    int i;
+    FbBits *winBase = NULL, *win;
+    CARD32 winSize;
+    static Bool firstQuery = TRUE;
+    static Bool forceAlign = FALSE;
+    Bool isAstBMC = FALSE;
+    Bool isFtBMC = FALSE;
+    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+    modesettingPtr ms = modesettingPTR(pScrn);
+    struct pci_device *pci = NULL;
+
+    if (BUS_PLATFORM == ms->pEnt->location.type) {
+        pci = ms->pEnt->location.id.plat->pdev;
+    } else if (BUS_PCI == ms->pEnt->location.type) {
+        pci = ms->pEnt->location.id.pci;
+    }
+
+    if (pci && device_is_ast_bmc(pci)) {
+        isAstBMC = TRUE;
+        if (firstQuery) {
+			if (1 == drmIoctl(ms->fd, DRM_IOCTL_AST_VRAM_TYPE_DEVICE, NULL)) {
+				forceAlign = TRUE;
+			}
+			firstQuery = FALSE;
+        }
+    } else if (pci && device_is_ft_bmc(pci)) {
+		isFtBMC = TRUE;
+		if (firstQuery) {
+			if (1 == drmIoctl(ms->fd, DRM_IOCTL_PHYTIUM_VRAM_TYPE_DEVICE, NULL)) {
+				forceAlign = TRUE;
+			}
+			firstQuery = FALSE;
+        }
+	}
+
+    fbGetDrawable(&pShadow->drawable, shaBase, shaStride, shaBpp, shaXoff,
+                  shaYoff);
+    while (nbox--) {
+        x = pbox->x1 * shaBpp;
+        y = pbox->y1;
+        w = (pbox->x2 - pbox->x1) * shaBpp;
+        h = pbox->y2 - pbox->y1;
+
+        scrLine = (x >> FB_SHIFT);
+        shaLine = shaBase + y * shaStride + (x >> FB_SHIFT);
+
+        x &= FB_MASK;
+        w = (w + x + FB_MASK) >> FB_SHIFT;
+
+        while (h--) {
+            winSize = 0;
+            scrBase = 0;
+            width = w;
+            scr = scrLine;
+            sha = shaLine;
+            while (width) {
+                /* how much remains in this window */
+                i = scrBase + winSize - scr;
+                if (i <= 0 || scr < scrBase) {
+                    winBase = (FbBits *) (*pBuf->window) (pScreen,
+                                                          y,
+                                                          scr * sizeof(FbBits),
+                                                          SHADOW_WINDOW_WRITE,
+                                                          &winSize,
+                                                          pBuf->closure);
+                    if (!winBase)
+                        return;
+                    scrBase = scr;
+                    winSize /= sizeof(FbBits);
+                    i = winSize;
+                }
+                win = winBase + (scr - scrBase);
+                if (i > width)
+                    i = width;
+                width -= i;
+                scr += i;
+                if ((isFtBMC || isAstBMC) && forceAlign) {
+                    align_memcpy(win, sha, i * sizeof(FbBits));
+                } else {
+                    memcpy(win, sha, i * sizeof(FbBits));
+                }
+                sha += i;
+            }
+            shaLine += shaStride;
+            y++;
+        }
+        pbox++;
+    }
+}
+
 static void
 msUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
 {
@@ -1193,7 +1349,7 @@ msUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
     if (use_3224)
         shadowUpdate32to24(pScreen, pBuf);
     else
-        shadowUpdatePacked(pScreen, pBuf);
+        msshadowUpdatePacked(pScreen, pBuf);
 }
 
 static Bool
-- 
2.37.0

