Merge branch 'gpu-switcher' of /ssd/git//linux-2.6 into drm-next-stage
[linux-2.6.git] / drivers / gpu / drm / radeon / radeon_device.c
index cb8d9a1..e28e4ed 100644 (file)
@@ -101,80 +101,103 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
        }
 }
 
-/*
- * MC common functions
+/**
+ * radeon_vram_location - try to find VRAM location
+ * @rdev: radeon device structure holding all necessary informations
+ * @mc: memory controller structure holding memory informations
+ * @base: base address at which to put VRAM
+ *
+ * Function will place try to place VRAM at base address provided
+ * as parameter (which is so far either PCI aperture address or
+ * for IGP TOM base address).
+ *
+ * If there is not enough space to fit the unvisible VRAM in the 32bits
+ * address space then we limit the VRAM size to the aperture.
+ *
+ * If we are using AGP and if the AGP aperture doesn't allow us to have
+ * room for all the VRAM than we restrict the VRAM to the PCI aperture
+ * size and print a warning.
+ *
+ * This function will never fails, worst case are limiting VRAM.
+ *
+ * Note: GTT start, end, size should be initialized before calling this
+ * function on AGP platform.
+ *
+ * Note: We don't explictly enforce VRAM start to be aligned on VRAM size,
+ * this shouldn't be a problem as we are using the PCI aperture as a reference.
+ * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but
+ * not IGP.
+ *
+ * Note: we use mc_vram_size as on some board we need to program the mc to
+ * cover the whole aperture even if VRAM size is inferior to aperture size
+ * Novell bug 204882 + along with lots of ubuntu ones
+ *
+ * Note: when limiting vram it's safe to overwritte real_vram_size because
+ * we are not in case where real_vram_size is inferior to mc_vram_size (ie
+ * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu
+ * ones)
+ *
+ * Note: IGP TOM addr should be the same as the aperture addr, we don't
+ * explicitly check for that thought.
+ *
+ * FIXME: when reducing VRAM size align new size on power of 2.
+ */
+void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base)
+{
+       mc->vram_start = base;
+       if (mc->mc_vram_size > (0xFFFFFFFF - base + 1)) {
+               dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
+               mc->real_vram_size = mc->aper_size;
+               mc->mc_vram_size = mc->aper_size;
+       }
+       mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+       if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_end <= mc->gtt_end) {
+               dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
+               mc->real_vram_size = mc->aper_size;
+               mc->mc_vram_size = mc->aper_size;
+       }
+       mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+       dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n",
+                       mc->mc_vram_size >> 20, mc->vram_start,
+                       mc->vram_end, mc->real_vram_size >> 20);
+}
+
+/**
+ * radeon_gtt_location - try to find GTT location
+ * @rdev: radeon device structure holding all necessary informations
+ * @mc: memory controller structure holding memory informations
+ *
+ * Function will place try to place GTT before or after VRAM.
+ *
+ * If GTT size is bigger than space left then we ajust GTT size.
+ * Thus function will never fails.
+ *
+ * FIXME: when reducing GTT size align new size on power of 2.
  */
-int radeon_mc_setup(struct radeon_device *rdev)
+void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
 {
-       uint32_t tmp;
+       u64 size_af, size_bf;
 
-       /* Some chips have an "issue" with the memory controller, the
-        * location must be aligned to the size. We just align it down,
-        * too bad if we walk over the top of system memory, we don't
-        * use DMA without a remapped anyway.
-        * Affected chips are rv280, all r3xx, and all r4xx, but not IGP
-        */
-       /* FGLRX seems to setup like this, VRAM a 0, then GART.
-        */
-       /*
-        * Note: from R6xx the address space is 40bits but here we only
-        * use 32bits (still have to see a card which would exhaust 4G
-        * address space).
-        */
-       if (rdev->mc.vram_location != 0xFFFFFFFFUL) {
-               /* vram location was already setup try to put gtt after
-                * if it fits */
-               tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size;
-               tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1);
-               if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) {
-                       rdev->mc.gtt_location = tmp;
-               } else {
-                       if (rdev->mc.gtt_size >= rdev->mc.vram_location) {
-                               printk(KERN_ERR "[drm] GTT too big to fit "
-                                      "before or after vram location.\n");
-                               return -EINVAL;
-                       }
-                       rdev->mc.gtt_location = 0;
-               }
-       } else if (rdev->mc.gtt_location != 0xFFFFFFFFUL) {
-               /* gtt location was already setup try to put vram before
-                * if it fits */
-               if (rdev->mc.mc_vram_size < rdev->mc.gtt_location) {
-                       rdev->mc.vram_location = 0;
-               } else {
-                       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size;
-                       tmp += (rdev->mc.mc_vram_size - 1);
-                       tmp &= ~(rdev->mc.mc_vram_size - 1);
-                       if ((0xFFFFFFFFUL - tmp) >= rdev->mc.mc_vram_size) {
-                               rdev->mc.vram_location = tmp;
-                       } else {
-                               printk(KERN_ERR "[drm] vram too big to fit "
-                                      "before or after GTT location.\n");
-                               return -EINVAL;
-                       }
+       size_af = 0xFFFFFFFF - mc->vram_end;
+       size_bf = mc->vram_start;
+       if (size_bf > size_af) {
+               if (mc->gtt_size > size_bf) {
+                       dev_warn(rdev->dev, "limiting GTT\n");
+                       mc->gtt_size = size_bf;
                }
+               mc->gtt_start = mc->vram_start - mc->gtt_size;
        } else {
-               rdev->mc.vram_location = 0;
-               tmp = rdev->mc.mc_vram_size;
-               tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1);
-               rdev->mc.gtt_location = tmp;
-       }
-       rdev->mc.vram_start = rdev->mc.vram_location;
-       rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
-       rdev->mc.gtt_start = rdev->mc.gtt_location;
-       rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
-       DRM_INFO("radeon: VRAM %uM\n", (unsigned)(rdev->mc.mc_vram_size >> 20));
-       DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n",
-                (unsigned)rdev->mc.vram_location,
-                (unsigned)(rdev->mc.vram_location + rdev->mc.mc_vram_size - 1));
-       DRM_INFO("radeon: GTT %uM\n", (unsigned)(rdev->mc.gtt_size >> 20));
-       DRM_INFO("radeon: GTT from 0x%08X to 0x%08X\n",
-                (unsigned)rdev->mc.gtt_location,
-                (unsigned)(rdev->mc.gtt_location + rdev->mc.gtt_size - 1));
-       return 0;
+               if (mc->gtt_size > size_af) {
+                       dev_warn(rdev->dev, "limiting GTT\n");
+                       mc->gtt_size = size_af;
+               }
+               mc->gtt_start = mc->vram_end + 1;
+       }
+       mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
+       dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n",
+                       mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
 }
 
