| #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; |
| } |