diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_device.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 235 |
1 files changed, 160 insertions, 75 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 768b1509fa03..e28e4ed5f720 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <drm/drm_crtc_helper.h> | 30 | #include <drm/drm_crtc_helper.h> |
31 | #include <drm/radeon_drm.h> | 31 | #include <drm/radeon_drm.h> |
32 | #include <linux/vgaarb.h> | 32 | #include <linux/vgaarb.h> |
33 | #include <linux/vga_switcheroo.h> | ||
33 | #include "radeon_reg.h" | 34 | #include "radeon_reg.h" |
34 | #include "radeon.h" | 35 | #include "radeon.h" |
35 | #include "radeon_asic.h" | 36 | #include "radeon_asic.h" |
@@ -100,80 +101,103 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) | |||
100 | } | 101 | } |
101 | } | 102 | } |
102 | 103 | ||
103 | /* | 104 | /** |
104 | * MC common functions | 105 | * radeon_vram_location - try to find VRAM location |
106 | * @rdev: radeon device structure holding all necessary informations | ||
107 | * @mc: memory controller structure holding memory informations | ||
108 | * @base: base address at which to put VRAM | ||
109 | * | ||
110 | * Function will place try to place VRAM at base address provided | ||
111 | * as parameter (which is so far either PCI aperture address or | ||
112 | * for IGP TOM base address). | ||
113 | * | ||
114 | * If there is not enough space to fit the unvisible VRAM in the 32bits | ||
115 | * address space then we limit the VRAM size to the aperture. | ||
116 | * | ||
117 | * If we are using AGP and if the AGP aperture doesn't allow us to have | ||
118 | * room for all the VRAM than we restrict the VRAM to the PCI aperture | ||
119 | * size and print a warning. | ||
120 | * | ||
121 | * This function will never fails, worst case are limiting VRAM. | ||
122 | * | ||
123 | * Note: GTT start, end, size should be initialized before calling this | ||
124 | * function on AGP platform. | ||
125 | * | ||
126 | * Note: We don't explictly enforce VRAM start to be aligned on VRAM size, | ||
127 | * this shouldn't be a problem as we are using the PCI aperture as a reference. | ||
128 | * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but | ||
129 | * not IGP. | ||
130 | * | ||
131 | * Note: we use mc_vram_size as on some board we need to program the mc to | ||
132 | * cover the whole aperture even if VRAM size is inferior to aperture size | ||
133 | * Novell bug 204882 + along with lots of ubuntu ones | ||
134 | * | ||
135 | * Note: when limiting vram it's safe to overwritte real_vram_size because | ||
136 | * we are not in case where real_vram_size is inferior to mc_vram_size (ie | ||
137 | * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu | ||
138 | * ones) | ||
139 | * | ||
140 | * Note: IGP TOM addr should be the same as the aperture addr, we don't | ||
141 | * explicitly check for that thought. | ||
142 | * | ||
143 | * FIXME: when reducing VRAM size align new size on power of 2. | ||
144 | */ | ||
145 | void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base) | ||
146 | { | ||
147 | mc->vram_start = base; | ||
148 | if (mc->mc_vram_size > (0xFFFFFFFF - base + 1)) { | ||
149 | dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); | ||
150 | mc->real_vram_size = mc->aper_size; | ||
151 | mc->mc_vram_size = mc->aper_size; | ||
152 | } | ||
153 | mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; | ||
154 | if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_end <= mc->gtt_end) { | ||
155 | dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); | ||
156 | mc->real_vram_size = mc->aper_size; | ||
157 | mc->mc_vram_size = mc->aper_size; | ||
158 | } | ||
159 | mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; | ||
160 | dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n", | ||
161 | mc->mc_vram_size >> 20, mc->vram_start, | ||
162 | mc->vram_end, mc->real_vram_size >> 20); | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * radeon_gtt_location - try to find GTT location | ||
167 | * @rdev: radeon device structure holding all necessary informations | ||
168 | * @mc: memory controller structure holding memory informations | ||
169 | * | ||
170 | * Function will place try to place GTT before or after VRAM. | ||
171 | * | ||
172 | * If GTT size is bigger than space left then we ajust GTT size. | ||
173 | * Thus function will never fails. | ||
174 | * | ||
175 | * FIXME: when reducing GTT size align new size on power of 2. | ||
105 | */ | 176 | */ |
106 | int radeon_mc_setup(struct radeon_device *rdev) | 177 | void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) |
107 | { | 178 | { |
108 | uint32_t tmp; | 179 | u64 size_af, size_bf; |
109 | 180 | ||
110 | /* Some chips have an "issue" with the memory controller, the | 181 | size_af = 0xFFFFFFFF - mc->vram_end; |
111 | * location must be aligned to the size. We just align it down, | 182 | size_bf = mc->vram_start; |
112 | * too bad if we walk over the top of system memory, we don't | 183 | if (size_bf > size_af) { |
113 | * use DMA without a remapped anyway. | 184 | if (mc->gtt_size > size_bf) { |
114 | * Affected chips are rv280, all r3xx, and all r4xx, but not IGP | 185 | dev_warn(rdev->dev, "limiting GTT\n"); |
115 | */ | 186 | mc->gtt_size = size_bf; |
116 | /* FGLRX seems to setup like this, VRAM a 0, then GART. | ||
117 | */ | ||
118 | /* | ||
119 | * Note: from R6xx the address space is 40bits but here we only | ||
120 | * use 32bits (still have to see a card which would exhaust 4G | ||
121 | * address space). | ||
122 | */ | ||
123 | if (rdev->mc.vram_location != 0xFFFFFFFFUL) { | ||
124 | /* vram location was already setup try to put gtt after | ||
125 | * if it fits */ | ||
126 | tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size; | ||
127 | tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1); | ||
128 | if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) { | ||
129 | rdev->mc.gtt_location = tmp; | ||
130 | } else { | ||
131 | if (rdev->mc.gtt_size >= rdev->mc.vram_location) { | ||
132 | printk(KERN_ERR "[drm] GTT too big to fit " | ||
133 | "before or after vram location.\n"); | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | rdev->mc.gtt_location = 0; | ||
137 | } | ||
138 | } else if (rdev->mc.gtt_location != 0xFFFFFFFFUL) { | ||
139 | /* gtt location was already setup try to put vram before | ||
140 | * if it fits */ | ||
141 | if (rdev->mc.mc_vram_size < rdev->mc.gtt_location) { | ||
142 | rdev->mc.vram_location = 0; | ||
143 | } else { | ||
144 | tmp = rdev->mc.gtt_location + rdev->mc.gtt_size; | ||
145 | tmp += (rdev->mc.mc_vram_size - 1); | ||
146 | tmp &= ~(rdev->mc.mc_vram_size - 1); | ||
147 | if ((0xFFFFFFFFUL - tmp) >= rdev->mc.mc_vram_size) { | ||
148 | rdev->mc.vram_location = tmp; | ||
149 | } else { | ||
150 | printk(KERN_ERR "[drm] vram too big to fit " | ||
151 | "before or after GTT location.\n"); | ||
152 | return -EINVAL; | ||
153 | } | ||
154 | } | 187 | } |
188 | mc->gtt_start = mc->vram_start - mc->gtt_size; | ||
155 | } else { | 189 | } else { |
156 | rdev->mc.vram_location = 0; | 190 | if (mc->gtt_size > size_af) { |
157 | tmp = rdev->mc.mc_vram_size; | 191 | dev_warn(rdev->dev, "limiting GTT\n"); |
158 | tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1); | 192 | mc->gtt_size = size_af; |
159 | rdev->mc.gtt_location = tmp; | 193 | } |
160 | } | 194 | mc->gtt_start = mc->vram_end + 1; |
161 | rdev->mc.vram_start = rdev->mc.vram_location; | 195 | } |
162 | rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1; | 196 | mc->gtt_end = mc->gtt_start + mc->gtt_size - 1; |
163 | rdev->mc.gtt_start = rdev->mc.gtt_location; | 197 | dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n", |
164 | rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; | 198 | mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end); |
165 | DRM_INFO("radeon: VRAM %uM\n", (unsigned)(rdev->mc.mc_vram_size >> 20)); | ||
166 | DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n", | ||
167 | (unsigned)rdev->mc.vram_location, | ||
168 | (unsigned)(rdev->mc.vram_location + rdev->mc.mc_vram_size - 1)); | ||
169 | DRM_INFO("radeon: GTT %uM\n", (unsigned)(rdev->mc.gtt_size >> 20)); | ||
170 | DRM_INFO("radeon: GTT from 0x%08X to 0x%08X\n", | ||
171 | (unsigned)rdev->mc.gtt_location, | ||
172 | (unsigned)(rdev->mc.gtt_location + rdev->mc.gtt_size - 1)); | ||
173 | return 0; | ||
174 | } | 199 | } |
175 | 200 | ||
176 | |||
177 | /* | 201 | /* |
178 | * GPU helpers function. | 202 | * GPU helpers function. |
179 | */ | 203 | */ |
@@ -182,7 +206,16 @@ bool radeon_card_posted(struct radeon_device *rdev) | |||
182 | uint32_t reg; | 206 | uint32_t reg; |
183 | 207 | ||
184 | /* first check CRTCs */ | 208 | /* first check CRTCs */ |
185 | if (ASIC_IS_AVIVO(rdev)) { | 209 | if (ASIC_IS_DCE4(rdev)) { |
210 | reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | | ||
211 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | | ||
212 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | | ||
213 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | | ||
214 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | | ||
215 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); | ||
216 | if (reg & EVERGREEN_CRTC_MASTER_EN) | ||
217 | return true; | ||
218 | } else if (ASIC_IS_AVIVO(rdev)) { | ||
186 | reg = RREG32(AVIVO_D1CRTC_CONTROL) | | 219 | reg = RREG32(AVIVO_D1CRTC_CONTROL) | |
187 | RREG32(AVIVO_D2CRTC_CONTROL); | 220 | RREG32(AVIVO_D2CRTC_CONTROL); |
188 | if (reg & AVIVO_CRTC_EN) { | 221 | if (reg & AVIVO_CRTC_EN) { |
@@ -229,6 +262,8 @@ bool radeon_boot_test_post_card(struct radeon_device *rdev) | |||
229 | 262 | ||
230 | int radeon_dummy_page_init(struct radeon_device *rdev) | 263 | int radeon_dummy_page_init(struct radeon_device *rdev) |
231 | { | 264 | { |
265 | if (rdev->dummy_page.page) | ||
266 | return 0; | ||
232 | rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO); | 267 | rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO); |
233 | if (rdev->dummy_page.page == NULL) | 268 | if (rdev->dummy_page.page == NULL) |
234 | return -ENOMEM; | 269 | return -ENOMEM; |
@@ -310,7 +345,7 @@ void radeon_register_accessor_init(struct radeon_device *rdev) | |||
310 | rdev->mc_rreg = &rs600_mc_rreg; | 345 | rdev->mc_rreg = &rs600_mc_rreg; |
311 | rdev->mc_wreg = &rs600_mc_wreg; | 346 | rdev->mc_wreg = &rs600_mc_wreg; |
312 | } | 347 | } |
313 | if (rdev->family >= CHIP_R600) { | 348 | if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) { |
314 | rdev->pciep_rreg = &r600_pciep_rreg; | 349 | rdev->pciep_rreg = &r600_pciep_rreg; |
315 | rdev->pciep_wreg = &r600_pciep_wreg; | 350 | rdev->pciep_wreg = &r600_pciep_wreg; |
316 | } | 351 | } |
@@ -329,21 +364,22 @@ int radeon_asic_init(struct radeon_device *rdev) | |||
329 | case CHIP_RS100: | 364 | case CHIP_RS100: |
330 | case CHIP_RV200: | 365 | case CHIP_RV200: |
331 | case CHIP_RS200: | 366 | case CHIP_RS200: |
367 | rdev->asic = &r100_asic; | ||
368 | break; | ||
332 | case CHIP_R200: | 369 | case CHIP_R200: |
333 | case CHIP_RV250: | 370 | case CHIP_RV250: |
334 | case CHIP_RS300: | 371 | case CHIP_RS300: |
335 | case CHIP_RV280: | 372 | case CHIP_RV280: |
336 | rdev->asic = &r100_asic; | 373 | rdev->asic = &r200_asic; |
337 | break; | 374 | break; |
338 | case CHIP_R300: | 375 | case CHIP_R300: |
339 | case CHIP_R350: | 376 | case CHIP_R350: |
340 | case CHIP_RV350: | 377 | case CHIP_RV350: |
341 | case CHIP_RV380: | 378 | case CHIP_RV380: |
342 | rdev->asic = &r300_asic; | 379 | if (rdev->flags & RADEON_IS_PCIE) |
343 | if (rdev->flags & RADEON_IS_PCIE) { | 380 | rdev->asic = &r300_asic_pcie; |
344 | rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; | 381 | else |
345 | rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; | 382 | rdev->asic = &r300_asic; |
346 | } | ||
347 | break; | 383 | break; |
348 | case CHIP_R420: | 384 | case CHIP_R420: |
349 | case CHIP_R423: | 385 | case CHIP_R423: |
@@ -387,6 +423,13 @@ int radeon_asic_init(struct radeon_device *rdev) | |||
387 | case CHIP_RV740: | 423 | case CHIP_RV740: |
388 | rdev->asic = &rv770_asic; | 424 | rdev->asic = &rv770_asic; |
389 | break; | 425 | break; |
426 | case CHIP_CEDAR: | ||
427 | case CHIP_REDWOOD: | ||
428 | case CHIP_JUNIPER: | ||
429 | case CHIP_CYPRESS: | ||
430 | case CHIP_HEMLOCK: | ||
431 | rdev->asic = &evergreen_asic; | ||
432 | break; | ||
390 | default: | 433 | default: |
391 | /* FIXME: not supported yet */ | 434 | /* FIXME: not supported yet */ |
392 | return -EINVAL; | 435 | return -EINVAL; |
@@ -613,6 +656,36 @@ void radeon_check_arguments(struct radeon_device *rdev) | |||
613 | } | 656 | } |
614 | } | 657 | } |
615 | 658 | ||
659 | static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) | ||
660 | { | ||
661 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
662 | struct radeon_device *rdev = dev->dev_private; | ||
663 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; | ||
664 | if (state == VGA_SWITCHEROO_ON) { | ||
665 | printk(KERN_INFO "radeon: switched on\n"); | ||
666 | /* don't suspend or resume card normally */ | ||
667 | rdev->powered_down = false; | ||
668 | radeon_resume_kms(dev); | ||
669 | } else { | ||
670 | printk(KERN_INFO "radeon: switched off\n"); | ||
671 | radeon_suspend_kms(dev, pmm); | ||
672 | /* don't suspend or resume card normally */ | ||
673 | rdev->powered_down = true; | ||
674 | } | ||
675 | } | ||
676 | |||
677 | static bool radeon_switcheroo_can_switch(struct pci_dev *pdev) | ||
678 | { | ||
679 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
680 | bool can_switch; | ||
681 | |||
682 | spin_lock(&dev->count_lock); | ||
683 | can_switch = (dev->open_count == 0); | ||
684 | spin_unlock(&dev->count_lock); | ||
685 | return can_switch; | ||
686 | } | ||
687 | |||
688 | |||
616 | int radeon_device_init(struct radeon_device *rdev, | 689 | int radeon_device_init(struct radeon_device *rdev, |
617 | struct drm_device *ddev, | 690 | struct drm_device *ddev, |
618 | struct pci_dev *pdev, | 691 | struct pci_dev *pdev, |
@@ -638,11 +711,14 @@ int radeon_device_init(struct radeon_device *rdev, | |||
638 | mutex_init(&rdev->cs_mutex); | 711 | mutex_init(&rdev->cs_mutex); |
639 | mutex_init(&rdev->ib_pool.mutex); | 712 | mutex_init(&rdev->ib_pool.mutex); |
640 | mutex_init(&rdev->cp.mutex); | 713 | mutex_init(&rdev->cp.mutex); |
714 | mutex_init(&rdev->dc_hw_i2c_mutex); | ||
641 | if (rdev->family >= CHIP_R600) | 715 | if (rdev->family >= CHIP_R600) |
642 | spin_lock_init(&rdev->ih.lock); | 716 | spin_lock_init(&rdev->ih.lock); |
643 | mutex_init(&rdev->gem.mutex); | 717 | mutex_init(&rdev->gem.mutex); |
718 | mutex_init(&rdev->pm.mutex); | ||
644 | rwlock_init(&rdev->fence_drv.lock); | 719 | rwlock_init(&rdev->fence_drv.lock); |
645 | INIT_LIST_HEAD(&rdev->gem.objects); | 720 | INIT_LIST_HEAD(&rdev->gem.objects); |
721 | init_waitqueue_head(&rdev->irq.vblank_queue); | ||
646 | 722 | ||
647 | /* setup workqueue */ | 723 | /* setup workqueue */ |
648 | rdev->wq = create_workqueue("radeon"); | 724 | rdev->wq = create_workqueue("radeon"); |
@@ -692,6 +768,9 @@ int radeon_device_init(struct radeon_device *rdev, | |||
692 | /* this will fail for cards that aren't VGA class devices, just | 768 | /* this will fail for cards that aren't VGA class devices, just |
693 | * ignore it */ | 769 | * ignore it */ |
694 | vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); | 770 | vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); |
771 | vga_switcheroo_register_client(rdev->pdev, | ||
772 | radeon_switcheroo_set_state, | ||
773 | radeon_switcheroo_can_switch); | ||
695 | 774 | ||
696 | r = radeon_init(rdev); | 775 | r = radeon_init(rdev); |
697 | if (r) | 776 | if (r) |
@@ -723,6 +802,7 @@ void radeon_device_fini(struct radeon_device *rdev) | |||
723 | rdev->shutdown = true; | 802 | rdev->shutdown = true; |
724 | radeon_fini(rdev); | 803 | radeon_fini(rdev); |
725 | destroy_workqueue(rdev->wq); | 804 | destroy_workqueue(rdev->wq); |
805 | vga_switcheroo_unregister_client(rdev->pdev); | ||
726 | vga_client_register(rdev->pdev, NULL, NULL, NULL); | 806 | vga_client_register(rdev->pdev, NULL, NULL, NULL); |
727 | iounmap(rdev->rmmio); | 807 | iounmap(rdev->rmmio); |
728 | rdev->rmmio = NULL; | 808 | rdev->rmmio = NULL; |
@@ -746,6 +826,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) | |||
746 | } | 826 | } |
747 | rdev = dev->dev_private; | 827 | rdev = dev->dev_private; |
748 | 828 | ||
829 | if (rdev->powered_down) | ||
830 | return 0; | ||
749 | /* unpin the front buffers */ | 831 | /* unpin the front buffers */ |
750 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 832 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
751 | struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); | 833 | struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); |
@@ -791,6 +873,9 @@ int radeon_resume_kms(struct drm_device *dev) | |||
791 | { | 873 | { |
792 | struct radeon_device *rdev = dev->dev_private; | 874 | struct radeon_device *rdev = dev->dev_private; |
793 | 875 | ||
876 | if (rdev->powered_down) | ||
877 | return 0; | ||
878 | |||
794 | acquire_console_sem(); | 879 | acquire_console_sem(); |
795 | pci_set_power_state(dev->pdev, PCI_D0); | 880 | pci_set_power_state(dev->pdev, PCI_D0); |
796 | pci_restore_state(dev->pdev); | 881 | pci_restore_state(dev->pdev); |