-
 /*
  * GPU helpers function.
  */
@@ -183,7 +206,16 @@ bool radeon_card_posted(struct radeon_device *rdev)
        uint32_t reg;
 
        /* first check CRTCs */
-       if (ASIC_IS_AVIVO(rdev)) {
+       if (ASIC_IS_DCE4(rdev)) {
+               reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
+                       RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) |
+                       RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
+                       RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) |
+                       RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
+                       RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+               if (reg & EVERGREEN_CRTC_MASTER_EN)
+                       return true;
+       } else if (ASIC_IS_AVIVO(rdev)) {
                reg = RREG32(AVIVO_D1CRTC_CONTROL) |
                      RREG32(AVIVO_D2CRTC_CONTROL);
                if (reg & AVIVO_CRTC_EN) {
@@ -230,6 +262,8 @@ bool radeon_boot_test_post_card(struct radeon_device *rdev)
 
 int radeon_dummy_page_init(struct radeon_device *rdev)
 {
+       if (rdev->dummy_page.page)
+               return 0;
        rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO);
        if (rdev->dummy_page.page == NULL)
                return -ENOMEM;
@@ -311,7 +345,7 @@ void radeon_register_accessor_init(struct radeon_device *rdev)
                rdev->mc_rreg = &rs600_mc_rreg;
                rdev->mc_wreg = &rs600_mc_wreg;
        }
-       if (rdev->family >= CHIP_R600) {
+       if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) {
                rdev->pciep_rreg = &r600_pciep_rreg;
                rdev->pciep_wreg = &r600_pciep_wreg;
        }
@@ -330,21 +364,22 @@ int radeon_asic_init(struct radeon_device *rdev)
        case CHIP_RS100:
        case CHIP_RV200:
        case CHIP_RS200:
+               rdev->asic = &r100_asic;
+               break;
        case CHIP_R200:
        case CHIP_RV250:
        case CHIP_RS300:
        case CHIP_RV280:
-               rdev->asic = &r100_asic;
+               rdev->asic = &r200_asic;
                break;
        case CHIP_R300:
        case CHIP_R350:
        case CHIP_RV350:
        case CHIP_RV380:
-               rdev->asic = &r300_asic;
-               if (rdev->flags & RADEON_IS_PCIE) {
-                       rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
-                       rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
-               }
+               if (rdev->flags & RADEON_IS_PCIE)
+                       rdev->asic = &r300_asic_pcie;
+               else
+                       rdev->asic = &r300_asic;
                break;
        case CHIP_R420:
        case CHIP_R423:
@@ -388,6 +423,13 @@ int radeon_asic_init(struct radeon_device *rdev)
        case CHIP_RV740:
                rdev->asic = &rv770_asic;
                break;
+       case CHIP_CEDAR:
+       case CHIP_REDWOOD:
+       case CHIP_JUNIPER:
+       case CHIP_CYPRESS:
+       case CHIP_HEMLOCK:
+               rdev->asic = &evergreen_asic;
+               break;
        default:
                /* FIXME: not supported yet */
                return -EINVAL;
@@ -669,11 +711,14 @@ int radeon_device_init(struct radeon_device *rdev,
        mutex_init(&rdev->cs_mutex);
        mutex_init(&rdev->ib_pool.mutex);
        mutex_init(&rdev->cp.mutex);
+       mutex_init(&rdev->dc_hw_i2c_mutex);
        if (rdev->family >= CHIP_R600)
                spin_lock_init(&rdev->ih.lock);
        mutex_init(&rdev->gem.mutex);
+       mutex_init(&rdev->pm.mutex);
        rwlock_init(&rdev->fence_drv.lock);
        INIT_LIST_HEAD(&rdev->gem.objects);
+       init_waitqueue_head(&rdev->irq.vblank_queue);
 
        /* setup workqueue */
        rdev->wq = create_workqueue("radeon");