diff options
author | Corbin Simpson <MostAwesomeDude@gmail.com> | 2010-01-06 13:28:48 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-01-07 22:09:46 -0500 |
commit | 62cdc0c20663ef840a94850892517b2b7f584904 (patch) | |
tree | bbd68626995863c9c91bef7c146dc13ba5a0d887 /drivers/gpu | |
parent | 06b6476d6b291473d0928ed242158a001d50c0f0 (diff) |
drm/radeon/kms: Workaround RV410/R420 CP errata (V3)
Long story short, this fixes sporadic hardlocks with my rv410 during
times of intense 2D acceleration (Flash on Fx3).
V2: Fix indentation and move errata_fini to suspend function so we
don't leak scratch register over suspend/resume cycle.
V3: Move scratch_reg to asic specific structure (aim is to slowly
move stuff to asic specific structure and avoid poluting
radeon_device struct with asic specific variables)
Signed-off-by: Corbin Simpson <MostAwesomeDude@gmail.com>
Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/radeon/r420.c | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 1 |
2 files changed, 32 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index c05a7270cf0c..f46502a253ec 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "radeon_reg.h" | 30 | #include "radeon_reg.h" |
31 | #include "radeon.h" | 31 | #include "radeon.h" |
32 | #include "atom.h" | 32 | #include "atom.h" |
33 | #include "r100d.h" | ||
33 | #include "r420d.h" | 34 | #include "r420d.h" |
34 | 35 | ||
35 | int r420_mc_init(struct radeon_device *rdev) | 36 | int r420_mc_init(struct radeon_device *rdev) |
@@ -165,6 +166,34 @@ static void r420_clock_resume(struct radeon_device *rdev) | |||
165 | WREG32_PLL(R_00000D_SCLK_CNTL, sclk_cntl); | 166 | WREG32_PLL(R_00000D_SCLK_CNTL, sclk_cntl); |
166 | } | 167 | } |
167 | 168 | ||
169 | static void r420_cp_errata_init(struct radeon_device *rdev) | ||
170 | { | ||
171 | /* RV410 and R420 can lock up if CP DMA to host memory happens | ||
172 | * while the 2D engine is busy. | ||
173 | * | ||
174 | * The proper workaround is to queue a RESYNC at the beginning | ||
175 | * of the CP init, apparently. | ||
176 | */ | ||
177 | radeon_scratch_get(rdev, &rdev->config.r300.resync_scratch); | ||
178 | radeon_ring_lock(rdev, 8); | ||
179 | radeon_ring_write(rdev, PACKET0(R300_CP_RESYNC_ADDR, 1)); | ||
180 | radeon_ring_write(rdev, rdev->config.r300.resync_scratch); | ||
181 | radeon_ring_write(rdev, 0xDEADBEEF); | ||
182 | radeon_ring_unlock_commit(rdev); | ||
183 | } | ||
184 | |||
185 | static void r420_cp_errata_fini(struct radeon_device *rdev) | ||
186 | { | ||
187 | /* Catch the RESYNC we dispatched all the way back, | ||
188 | * at the very beginning of the CP init. | ||
189 | */ | ||
190 | radeon_ring_lock(rdev, 8); | ||
191 | radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); | ||
192 | radeon_ring_write(rdev, R300_RB3D_DC_FINISH); | ||
193 | radeon_ring_unlock_commit(rdev); | ||
194 | radeon_scratch_free(rdev, rdev->config.r300.resync_scratch); | ||
195 | } | ||
196 | |||
168 | static int r420_startup(struct radeon_device *rdev) | 197 | static int r420_startup(struct radeon_device *rdev) |
169 | { | 198 | { |
170 | int r; | 199 | int r; |
@@ -196,6 +225,7 @@ static int r420_startup(struct radeon_device *rdev) | |||
196 | dev_err(rdev->dev, "failled initializing CP (%d).\n", r); | 225 | dev_err(rdev->dev, "failled initializing CP (%d).\n", r); |
197 | return r; | 226 | return r; |
198 | } | 227 | } |
228 | r420_cp_errata_init(rdev); | ||
199 | r = r100_wb_init(rdev); | 229 | r = r100_wb_init(rdev); |
200 | if (r) { | 230 | if (r) { |
201 | dev_err(rdev->dev, "failled initializing WB (%d).\n", r); | 231 | dev_err(rdev->dev, "failled initializing WB (%d).\n", r); |
@@ -238,6 +268,7 @@ int r420_resume(struct radeon_device *rdev) | |||
238 | 268 | ||
239 | int r420_suspend(struct radeon_device *rdev) | 269 | int r420_suspend(struct radeon_device *rdev) |
240 | { | 270 | { |
271 | r420_cp_errata_fini(rdev); | ||
241 | r100_cp_disable(rdev); | 272 | r100_cp_disable(rdev); |
242 | r100_wb_disable(rdev); | 273 | r100_wb_disable(rdev); |
243 | r100_irq_disable(rdev); | 274 | r100_irq_disable(rdev); |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a7e349dc4b97..cee8bdc6c9ff 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -674,6 +674,7 @@ struct r100_asic { | |||
674 | struct r300_asic { | 674 | struct r300_asic { |
675 | const unsigned *reg_safe_bm; | 675 | const unsigned *reg_safe_bm; |
676 | unsigned reg_safe_bm_size; | 676 | unsigned reg_safe_bm_size; |
677 | u32 resync_scratch; | ||
677 | }; | 678 | }; |
678 | 679 | ||
679 | struct r600_asic { | 680 | struct r600_asic { |