drm/glint: detect VRAM size

Signed-off-by: Matt Turner <mattst88@gmail.com>
diff --git a/drivers/gpu/drm/glint/glint.h b/drivers/gpu/drm/glint/glint.h
index 9c0a596..51c8f2c 100644
--- a/drivers/gpu/drm/glint/glint.h
+++ b/drivers/gpu/drm/glint/glint.h
@@ -3,6 +3,12 @@
 
 #include "glint_family.h"
 
+struct glint_mc {
+	resource_size_t			aper_size;
+	resource_size_t			aper_base;
+	u32				vram_size;
+};
+
 struct glint_device {
 	struct device			*dev;
 	struct drm_device		*ddev;
@@ -13,6 +19,8 @@
 	resource_size_t			rmmio_base;
 	resource_size_t			rmmio_size;
 	void				*rmmio;
+
+	struct glint_mc			mc;
 };
 
 #endif				/* __GLINT_H__ */
diff --git a/drivers/gpu/drm/glint/glint_device.c b/drivers/gpu/drm/glint/glint_device.c
index 51163f9..2cf207a 100644
--- a/drivers/gpu/drm/glint/glint_device.c
+++ b/drivers/gpu/drm/glint/glint_device.c
@@ -4,6 +4,76 @@
 #include "glint.h"
 #include "glint_drv.h"
 
+#include <video/pm3fb.h>
+
+static u32 glint_vram_init_size(struct glint_device *gdev)
+{
+	char __iomem *vram;
+	unsigned i;
+	u32 tempBypass = RREG32(PM3MemBypassWriteMask);
+	u32 temp1, temp2;
+	u32 memsize = 0;
+
+	/* work out accessible VRAM */
+	gdev->mc.aper_base = pci_resource_start(gdev->ddev->pdev, 1);
+	gdev->mc.aper_size = pci_resource_len(gdev->ddev->pdev, 1);
+
+	vram = ioremap(gdev->mc.aper_base, gdev->mc.aper_size);
+	if (!vram) {
+		GLINT_ERROR("Unable to ioremap %lu MB of VRAM. Retrying...\n", (unsigned long)gdev->mc.aper_size / MB);
+		gdev->mc.aper_size /= 2;
+		ioremap(gdev->mc.aper_base, gdev->mc.aper_size);
+		if (!vram) {
+			GLINT_ERROR("Unable to ioremap %lu MB of VRAM. Bailing out.\n", (unsigned long)gdev->mc.aper_size / MB);
+			return 0;
+		}
+		GLINT_INFO("ioremapped %lu MB of VRAM.\n", (unsigned long)gdev->mc.aper_size / MB);
+	}
+
+	WREG32(PM3MemBypassWriteMask, 0xffffffff);
+
+#define TEST_PATTERN 0x00345678
+	for (i = 0; i < 32; i++) {
+		iowrite32(i * TEST_PATTERN, vram + (i * MB));
+		mb();
+		temp1 = ioread32(vram + (i * MB));
+
+		/* Let's check for wrapover, write will fail at 16MB boundary */
+		if (temp1 == (i * TEST_PATTERN))
+			memsize = i;
+		else
+			break;
+	}
+	GLINT_INFO("First pass detected %u MB of VRAM\n", memsize + 1);
+
+	if (memsize + 1 == i) {
+		for (i = 0; i < 32; i++) {
+			/* Clear first 4 bytes of each of the first 32MB */
+			iowrite32(0, vram + (i * MB));
+		}
+		wmb();
+
+		for (i = 32; i < 64; i++) {
+			iowrite32(i * TEST_PATTERN, vram + (i * MB));
+			mb();
+			temp1 = ioread32(vram + (i * MB));
+			temp2 = ioread32(vram + ((i - 32) * MB));
+
+			/* different value, different RAM... */
+			if ((temp1 == (i * TEST_PATTERN)) && (temp2 == 0))
+				memsize = i;
+			else
+				break;
+		}
+	}
+	GLINT_INFO("Second pass detected %u MB of VRAM\n", memsize + 1);
+
+	WREG32(PM3MemBypassWriteMask, tempBypass);
+	iounmap(vram);
+
+	return (memsize + 1) * MB;
+}
+
 int glint_device_init(struct glint_device *gdev,
 		      struct drm_device *ddev,
 		      struct pci_dev *pdev,
@@ -32,6 +102,8 @@
 	GLINT_INFO("register mmio base: 0x%08X\n", (uint32_t)gdev->rmmio_base);
 	GLINT_INFO("register mmio size: %u\n", (unsigned)gdev->rmmio_size);
 
+	gdev->mc.vram_size = glint_vram_init_size(gdev);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/glint/glint_drv.h b/drivers/gpu/drm/glint/glint_drv.h
index 58fedbc..b3f7d55 100644
--- a/drivers/gpu/drm/glint/glint_drv.h
+++ b/drivers/gpu/drm/glint/glint_drv.h
@@ -12,6 +12,12 @@
 #define DRIVER_PATCHLEVEL	0
 
 #define GLINT_INFO(fmt, arg...) DRM_INFO(DRIVER_NAME ": " fmt, ##arg)
+#define GLINT_ERROR(fmt, arg...) DRM_ERROR(DRIVER_NAME ": " fmt, ##arg)
+
+#define RREG32(reg) ioread32(((void __iomem *)gdev->rmmio) + (reg))
+#define WREG32(reg, v) iowrite32(v, ((void __iomem *)gdev->rmmio) + (reg))
+
+#define MB (1024 * 1024)
 
 #include "glint.h"