diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_device.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 195 |
1 files changed, 120 insertions, 75 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 768b1509fa03..91a9b966238e 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
@@ -100,80 +100,103 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) | |||
100 | } | 100 | } |
101 | } | 101 | } |
102 | 102 | ||
103 | /* | 103 | /** |
104 | * MC common functions | 104 | * radeon_vram_location - try to find VRAM location |
105 | * @rdev: radeon device structure holding all necessary informations | ||
106 | * @mc: memory controller structure holding memory informations | ||
107 | * @base: base address at which to put VRAM | ||
108 | * | ||
109 | * Function will place try to place VRAM at base address provided | ||
110 | * as parameter (which is so far either PCI aperture address or | ||
111 | * for IGP TOM base address). | ||
112 | * | ||
113 | * If there is not enough space to fit the unvisible VRAM in the 32bits | ||
114 | * address space then we limit the VRAM size to the aperture. | ||
115 | * | ||
116 | * If we are using AGP and if the AGP aperture doesn't allow us to have | ||
117 | * room for all the VRAM than we restrict the VRAM to the PCI aperture | ||
118 | * size and print a warning. | ||
119 | * | ||
120 | * This function will never fails, worst case are limiting VRAM. | ||
121 | * | ||
122 | * Note: GTT start, end, size should be initialized before calling this | ||
123 | * function on AGP platform. | ||
124 | * | ||
125 | * Note: We don't explictly enforce VRAM start to be aligned on VRAM size, | ||
126 | * this shouldn't be a problem as we are using the PCI aperture as a reference. | ||
127 | * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but | ||
128 | * not IGP. | ||
129 | * | ||
130 | * Note: we use mc_vram_size as on some board we need to program the mc to | ||
131 | * cover the whole aperture even if VRAM size is inferior to aperture size | ||
132 | * Novell bug 204882 + along with lots of ubuntu ones | ||
133 | * | ||
134 | * Note: when limiting vram it's safe to overwritte real_vram_size because | ||
135 | * we are not in case where real_vram_size is inferior to mc_vram_size (ie | ||
136 | * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu | ||
137 | * ones) | ||
138 | * | ||
139 | * Note: IGP TOM addr should be the same as the aperture addr, we don't | ||
140 | * explicitly check for that thought. | ||
141 | * | ||
142 | * FIXME: when reducing VRAM size align new size on power of 2. | ||
143 | */ | ||
144 | void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base) | ||
145 | { | ||
146 | mc->vram_start = base; | ||
147 | if (mc->mc_vram_size > (0xFFFFFFFF - base + 1)) { | ||
148 | dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); | ||
149 | mc->real_vram_size = mc->aper_size; | ||
150 | mc->mc_vram_size = mc->aper_size; | ||
151 | } | ||
152 | mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; | ||
153 | if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_end <= mc->gtt_end) { | ||
154 | dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); | ||
155 | mc->real_vram_size = mc->aper_size; | ||
156 | mc->mc_vram_size = mc->aper_size; | ||
157 | } | ||
158 | mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; | ||
159 | dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n", | ||
160 | mc->mc_vram_size >> 20, mc->vram_start, | ||
161 | mc->vram_end, mc->real_vram_size >> 20); | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * radeon_gtt_location - try to find GTT location | ||
166 | * @rdev: radeon device structure holding all necessary informations | ||
167 | * @mc: memory controller structure holding memory informations | ||
168 | * | ||
169 | * Function will place try to place GTT before or after VRAM. | ||
170 | * | ||
171 | * If GTT size is bigger than space left then we ajust GTT size. | ||
172 | * Thus function will never fails. | ||
173 | * | ||
174 | * FIXME: when reducing GTT size align new size on power of 2. | ||
105 | */ | 175 | */ |
106 | int radeon_mc_setup(struct radeon_device *rdev) | 176 | void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) |
107 | { | 177 | { |
108 | uint32_t tmp; | 178 | u64 size_af, size_bf; |
109 | 179 | ||
110 | /* Some chips have an "issue" with the memory controller, the | 180 | size_af = 0xFFFFFFFF - mc->vram_end; |
111 | * location must be aligned to the size. We just align it down, | 181 | size_bf = mc->vram_start; |
112 | * too bad if we walk over the top of system memory, we don't | 182 | if (size_bf > size_af) { |
113 | * use DMA without a remapped anyway. | 183 | if (mc->gtt_size > size_bf) { |
114 | * Affected chips are rv280, all r3xx, and all r4xx, but not IGP | 184 | dev_warn(rdev->dev, "limiting GTT\n"); |
115 | */ | 185 | 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 | } | 186 | } |
187 | mc->gtt_start = mc->vram_start - mc->gtt_size; | ||
155 | } else { | 188 | } else { |
156 | rdev->mc.vram_location = 0; | 189 | if (mc->gtt_size > size_af) { |
157 | tmp = rdev->mc.mc_vram_size; | 190 | dev_warn(rdev->dev, "limiting GTT\n"); |
158 | tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1); | 191 | mc->gtt_size = size_af; |
159 | rdev->mc.gtt_location = tmp; | 192 | } |
160 | } | 193 | mc->gtt_start = mc->vram_end + 1; |
161 | rdev->mc.vram_start = rdev->mc.vram_location; | 194 | } |
162 | rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1; | 195 | mc->gtt_end = mc->gtt_start + mc->gtt_size - 1; |
163 | rdev->mc.gtt_start = rdev->mc.gtt_location; | 196 | 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; | 197 | 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 | } | 198 | } |
175 | 199 | ||
176 | |||
177 | /* | 200 | /* |
178 | * GPU helpers function. | 201 | * GPU helpers function. |
179 | */ | 202 | */ |
@@ -182,7 +205,16 @@ bool radeon_card_posted(struct radeon_device *rdev) | |||
182 | uint32_t reg; | 205 | uint32_t reg; |
183 | 206 | ||
184 | /* first check CRTCs */ | 207 | /* first check CRTCs */ |
185 | if (ASIC_IS_AVIVO(rdev)) { | 208 | if (ASIC_IS_DCE4(rdev)) { |
209 | reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | | ||
210 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | | ||
211 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | | ||
212 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | | ||
213 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | | ||
214 | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); | ||
215 | if (reg & EVERGREEN_CRTC_MASTER_EN) | ||
216 | return true; | ||
217 | } else if (ASIC_IS_AVIVO(rdev)) { | ||
186 | reg = RREG32(AVIVO_D1CRTC_CONTROL) | | 218 | reg = RREG32(AVIVO_D1CRTC_CONTROL) | |
187 | RREG32(AVIVO_D2CRTC_CONTROL); | 219 | RREG32(AVIVO_D2CRTC_CONTROL); |
188 | if (reg & AVIVO_CRTC_EN) { | 220 | if (reg & AVIVO_CRTC_EN) { |
@@ -229,6 +261,8 @@ bool radeon_boot_test_post_card(struct radeon_device *rdev) | |||
229 | 261 | ||
230 | int radeon_dummy_page_init(struct radeon_device *rdev) | 262 | int radeon_dummy_page_init(struct radeon_device *rdev) |
231 | { | 263 | { |
264 | if (rdev->dummy_page.page) | ||
265 | return 0; | ||
232 | rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO); | 266 | rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO); |
233 | if (rdev->dummy_page.page == NULL) | 267 | if (rdev->dummy_page.page == NULL) |
234 | return -ENOMEM; | 268 | return -ENOMEM; |
@@ -310,7 +344,7 @@ void radeon_register_accessor_init(struct radeon_device *rdev) | |||
310 | rdev->mc_rreg = &rs600_mc_rreg; | 344 | rdev->mc_rreg = &rs600_mc_rreg; |
311 | rdev->mc_wreg = &rs600_mc_wreg; | 345 | rdev->mc_wreg = &rs600_mc_wreg; |
312 | } | 346 | } |
313 | if (rdev->family >= CHIP_R600) { | 347 | if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) { |
314 | rdev->pciep_rreg = &r600_pciep_rreg; | 348 | rdev->pciep_rreg = &r600_pciep_rreg; |
315 | rdev->pciep_wreg = &r600_pciep_wreg; | 349 | rdev->pciep_wreg = &r600_pciep_wreg; |
316 | } | 350 | } |
@@ -329,21 +363,22 @@ int radeon_asic_init(struct radeon_device *rdev) | |||
329 | case CHIP_RS100: | 363 | case CHIP_RS100: |
330 | case CHIP_RV200: | 364 | case CHIP_RV200: |
331 | case CHIP_RS200: | 365 | case CHIP_RS200: |
366 | rdev->asic = &r100_asic; | ||
367 | break; | ||
332 | case CHIP_R200: | 368 | case CHIP_R200: |
333 | case CHIP_RV250: | 369 | case CHIP_RV250: |
334 | case CHIP_RS300: | 370 | case CHIP_RS300: |
335 | case CHIP_RV280: | 371 | case CHIP_RV280: |
336 | rdev->asic = &r100_asic; | 372 | rdev->asic = &r200_asic; |
337 | break; | 373 | break; |
338 | case CHIP_R300: | 374 | case CHIP_R300: |
339 | case CHIP_R350: | 375 | case CHIP_R350: |
340 | case CHIP_RV350: | 376 | case CHIP_RV350: |
341 | case CHIP_RV380: | 377 | case CHIP_RV380: |
342 | rdev->asic = &r300_asic; | 378 | if (rdev->flags & RADEON_IS_PCIE) |
343 | if (rdev->flags & RADEON_IS_PCIE) { | 379 | rdev->asic = &r300_asic_pcie; |
344 | rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; | 380 | else |
345 | rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; | 381 | rdev->asic = &r300_asic; |
346 | } | ||
347 | break; | 382 | break; |
348 | case CHIP_R420: | 383 | case CHIP_R420: |
349 | case CHIP_R423: | 384 | case CHIP_R423: |
@@ -387,6 +422,13 @@ int radeon_asic_init(struct radeon_device *rdev) | |||
387 | case CHIP_RV740: | 422 | case CHIP_RV740: |
388 | rdev->asic = &rv770_asic; | 423 | rdev->asic = &rv770_asic; |
389 | break; | 424 | break; |
425 | case CHIP_CEDAR: | ||
426 | case CHIP_REDWOOD: | ||
427 | case CHIP_JUNIPER: | ||
428 | case CHIP_CYPRESS: | ||
429 | case CHIP_HEMLOCK: | ||
430 | rdev->asic = &evergreen_asic; | ||
431 | break; | ||
390 | default: | 432 | default: |
391 | /* FIXME: not supported yet */ | 433 | /* FIXME: not supported yet */ |
392 | return -EINVAL; | 434 | return -EINVAL; |
@@ -638,11 +680,14 @@ int radeon_device_init(struct radeon_device *rdev, | |||
638 | mutex_init(&rdev->cs_mutex); | 680 | mutex_init(&rdev->cs_mutex); |
639 | mutex_init(&rdev->ib_pool.mutex); | 681 | mutex_init(&rdev->ib_pool.mutex); |
640 | mutex_init(&rdev->cp.mutex); | 682 | mutex_init(&rdev->cp.mutex); |
683 | mutex_init(&rdev->dc_hw_i2c_mutex); | ||
641 | if (rdev->family >= CHIP_R600) | 684 | if (rdev->family >= CHIP_R600) |
642 | spin_lock_init(&rdev->ih.lock); | 685 | spin_lock_init(&rdev->ih.lock); |
643 | mutex_init(&rdev->gem.mutex); | 686 | mutex_init(&rdev->gem.mutex); |
687 | mutex_init(&rdev->pm.mutex); | ||
644 | rwlock_init(&rdev->fence_drv.lock); | 688 | rwlock_init(&rdev->fence_drv.lock); |
645 | INIT_LIST_HEAD(&rdev->gem.objects); | 689 | INIT_LIST_HEAD(&rdev->gem.objects); |
690 | init_waitqueue_head(&rdev->irq.vblank_queue); | ||
646 | 691 | ||
647 | /* setup workqueue */ | 692 | /* setup workqueue */ |
648 | rdev->wq = create_workqueue("radeon"); | 693 | rdev->wq = create_workqueue("radeon"); |