blob: cb8ecc8249446abc9f63d00ad40d0e1aeeddf9a9 [file] [log] [blame]
#include "drmP.h"
#include "drm.h"
#include "glint.h"
#include "glint_drv.h"
#include <video/pm3fb.h>
static u32 glint_vram_size(struct glint_device *gdev)
{
u32 tempBypass = RREG32(PM3MemBypassWriteMask);
u32 temp1, temp2;
u32 memsize = 0;
unsigned i;
char __iomem *vram;
vram = ioremap(gdev->mc.vram_base, gdev->mc.vram_size);
if (!vram) {
GLINT_ERROR("Unable to ioremap %lu MB of VRAM. Retrying...\n", (unsigned long)gdev->mc.vram_size / MB);
gdev->mc.vram_size /= 2;
ioremap(gdev->mc.vram_base, gdev->mc.vram_size);
if (!vram) {
GLINT_ERROR("Unable to ioremap %lu MB of VRAM. Bailing out.\n", (unsigned long)gdev->mc.vram_size / MB);
return -1;
}
GLINT_INFO("ioremapped %lu MB of VRAM.\n", (unsigned long)gdev->mc.vram_size / MB);
}
GLINT_INFO("vram base: 0x%08X\n", (uint32_t)gdev->mc.vram_base);
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;
}
static int glint_vram_init(struct glint_device *gdev)
{
unsigned size;
int ret;
/* work out accessible VRAM */
gdev->mc.vram_base = pci_resource_start(gdev->ddev->pdev, 1);
gdev->mc.vram_size = pci_resource_len(gdev->ddev->pdev, 1);
gdev->mc.vram_size = glint_vram_size(gdev);
if (!request_region(gdev->mc.vram_base, gdev->mc.vram_size, "glintfb_vram")) {
GLINT_ERROR("can't region_reserve VRAM\n");
return -ENXIO;
}
ret = generic_ttm_global_init(&gdev->mman);
if (ret) {
GLINT_ERROR("failed to set up ttm\n");
return -1;
}
ret = ttm_bo_device_init(&gdev->mman.bdev,
gdev->mman.bo_global_ref.ref.object,
&glint_bo_driver, DRM_FILE_PAGE_OFFSET,
false);
if (ret) {
GLINT_ERROR("failed to set up buffer object driver: %d\n", ret);
return -1;
}
size = size & (PAGE_MASK << 1);
ret = ttm_bo_init_mm(&gdev->mman.bdev, TTM_PL_VRAM, size >> PAGE_SHIFT);
if (ret) {
GLINT_ERROR("failed vram init: %d\n", ret);
return -1;
}
ret = drm_addmap(gdev->ddev, gdev->mc.vram_base, gdev->mc.vram_size,
_DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING,
&gdev->framebuffer);
return 0;
}
static void glint_vram_fini(struct glint_device *gdev)
{
iounmap(gdev->rmmio);
gdev->rmmio = NULL;
if (gdev->framebuffer)
drm_rmmap(gdev->ddev, gdev->framebuffer);
if (gdev->mc.vram_base)
release_region(gdev->mc.vram_base, gdev->mc.vram_size);
}
int glint_device_init(struct glint_device *gdev,
struct drm_device *ddev,
struct pci_dev *pdev,
uint32_t flags)
{
int ret;
gdev->dev = &pdev->dev;
gdev->ddev = ddev;
gdev->pdev = pdev;
gdev->flags = flags;
gdev->num_crtc = 1;
/* 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);
ret = glint_vram_init(gdev);
if (ret)
return ret;
return 0;
}
void glint_device_fini(struct glint_device *gdev)
{
glint_vram_fini(gdev);
}