blob: 125df20bb05882ef619c976f6b31ff5fde8c2dcc [file] [log] [blame]
#include "drmP.h"
#include "drm.h"
#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,
uint32_t flags)
{
gdev->dev = &pdev->dev;
gdev->ddev = ddev;
gdev->pdev = pdev;
gdev->flags = flags;
gdev->num_crtc = 2;
/* Registers mapping */
/* TODO: block userspace mapping of io register */
gdev->rmmio_base = pci_resource_start(gdev->ddev->pdev, 0);
gdev->rmmio_size = PM3_REGS_SIZE;
/* The first 64 KiB provides little-endian access, the second
* provides big-endian access. */
#if defined(__BIG_ENDIAN)
gdev->rmmio_base += PM3_REGS_SIZE;
GLINT_INFO("Adjusting register base for big-endian.\n");
#endif
gdev->rmmio = ioremap(gdev->rmmio_base, gdev->rmmio_size);
if (gdev->rmmio == NULL) {
return -ENOMEM;
}
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;
}
void glint_device_fini(struct glint_device *gdev)
{
iounmap(gdev->rmmio);
gdev->rmmio = NULL;
}