From 225758d8ba4fdcc1e8c9cf617fd89529bd4a9596 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 9 Mar 2010 14:45:10 +0000 Subject: drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 This patch cleanup the fence code, it drops the timeout field of fence as the time to complete each IB is unpredictable and shouldn't be bound. The fence cleanup lead to GPU lockup detection improvement, this patch introduce a callback, allowing to do asic specific test for lockup detection. In this patch the CP is use as a first indicator of GPU lockup. If CP doesn't make progress during 1second we assume we are facing a GPU lockup. To avoid overhead of testing GPU lockup frequently due to fence taking time to be signaled we query the lockup callback every 500msec. There is plenty code comment explaining the design & choise inside the code. This have been tested mostly on R3XX/R5XX hw, in normal running destkop (compiz firefox, quake3 running) the lockup callback wasn't call once (1 hour session). Also tested with forcing GPU lockup and lockup was reported after the 1s CP activity timeout. V2 switch to 500ms timeout so GPU lockup get call at least 2 times in less than 2sec. V3 store last jiffies in fence struct so on ERESTART, EBUSY we keep track of how long we already wait for a given fence V4 make sure we got up to date cp read pointer so we don't have false positive Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 5509354c7c8..a09c062df4d 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -784,7 +784,7 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) dev_info(rdev->dev, " R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp); WREG32(R_008020_GRBM_SOFT_RESET, tmp); (void)RREG32(R_008020_GRBM_SOFT_RESET); - udelay(50); + mdelay(1); WREG32(R_008020_GRBM_SOFT_RESET, 0); (void)RREG32(R_008020_GRBM_SOFT_RESET); } @@ -824,16 +824,16 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) dev_info(rdev->dev, " R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset); WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); (void)RREG32(R_000E60_SRBM_SOFT_RESET); - udelay(50); + mdelay(1); WREG32(R_000E60_SRBM_SOFT_RESET, 0); (void)RREG32(R_000E60_SRBM_SOFT_RESET); WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); (void)RREG32(R_000E60_SRBM_SOFT_RESET); - udelay(50); + mdelay(1); WREG32(R_000E60_SRBM_SOFT_RESET, 0); (void)RREG32(R_000E60_SRBM_SOFT_RESET); /* Wait a little for things to settle down */ - udelay(50); + mdelay(1); dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n", RREG32(R_008010_GRBM_STATUS)); dev_info(rdev->dev, " R_008014_GRBM_STATUS2=0x%08X\n", @@ -848,6 +848,32 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) return 0; } +bool r600_gpu_is_lockup(struct radeon_device *rdev) +{ + u32 srbm_status; + u32 grbm_status; + u32 grbm_status2; + int r; + + srbm_status = RREG32(R_000E50_SRBM_STATUS); + grbm_status = RREG32(R_008010_GRBM_STATUS); + grbm_status2 = RREG32(R_008014_GRBM_STATUS2); + if (!G_008010_GUI_ACTIVE(grbm_status)) { + r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp); + return false; + } + /* force CP activities */ + r = radeon_ring_lock(rdev, 2); + if (!r) { + /* PACKET2 NOP */ + radeon_ring_write(rdev, 0x80000000); + radeon_ring_write(rdev, 0x80000000); + radeon_ring_unlock_commit(rdev); + } + rdev->cp.rptr = RREG32(R600_CP_RB_RPTR); + return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); +} + int r600_gpu_reset(struct radeon_device *rdev) { return r600_gpu_soft_reset(rdev); -- cgit v1.2.3-70-g09d2 From a2d07b7438f015a0349bc9af3c96a8164549bbc5 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 9 Mar 2010 14:45:11 +0000 Subject: drm/radeon/kms: rename gpu_reset to asic_reset Patch rename gpu_reset to asic_reset in prevision of having gpu_reset doing more stuff than just basic asic reset. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 2 +- drivers/gpu/drm/radeon/r100.c | 6 +++--- drivers/gpu/drm/radeon/r300.c | 6 +++--- drivers/gpu/drm/radeon/r420.c | 4 ++-- drivers/gpu/drm/radeon/r520.c | 4 ++-- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 6 +++--- drivers/gpu/drm/radeon/radeon_asic.c | 28 ++++++++++++++-------------- drivers/gpu/drm/radeon/radeon_asic.h | 10 +++++----- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/gpu/drm/radeon/radeon_fence.c | 2 +- drivers/gpu/drm/radeon/rs400.c | 4 ++-- drivers/gpu/drm/radeon/rs600.c | 4 ++-- drivers/gpu/drm/radeon/rs690.c | 4 ++-- drivers/gpu/drm/radeon/rv515.c | 8 ++++---- 15 files changed, 46 insertions(+), 46 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3070e599412..7672f11ed99 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -492,7 +492,7 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev) return false; } -int evergreen_gpu_reset(struct radeon_device *rdev) +int evergreen_asic_reset(struct radeon_device *rdev) { /* FIXME: implement for evergreen */ return 0; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 845c8f3063f..8bb91092bff 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -1863,7 +1863,7 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev) return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp); } -int r100_gpu_reset(struct radeon_device *rdev) +int r100_asic_reset(struct radeon_device *rdev) { uint32_t status; @@ -3512,7 +3512,7 @@ int r100_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ r100_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -3581,7 +3581,7 @@ int r100_init(struct radeon_device *rdev) return r; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 9825fb19331..7d5de5dbde2 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -449,7 +449,7 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev) return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); } -int r300_gpu_reset(struct radeon_device *rdev) +int r300_asic_reset(struct radeon_device *rdev) { uint32_t status; @@ -1333,7 +1333,7 @@ int r300_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ r300_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -1404,7 +1404,7 @@ int r300_init(struct radeon_device *rdev) return r; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 0b8603ca697..061553aa7a0 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -234,7 +234,7 @@ int r420_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ r420_clock_resume(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -315,7 +315,7 @@ int r420_init(struct radeon_device *rdev) } } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 3c44b8d3931..3ade473e69b 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -209,7 +209,7 @@ int r520_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ rv515_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -246,7 +246,7 @@ int r520_init(struct radeon_device *rdev) return -EINVAL; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index a09c062df4d..24fd5459fb4 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -874,7 +874,7 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev) return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); } -int r600_gpu_reset(struct radeon_device *rdev) +int r600_asic_reset(struct radeon_device *rdev) { return r600_gpu_soft_reset(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a3d13c36717..3cc5820b0e1 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -748,7 +748,7 @@ struct radeon_asic { int (*suspend)(struct radeon_device *rdev); void (*vga_set_state)(struct radeon_device *rdev, bool state); bool (*gpu_is_lockup)(struct radeon_device *rdev); - int (*gpu_reset)(struct radeon_device *rdev); + int (*asic_reset)(struct radeon_device *rdev); void (*gart_tlb_flush)(struct radeon_device *rdev); int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr); int (*cp_init)(struct radeon_device *rdev, unsigned ring_size); @@ -1157,7 +1157,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_cs_parse(p) rdev->asic->cs_parse((p)) #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) #define radeon_gpu_is_lockup(rdev) (rdev)->asic->gpu_is_lockup((rdev)) -#define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev)) +#define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev)) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev)) #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p)) #define radeon_cp_commit(rdev) (rdev)->asic->cp_commit((rdev)) @@ -1290,7 +1290,7 @@ extern void r600_scratch_init(struct radeon_device *rdev); extern int r600_blit_init(struct radeon_device *rdev); extern void r600_blit_fini(struct radeon_device *rdev); extern int r600_init_microcode(struct radeon_device *rdev); -extern int r600_gpu_reset(struct radeon_device *rdev); +extern int r600_asic_reset(struct radeon_device *rdev); /* r600 irq */ extern int r600_irq_init(struct radeon_device *rdev); extern void r600_irq_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 7e21985139f..011ac6d8658 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -135,7 +135,7 @@ static struct radeon_asic r100_asic = { .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r100_gpu_is_lockup, - .gpu_reset = &r100_gpu_reset, + .asic_reset = &r100_asic_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, .cp_commit = &r100_cp_commit, @@ -174,7 +174,7 @@ static struct radeon_asic r200_asic = { .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r100_gpu_is_lockup, - .gpu_reset = &r100_gpu_reset, + .asic_reset = &r100_asic_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, .cp_commit = &r100_cp_commit, @@ -212,7 +212,7 @@ static struct radeon_asic r300_asic = { .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, .cp_commit = &r100_cp_commit, @@ -251,7 +251,7 @@ static struct radeon_asic r300_asic_pcie = { .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -289,7 +289,7 @@ static struct radeon_asic r420_asic = { .resume = &r420_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -328,7 +328,7 @@ static struct radeon_asic rs400_asic = { .resume = &rs400_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rs400_gart_tlb_flush, .gart_set_page = &rs400_gart_set_page, .cp_commit = &r100_cp_commit, @@ -367,7 +367,7 @@ static struct radeon_asic rs600_asic = { .resume = &rs600_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rs600_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .cp_commit = &r100_cp_commit, @@ -406,7 +406,7 @@ static struct radeon_asic rs690_asic = { .resume = &rs690_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rs400_gart_tlb_flush, .gart_set_page = &rs400_gart_set_page, .cp_commit = &r100_cp_commit, @@ -445,7 +445,7 @@ static struct radeon_asic rv515_asic = { .resume = &rv515_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &rv515_gpu_reset, + .asic_reset = &rv515_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -484,7 +484,7 @@ static struct radeon_asic r520_asic = { .resume = &r520_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &rv515_gpu_reset, + .asic_reset = &rv515_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -524,7 +524,7 @@ static struct radeon_asic r600_asic = { .cp_commit = &r600_cp_commit, .vga_set_state = &r600_vga_set_state, .gpu_is_lockup = &r600_gpu_is_lockup, - .gpu_reset = &r600_gpu_reset, + .asic_reset = &r600_asic_reset, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, @@ -561,7 +561,7 @@ static struct radeon_asic rs780_asic = { .resume = &r600_resume, .cp_commit = &r600_cp_commit, .vga_set_state = &r600_vga_set_state, - .gpu_reset = &r600_gpu_reset, + .asic_reset = &r600_asic_reset, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, @@ -597,7 +597,7 @@ static struct radeon_asic rv770_asic = { .suspend = &rv770_suspend, .resume = &rv770_resume, .cp_commit = &r600_cp_commit, - .gpu_reset = &r600_gpu_reset, + .asic_reset = &r600_asic_reset, .gpu_is_lockup = &r600_gpu_is_lockup, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, @@ -636,7 +636,7 @@ static struct radeon_asic evergreen_asic = { .resume = &evergreen_resume, .cp_commit = NULL, .gpu_is_lockup = &evergreen_gpu_is_lockup, - .gpu_reset = &evergreen_gpu_reset, + .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index ce2f3e4f081..53ebcacbd0e 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -61,7 +61,7 @@ uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg); void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void r100_vga_set_state(struct radeon_device *rdev, bool state); bool r100_gpu_is_lockup(struct radeon_device *rdev); -int r100_gpu_reset(struct radeon_device *rdev); +int r100_asic_reset(struct radeon_device *rdev); u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc); void r100_pci_gart_tlb_flush(struct radeon_device *rdev); int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); @@ -145,7 +145,7 @@ extern void r300_fini(struct radeon_device *rdev); extern int r300_suspend(struct radeon_device *rdev); extern int r300_resume(struct radeon_device *rdev); extern bool r300_gpu_is_lockup(struct radeon_device *rdev); -extern int r300_gpu_reset(struct radeon_device *rdev); +extern int r300_asic_reset(struct radeon_device *rdev); extern void r300_ring_start(struct radeon_device *rdev); extern void r300_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence); @@ -214,7 +214,7 @@ void rs690_bandwidth_update(struct radeon_device *rdev); */ int rv515_init(struct radeon_device *rdev); void rv515_fini(struct radeon_device *rdev); -int rv515_gpu_reset(struct radeon_device *rdev); +int rv515_asic_reset(struct radeon_device *rdev); uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rv515_ring_start(struct radeon_device *rdev); @@ -255,7 +255,7 @@ int r600_copy_dma(struct radeon_device *rdev, int r600_irq_process(struct radeon_device *rdev); int r600_irq_set(struct radeon_device *rdev); bool r600_gpu_is_lockup(struct radeon_device *rdev); -int r600_gpu_reset(struct radeon_device *rdev); +int r600_asic_reset(struct radeon_device *rdev); int r600_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, uint32_t offset, uint32_t obj_size); @@ -288,7 +288,7 @@ void evergreen_fini(struct radeon_device *rdev); int evergreen_suspend(struct radeon_device *rdev); int evergreen_resume(struct radeon_device *rdev); bool evergreen_gpu_is_lockup(struct radeon_device *rdev); -int evergreen_gpu_reset(struct radeon_device *rdev); +int evergreen_asic_reset(struct radeon_device *rdev); void evergreen_bandwidth_update(struct radeon_device *rdev); void evergreen_hpd_init(struct radeon_device *rdev); void evergreen_hpd_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 60ec47b7164..232a3076849 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -619,7 +619,7 @@ int radeon_device_init(struct radeon_device *rdev, /* Acceleration not working on AGP card try again * with fallback to PCI or PCIE GART */ - radeon_gpu_reset(rdev); + radeon_asic_reset(rdev); radeon_fini(rdev); radeon_agp_disable(rdev); r = radeon_init(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 393154268de..2560740ff92 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -231,7 +231,7 @@ retry: if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) { /* good news we believe it's a lockup */ dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq); - r = radeon_gpu_reset(rdev); + r = radeon_asic_reset(rdev); if (r) return r; /* FIXME: what should we do ? marking everyone diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 626aaf082b1..3deec218508 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -432,7 +432,7 @@ int rs400_resume(struct radeon_device *rdev) /* setup MC before calling post tables */ rs400_mc_program(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -496,7 +496,7 @@ int rs400_init(struct radeon_device *rdev) return r; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index abf824c2123..c1be20afd42 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -601,7 +601,7 @@ int rs600_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ rv515_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -664,7 +664,7 @@ int rs600_init(struct radeon_device *rdev) return -EINVAL; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index bbf3da790fd..ef35e0468f1 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -653,7 +653,7 @@ int rs690_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ rv515_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -717,7 +717,7 @@ int rs690_init(struct radeon_device *rdev) return -EINVAL; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 1cf233f7e51..2a4c01f5cf1 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -227,7 +227,7 @@ int rv515_ga_reset(struct radeon_device *rdev) return -1; } -int rv515_gpu_reset(struct radeon_device *rdev) +int rv515_asic_reset(struct radeon_device *rdev) { uint32_t status; @@ -334,7 +334,7 @@ static int rv515_debugfs_ga_info(struct seq_file *m, void *data) tmp = RREG32(0x2140); seq_printf(m, "VAP_CNTL_STATUS 0x%08x\n", tmp); - radeon_gpu_reset(rdev); + radeon_asic_reset(rdev); tmp = RREG32(0x425C); seq_printf(m, "GA_IDLE 0x%08x\n", tmp); return 0; @@ -502,7 +502,7 @@ int rv515_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ rv515_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -572,7 +572,7 @@ int rv515_init(struct radeon_device *rdev) return -EINVAL; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), -- cgit v1.2.3-70-g09d2 From 90aca4d2740255bd130ea71a91530b9920c70abe Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 9 Mar 2010 14:45:12 +0000 Subject: drm/radeon/kms: simplify & improve GPU reset V2 This simplify and improve GPU reset for R1XX-R6XX hw, it's not 100% reliable here are result: - R1XX/R2XX works bunch of time in a row, sometimes it seems it can work indifinitly - R3XX/R3XX the most unreliable one, sometimes you will be able to reset few times, sometimes not even once - R5XX more reliable than previous hw, seems to work most of the times but once in a while it fails for no obvious reasons (same status than previous reset just no same happy ending) - R6XX/R7XX are lot more reliable with this patch, still it seems that it can fail after a bunch (reset every 2sec for 3hour bring down the GPU & computer) This have been tested on various hw, for some odd reasons i wasn't able to lockup RS480/RS690 (while they use to love locking up). Note that on R1XX-R5XX the cursor will disapear after lockup haven't checked why, switch to console and back to X will restore cursor. Next step is to record the bogus command that leaded to the lockup. V2 Fix r6xx resume path to avoid reinitializing blit module, use the gpu_lockup boolean to avoid entering inifinite waiting loop on fence while reiniting the GPU Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 180 ++++++++++++--------------------- drivers/gpu/drm/radeon/r100d.h | 128 +++++++++++++++++++++++ drivers/gpu/drm/radeon/r300.c | 134 +++++++++++------------- drivers/gpu/drm/radeon/r300d.h | 47 ++++++++- drivers/gpu/drm/radeon/r520.c | 1 - drivers/gpu/drm/radeon/r600.c | 53 +--------- drivers/gpu/drm/radeon/r600_blit_kms.c | 3 + drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_asic.c | 9 +- drivers/gpu/drm/radeon/radeon_asic.h | 6 +- drivers/gpu/drm/radeon/radeon_cs.c | 4 - drivers/gpu/drm/radeon/radeon_device.c | 22 ++++ drivers/gpu/drm/radeon/radeon_fence.c | 13 ++- drivers/gpu/drm/radeon/radeon_gart.c | 2 +- drivers/gpu/drm/radeon/rs400.c | 2 - drivers/gpu/drm/radeon/rs600.c | 73 ++++++++++++- drivers/gpu/drm/radeon/rs600d.h | 46 +++++++++ drivers/gpu/drm/radeon/rs690.c | 2 - drivers/gpu/drm/radeon/rv515.c | 90 ----------------- drivers/gpu/drm/radeon/rv515d.h | 46 +++++++++ 20 files changed, 508 insertions(+), 354 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 8bb91092bff..7a4a4fc276b 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -662,26 +662,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) if (r100_debugfs_cp_init(rdev)) { DRM_ERROR("Failed to register debugfs file for CP !\n"); } - /* Reset CP */ - tmp = RREG32(RADEON_CP_CSQ_STAT); - if ((tmp & (1 << 31))) { - DRM_INFO("radeon: cp busy (0x%08X) resetting\n", tmp); - WREG32(RADEON_CP_CSQ_MODE, 0); - WREG32(RADEON_CP_CSQ_CNTL, 0); - WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP); - tmp = RREG32(RADEON_RBBM_SOFT_RESET); - mdelay(2); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - tmp = RREG32(RADEON_RBBM_SOFT_RESET); - mdelay(2); - tmp = RREG32(RADEON_CP_CSQ_STAT); - if ((tmp & (1 << 31))) { - DRM_INFO("radeon: cp reset failed (0x%08X)\n", tmp); - } - } else { - DRM_INFO("radeon: cp idle (0x%08X)\n", tmp); - } - if (!rdev->me_fw) { r = r100_cp_init_microcode(rdev); if (r) { @@ -786,39 +766,6 @@ void r100_cp_disable(struct radeon_device *rdev) } } -int r100_cp_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - bool reinit_cp; - int i; - - reinit_cp = rdev->cp.ready; - rdev->cp.ready = false; - WREG32(RADEON_CP_CSQ_MODE, 0); - WREG32(RADEON_CP_CSQ_CNTL, 0); - WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP); - (void)RREG32(RADEON_RBBM_SOFT_RESET); - udelay(200); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RADEON_RBBM_STATUS); - if (!(tmp & (1 << 16))) { - DRM_INFO("CP reset succeed (RBBM_STATUS=0x%08X)\n", - tmp); - if (reinit_cp) { - return r100_cp_init(rdev, rdev->cp.ring_size); - } - return 0; - } - DRM_UDELAY(1); - } - tmp = RREG32(RADEON_RBBM_STATUS); - DRM_ERROR("Failed to reset CP (RBBM_STATUS=0x%08X)!\n", tmp); - return -1; -} - void r100_cp_commit(struct radeon_device *rdev) { WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr); @@ -1732,51 +1679,6 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev) return -1; } -void r100_gpu_init(struct radeon_device *rdev) -{ - /* TODO: anythings to do here ? pipes ? */ - r100_hdp_reset(rdev); -} - -void r100_hdp_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - - tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL; - tmp |= (7 << 28); - WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE); - (void)RREG32(RADEON_HOST_PATH_CNTL); - udelay(200); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - WREG32(RADEON_HOST_PATH_CNTL, tmp); - (void)RREG32(RADEON_HOST_PATH_CNTL); -} - -int r100_rb2d_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - int i; - - WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_E2); - (void)RREG32(RADEON_RBBM_SOFT_RESET); - udelay(200); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RADEON_RBBM_STATUS); - if (!(tmp & (1 << 26))) { - DRM_INFO("RB2D reset succeed (RBBM_STATUS=0x%08X)\n", - tmp); - return 0; - } - DRM_UDELAY(1); - } - tmp = RREG32(RADEON_RBBM_STATUS); - DRM_ERROR("Failed to reset RB2D (RBBM_STATUS=0x%08X)!\n", tmp); - return -1; -} - void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp) { lockup->last_cp_rptr = cp->rptr; @@ -1863,31 +1765,77 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev) return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp); } +void r100_bm_disable(struct radeon_device *rdev) +{ + u32 tmp; + + /* disable bus mastering */ + tmp = RREG32(R_000030_BUS_CNTL); + WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000044); + mdelay(1); + WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000042); + mdelay(1); + WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); + tmp = RREG32(RADEON_BUS_CNTL); + mdelay(1); + pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp); + pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); + mdelay(1); +} + int r100_asic_reset(struct radeon_device *rdev) { - uint32_t status; + struct r100_mc_save save; + u32 status, tmp; - /* reset order likely matter */ - status = RREG32(RADEON_RBBM_STATUS); - /* reset HDP */ - r100_hdp_reset(rdev); - /* reset rb2d */ - if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { - r100_rb2d_reset(rdev); + r100_mc_stop(rdev, &save); + status = RREG32(R_000E40_RBBM_STATUS); + if (!G_000E40_GUI_ACTIVE(status)) { + return 0; } - /* TODO: reset 3D engine */ + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* stop CP */ + WREG32(RADEON_CP_CSQ_CNTL, 0); + tmp = RREG32(RADEON_CP_RB_CNTL); + WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); + WREG32(RADEON_CP_RB_RPTR_WR, 0); + WREG32(RADEON_CP_RB_WPTR, 0); + WREG32(RADEON_CP_RB_CNTL, tmp); + /* save PCI state */ + pci_save_state(rdev->pdev); + /* disable bus mastering */ + r100_bm_disable(rdev); + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_SE(1) | + S_0000F0_SOFT_RESET_RE(1) | + S_0000F0_SOFT_RESET_PP(1) | + S_0000F0_SOFT_RESET_RB(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* reset CP */ - status = RREG32(RADEON_RBBM_STATUS); - if (status & (1 << 16)) { - r100_cp_reset(rdev); - } + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* restore PCI & busmastering */ + pci_restore_state(rdev->pdev); + r100_enable_bm(rdev); /* Check if GPU is idle */ - status = RREG32(RADEON_RBBM_STATUS); - if (status & RADEON_RBBM_ACTIVE) { - DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); + if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) || + G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) { + dev_err(rdev->dev, "failed to reset GPU\n"); + rdev->gpu_lockup = true; return -1; } - DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); + r100_mc_resume(rdev, &save); + dev_info(rdev->dev, "GPU reset succeed\n"); return 0; } @@ -3475,7 +3423,7 @@ static int r100_startup(struct radeon_device *rdev) /* Resume clock */ r100_clock_startup(rdev); /* Initialize GPU configuration (# pipes, ...) */ - r100_gpu_init(rdev); +// r100_gpu_init(rdev); /* Initialize GART (initialize after TTM so we can allocate * memory through TTM but finalize after TTM) */ r100_enable_bm(rdev); diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h index df29a630c46..de8abd104ab 100644 --- a/drivers/gpu/drm/radeon/r100d.h +++ b/drivers/gpu/drm/radeon/r100d.h @@ -74,6 +74,134 @@ #define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) /* Registers */ +#define R_0000F0_RBBM_SOFT_RESET 0x0000F0 +#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0) +#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1) +#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE +#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1) +#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1) +#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD +#define S_0000F0_SOFT_RESET_SE(x) (((x) & 0x1) << 2) +#define G_0000F0_SOFT_RESET_SE(x) (((x) >> 2) & 0x1) +#define C_0000F0_SOFT_RESET_SE 0xFFFFFFFB +#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3) +#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1) +#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7 +#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4) +#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1) +#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF +#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5) +#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1) +#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF +#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6) +#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1) +#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF +#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7) +#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1) +#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F +#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8) +#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1) +#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF +#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9) +#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1) +#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF +#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10) +#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1) +#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF +#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11) +#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1) +#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF +#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12) +#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1) +#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF +#define R_000030_BUS_CNTL 0x000030 +#define S_000030_BUS_DBL_RESYNC(x) (((x) & 0x1) << 0) +#define G_000030_BUS_DBL_RESYNC(x) (((x) >> 0) & 0x1) +#define C_000030_BUS_DBL_RESYNC 0xFFFFFFFE +#define S_000030_BUS_MSTR_RESET(x) (((x) & 0x1) << 1) +#define G_000030_BUS_MSTR_RESET(x) (((x) >> 1) & 0x1) +#define C_000030_BUS_MSTR_RESET 0xFFFFFFFD +#define S_000030_BUS_FLUSH_BUF(x) (((x) & 0x1) << 2) +#define G_000030_BUS_FLUSH_BUF(x) (((x) >> 2) & 0x1) +#define C_000030_BUS_FLUSH_BUF 0xFFFFFFFB +#define S_000030_BUS_STOP_REQ_DIS(x) (((x) & 0x1) << 3) +#define G_000030_BUS_STOP_REQ_DIS(x) (((x) >> 3) & 0x1) +#define C_000030_BUS_STOP_REQ_DIS 0xFFFFFFF7 +#define S_000030_BUS_PM4_READ_COMBINE_EN(x) (((x) & 0x1) << 4) +#define G_000030_BUS_PM4_READ_COMBINE_EN(x) (((x) >> 4) & 0x1) +#define C_000030_BUS_PM4_READ_COMBINE_EN 0xFFFFFFEF +#define S_000030_BUS_WRT_COMBINE_EN(x) (((x) & 0x1) << 5) +#define G_000030_BUS_WRT_COMBINE_EN(x) (((x) >> 5) & 0x1) +#define C_000030_BUS_WRT_COMBINE_EN 0xFFFFFFDF +#define S_000030_BUS_MASTER_DIS(x) (((x) & 0x1) << 6) +#define G_000030_BUS_MASTER_DIS(x) (((x) >> 6) & 0x1) +#define C_000030_BUS_MASTER_DIS 0xFFFFFFBF +#define S_000030_BIOS_ROM_WRT_EN(x) (((x) & 0x1) << 7) +#define G_000030_BIOS_ROM_WRT_EN(x) (((x) >> 7) & 0x1) +#define C_000030_BIOS_ROM_WRT_EN 0xFFFFFF7F +#define S_000030_BM_DAC_CRIPPLE(x) (((x) & 0x1) << 8) +#define G_000030_BM_DAC_CRIPPLE(x) (((x) >> 8) & 0x1) +#define C_000030_BM_DAC_CRIPPLE 0xFFFFFEFF +#define S_000030_BUS_NON_PM4_READ_COMBINE_EN(x) (((x) & 0x1) << 9) +#define G_000030_BUS_NON_PM4_READ_COMBINE_EN(x) (((x) >> 9) & 0x1) +#define C_000030_BUS_NON_PM4_READ_COMBINE_EN 0xFFFFFDFF +#define S_000030_BUS_XFERD_DISCARD_EN(x) (((x) & 0x1) << 10) +#define G_000030_BUS_XFERD_DISCARD_EN(x) (((x) >> 10) & 0x1) +#define C_000030_BUS_XFERD_DISCARD_EN 0xFFFFFBFF +#define S_000030_BUS_SGL_READ_DISABLE(x) (((x) & 0x1) << 11) +#define G_000030_BUS_SGL_READ_DISABLE(x) (((x) >> 11) & 0x1) +#define C_000030_BUS_SGL_READ_DISABLE 0xFFFFF7FF +#define S_000030_BIOS_DIS_ROM(x) (((x) & 0x1) << 12) +#define G_000030_BIOS_DIS_ROM(x) (((x) >> 12) & 0x1) +#define C_000030_BIOS_DIS_ROM 0xFFFFEFFF +#define S_000030_BUS_PCI_READ_RETRY_EN(x) (((x) & 0x1) << 13) +#define G_000030_BUS_PCI_READ_RETRY_EN(x) (((x) >> 13) & 0x1) +#define C_000030_BUS_PCI_READ_RETRY_EN 0xFFFFDFFF +#define S_000030_BUS_AGP_AD_STEPPING_EN(x) (((x) & 0x1) << 14) +#define G_000030_BUS_AGP_AD_STEPPING_EN(x) (((x) >> 14) & 0x1) +#define C_000030_BUS_AGP_AD_STEPPING_EN 0xFFFFBFFF +#define S_000030_BUS_PCI_WRT_RETRY_EN(x) (((x) & 0x1) << 15) +#define G_000030_BUS_PCI_WRT_RETRY_EN(x) (((x) >> 15) & 0x1) +#define C_000030_BUS_PCI_WRT_RETRY_EN 0xFFFF7FFF +#define S_000030_BUS_RETRY_WS(x) (((x) & 0xF) << 16) +#define G_000030_BUS_RETRY_WS(x) (((x) >> 16) & 0xF) +#define C_000030_BUS_RETRY_WS 0xFFF0FFFF +#define S_000030_BUS_MSTR_RD_MULT(x) (((x) & 0x1) << 20) +#define G_000030_BUS_MSTR_RD_MULT(x) (((x) >> 20) & 0x1) +#define C_000030_BUS_MSTR_RD_MULT 0xFFEFFFFF +#define S_000030_BUS_MSTR_RD_LINE(x) (((x) & 0x1) << 21) +#define G_000030_BUS_MSTR_RD_LINE(x) (((x) >> 21) & 0x1) +#define C_000030_BUS_MSTR_RD_LINE 0xFFDFFFFF +#define S_000030_BUS_SUSPEND(x) (((x) & 0x1) << 22) +#define G_000030_BUS_SUSPEND(x) (((x) >> 22) & 0x1) +#define C_000030_BUS_SUSPEND 0xFFBFFFFF +#define S_000030_LAT_16X(x) (((x) & 0x1) << 23) +#define G_000030_LAT_16X(x) (((x) >> 23) & 0x1) +#define C_000030_LAT_16X 0xFF7FFFFF +#define S_000030_BUS_RD_DISCARD_EN(x) (((x) & 0x1) << 24) +#define G_000030_BUS_RD_DISCARD_EN(x) (((x) >> 24) & 0x1) +#define C_000030_BUS_RD_DISCARD_EN 0xFEFFFFFF +#define S_000030_ENFRCWRDY(x) (((x) & 0x1) << 25) +#define G_000030_ENFRCWRDY(x) (((x) >> 25) & 0x1) +#define C_000030_ENFRCWRDY 0xFDFFFFFF +#define S_000030_BUS_MSTR_WS(x) (((x) & 0x1) << 26) +#define G_000030_BUS_MSTR_WS(x) (((x) >> 26) & 0x1) +#define C_000030_BUS_MSTR_WS 0xFBFFFFFF +#define S_000030_BUS_PARKING_DIS(x) (((x) & 0x1) << 27) +#define G_000030_BUS_PARKING_DIS(x) (((x) >> 27) & 0x1) +#define C_000030_BUS_PARKING_DIS 0xF7FFFFFF +#define S_000030_BUS_MSTR_DISCONNECT_EN(x) (((x) & 0x1) << 28) +#define G_000030_BUS_MSTR_DISCONNECT_EN(x) (((x) >> 28) & 0x1) +#define C_000030_BUS_MSTR_DISCONNECT_EN 0xEFFFFFFF +#define S_000030_SERR_EN(x) (((x) & 0x1) << 29) +#define G_000030_SERR_EN(x) (((x) >> 29) & 0x1) +#define C_000030_SERR_EN 0xDFFFFFFF +#define S_000030_BUS_READ_BURST(x) (((x) & 0x1) << 30) +#define G_000030_BUS_READ_BURST(x) (((x) >> 30) & 0x1) +#define C_000030_BUS_READ_BURST 0xBFFFFFFF +#define S_000030_BUS_RDY_READ_DLY(x) (((x) & 0x1) << 31) +#define G_000030_BUS_RDY_READ_DLY(x) (((x) >> 31) & 0x1) +#define C_000030_BUS_RDY_READ_DLY 0x7FFFFFFF #define R_000040_GEN_INT_CNTL 0x000040 #define S_000040_CRTC_VBLANK(x) (((x) & 0x1) << 0) #define G_000040_CRTC_VBLANK(x) (((x) >> 0) & 0x1) diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 7d5de5dbde2..199110ef8df 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -151,6 +151,10 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) u32 tmp; int r; + WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); @@ -323,7 +327,6 @@ void r300_gpu_init(struct radeon_device *rdev) { uint32_t gb_tile_config, tmp; - r100_hdp_reset(rdev); /* FIXME: rv380 one pipes ? */ if ((rdev->family == CHIP_R300 && rdev->pdev->device != 0x4144) || (rdev->family == CHIP_R350)) { @@ -376,57 +379,6 @@ void r300_gpu_init(struct radeon_device *rdev) rdev->num_gb_pipes, rdev->num_z_pipes); } -int r300_ga_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - bool reinit_cp; - int i; - - reinit_cp = rdev->cp.ready; - rdev->cp.ready = false; - for (i = 0; i < rdev->usec_timeout; i++) { - WREG32(RADEON_CP_CSQ_MODE, 0); - WREG32(RADEON_CP_CSQ_CNTL, 0); - WREG32(RADEON_RBBM_SOFT_RESET, 0x32005); - (void)RREG32(RADEON_RBBM_SOFT_RESET); - udelay(200); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - tmp = RREG32(RADEON_RBBM_STATUS); - if (tmp & ((1 << 20) | (1 << 26))) { - DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)", tmp); - /* GA still busy soft reset it */ - WREG32(0x429C, 0x200); - WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0); - WREG32(R300_RE_SCISSORS_TL, 0); - WREG32(R300_RE_SCISSORS_BR, 0); - WREG32(0x24AC, 0); - } - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - tmp = RREG32(RADEON_RBBM_STATUS); - if (!(tmp & ((1 << 20) | (1 << 26)))) { - break; - } - } - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RADEON_RBBM_STATUS); - if (!(tmp & ((1 << 20) | (1 << 26)))) { - DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", - tmp); - if (reinit_cp) { - return r100_cp_init(rdev, rdev->cp.ring_size); - } - return 0; - } - DRM_UDELAY(1); - } - tmp = RREG32(RADEON_RBBM_STATUS); - DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); - return -1; -} - bool r300_gpu_is_lockup(struct radeon_device *rdev) { u32 rbbm_status; @@ -451,37 +403,69 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev) int r300_asic_reset(struct radeon_device *rdev) { - uint32_t status; + struct r100_mc_save save; + u32 status, tmp; - /* reset order likely matter */ - status = RREG32(RADEON_RBBM_STATUS); - dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); - /* reset HDP */ - r100_hdp_reset(rdev); - /* reset rb2d */ - if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { - r100_rb2d_reset(rdev); - } - /* reset GA */ - if (status & ((1 << 20) | (1 << 26))) { - r300_ga_reset(rdev); - } - /* reset CP */ - status = RREG32(RADEON_RBBM_STATUS); - if (status & (1 << 16)) { - r100_cp_reset(rdev); + r100_mc_stop(rdev, &save); + status = RREG32(R_000E40_RBBM_STATUS); + if (!G_000E40_GUI_ACTIVE(status)) { + return 0; } + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* stop CP */ + WREG32(RADEON_CP_CSQ_CNTL, 0); + tmp = RREG32(RADEON_CP_RB_CNTL); + WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); + WREG32(RADEON_CP_RB_RPTR_WR, 0); + WREG32(RADEON_CP_RB_WPTR, 0); + WREG32(RADEON_CP_RB_CNTL, tmp); + /* save PCI state */ + pci_save_state(rdev->pdev); + /* disable bus mastering */ + r100_bm_disable(rdev); + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | + S_0000F0_SOFT_RESET_GA(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* resetting the CP seems to be problematic sometimes it end up + * hard locking the computer, but it's necessary for successfull + * reset more test & playing is needed on R3XX/R4XX to find a + * reliable (if any solution) + */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* reset MC */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* restore PCI & busmastering */ + pci_restore_state(rdev->pdev); + r100_enable_bm(rdev); /* Check if GPU is idle */ - status = RREG32(RADEON_RBBM_STATUS); - if (status & RADEON_RBBM_ACTIVE) { - DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); + if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { + dev_err(rdev->dev, "failed to reset GPU\n"); + rdev->gpu_lockup = true; return -1; } - DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); + r100_mc_resume(rdev, &save); + dev_info(rdev->dev, "GPU reset succeed\n"); return 0; } - /* * r300,r350,rv350,rv380 VRAM info */ diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h index 4c73114f0de..968a33317fb 100644 --- a/drivers/gpu/drm/radeon/r300d.h +++ b/drivers/gpu/drm/radeon/r300d.h @@ -209,7 +209,52 @@ #define S_000E40_GUI_ACTIVE(x) (((x) & 0x1) << 31) #define G_000E40_GUI_ACTIVE(x) (((x) >> 31) & 0x1) #define C_000E40_GUI_ACTIVE 0x7FFFFFFF - +#define R_0000F0_RBBM_SOFT_RESET 0x0000F0 +#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0) +#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1) +#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE +#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1) +#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1) +#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD +#define S_0000F0_SOFT_RESET_VAP(x) (((x) & 0x1) << 2) +#define G_0000F0_SOFT_RESET_VAP(x) (((x) >> 2) & 0x1) +#define C_0000F0_SOFT_RESET_VAP 0xFFFFFFFB +#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3) +#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1) +#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7 +#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4) +#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1) +#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF +#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5) +#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1) +#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF +#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6) +#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1) +#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF +#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7) +#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1) +#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F +#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8) +#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1) +#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF +#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9) +#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1) +#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF +#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10) +#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1) +#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF +#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11) +#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1) +#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF +#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12) +#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1) +#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF +#define S_0000F0_SOFT_RESET_GA(x) (((x) & 0x1) << 13) +#define G_0000F0_SOFT_RESET_GA(x) (((x) >> 13) & 0x1) +#define C_0000F0_SOFT_RESET_GA 0xFFFFDFFF +#define S_0000F0_SOFT_RESET_IDCT(x) (((x) & 0x1) << 14) +#define G_0000F0_SOFT_RESET_IDCT(x) (((x) >> 14) & 0x1) +#define C_0000F0_SOFT_RESET_IDCT 0xFFFFBFFF #define R_00000D_SCLK_CNTL 0x00000D #define S_00000D_SCLK_SRC_SEL(x) (((x) & 0x7) << 0) diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 3ade473e69b..870111e26bd 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -53,7 +53,6 @@ static void r520_gpu_init(struct radeon_device *rdev) { unsigned pipe_select_current, gb_pipe_select, tmp; - r100_hdp_reset(rdev); rv515_vga_render_disable(rdev); /* * DST_PIPE_CONFIG 0x170C diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 24fd5459fb4..13c9cc34231 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -749,7 +749,6 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) S_008014_DB2_BUSY(1) | S_008014_DB3_BUSY(1) | S_008014_CB0_BUSY(1) | S_008014_CB1_BUSY(1) | S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1); - u32 srbm_reset = 0; u32 tmp; dev_info(rdev->dev, "GPU softreset \n"); @@ -764,7 +763,7 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); } /* Disable CP parsing/prefetching */ - WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(0xff)); + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); /* Check if any of the rendering block is busy and reset it */ if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) || (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) { @@ -783,55 +782,17 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) S_008020_SOFT_RESET_VGT(1); dev_info(rdev->dev, " R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp); WREG32(R_008020_GRBM_SOFT_RESET, tmp); - (void)RREG32(R_008020_GRBM_SOFT_RESET); - mdelay(1); + RREG32(R_008020_GRBM_SOFT_RESET); + mdelay(15); WREG32(R_008020_GRBM_SOFT_RESET, 0); - (void)RREG32(R_008020_GRBM_SOFT_RESET); } /* Reset CP (we always reset CP) */ tmp = S_008020_SOFT_RESET_CP(1); dev_info(rdev->dev, "R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp); WREG32(R_008020_GRBM_SOFT_RESET, tmp); - (void)RREG32(R_008020_GRBM_SOFT_RESET); - udelay(50); + RREG32(R_008020_GRBM_SOFT_RESET); + mdelay(15); WREG32(R_008020_GRBM_SOFT_RESET, 0); - (void)RREG32(R_008020_GRBM_SOFT_RESET); - /* Reset others GPU block if necessary */ - if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_RLC(1); - if (G_000E50_GRBM_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_GRBM(1); - if (G_000E50_HI_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_IH(1); - if (G_000E50_VMC_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_VMC(1); - if (G_000E50_MCB_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_MCDZ_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_MCDY_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_MCDX_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_MCDW_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_RLC(1); - if (G_000E50_SEM_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_SEM(1); - if (G_000E50_BIF_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_BIF(1); - dev_info(rdev->dev, " R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset); - WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); - (void)RREG32(R_000E60_SRBM_SOFT_RESET); - mdelay(1); - WREG32(R_000E60_SRBM_SOFT_RESET, 0); - (void)RREG32(R_000E60_SRBM_SOFT_RESET); - WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); - (void)RREG32(R_000E60_SRBM_SOFT_RESET); - mdelay(1); - WREG32(R_000E60_SRBM_SOFT_RESET, 0); - (void)RREG32(R_000E60_SRBM_SOFT_RESET); /* Wait a little for things to settle down */ mdelay(1); dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n", @@ -840,10 +801,6 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) RREG32(R_008014_GRBM_STATUS2)); dev_info(rdev->dev, " R_000E50_SRBM_STATUS=0x%08X\n", RREG32(R_000E50_SRBM_STATUS)); - /* After reset we need to reinit the asic as GPU often endup in an - * incoherent state. - */ - atom_asic_init(rdev->mode_info.atom_context); rv515_mc_resume(rdev, &save); return 0; } diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index f6c6c77db7e..d13622ae74e 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -447,6 +447,9 @@ int r600_blit_init(struct radeon_device *rdev) u32 packet2s[16]; int num_packet2s = 0; + /* don't reinitialize blit */ + if (rdev->r600_blit.shader_obj) + return 0; mutex_init(&rdev->r600_blit.mutex); rdev->r600_blit.state_offset = 0; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3cc5820b0e1..4ac97ab2894 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1188,6 +1188,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) /* Common functions */ /* AGP */ +extern int radeon_gpu_reset(struct radeon_device *rdev); extern void radeon_agp_disable(struct radeon_device *rdev); extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); extern void radeon_gart_restore(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 011ac6d8658..0d7664b8e48 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -367,7 +367,7 @@ static struct radeon_asic rs600_asic = { .resume = &rs600_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .asic_reset = &r300_asic_reset, + .asic_reset = &rs600_asic_reset, .gart_tlb_flush = &rs600_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .cp_commit = &r100_cp_commit, @@ -406,7 +406,7 @@ static struct radeon_asic rs690_asic = { .resume = &rs690_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .asic_reset = &r300_asic_reset, + .asic_reset = &rs600_asic_reset, .gart_tlb_flush = &rs400_gart_tlb_flush, .gart_set_page = &rs400_gart_set_page, .cp_commit = &r100_cp_commit, @@ -445,7 +445,7 @@ static struct radeon_asic rv515_asic = { .resume = &rv515_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .asic_reset = &rv515_asic_reset, + .asic_reset = &rs600_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -484,7 +484,7 @@ static struct radeon_asic r520_asic = { .resume = &r520_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .asic_reset = &rv515_asic_reset, + .asic_reset = &rs600_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -560,6 +560,7 @@ static struct radeon_asic rs780_asic = { .suspend = &r600_suspend, .resume = &r600_resume, .cp_commit = &r600_cp_commit, + .gpu_is_lockup = &r600_gpu_is_lockup, .vga_set_state = &r600_vga_set_state, .asic_reset = &r600_asic_reset, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 53ebcacbd0e..77d48ba4a29 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -111,8 +111,6 @@ void r100_vram_init_sizes(struct radeon_device *rdev); void r100_wb_disable(struct radeon_device *rdev); void r100_wb_fini(struct radeon_device *rdev); int r100_wb_init(struct radeon_device *rdev); -void r100_hdp_reset(struct radeon_device *rdev); -int r100_rb2d_reset(struct radeon_device *rdev); int r100_cp_reset(struct radeon_device *rdev); void r100_vga_render_disable(struct radeon_device *rdev); int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, @@ -127,7 +125,7 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p, unsigned idx); void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); - +void r100_bm_disable(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 */ @@ -180,6 +178,7 @@ void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); /* * rs600. */ +extern int rs600_asic_reset(struct radeon_device *rdev); extern int rs600_init(struct radeon_device *rdev); extern void rs600_fini(struct radeon_device *rdev); extern int rs600_suspend(struct radeon_device *rdev); @@ -214,7 +213,6 @@ void rs690_bandwidth_update(struct radeon_device *rdev); */ int rv515_init(struct radeon_device *rdev); void rv515_fini(struct radeon_device *rdev); -int rv515_asic_reset(struct radeon_device *rdev); uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rv515_ring_start(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index f9b0fe002c0..ae0fb7356e6 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -220,10 +220,6 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) int r; mutex_lock(&rdev->cs_mutex); - if (rdev->gpu_lockup) { - mutex_unlock(&rdev->cs_mutex); - return -EINVAL; - } /* initialize parser */ memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 232a3076849..d4ff5a6d349 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -639,6 +639,8 @@ void radeon_device_fini(struct radeon_device *rdev) { DRM_INFO("radeon: finishing device.\n"); rdev->shutdown = true; + /* evict vram memory */ + radeon_bo_evict_vram(rdev); radeon_fini(rdev); destroy_workqueue(rdev->wq); vga_switcheroo_unregister_client(rdev->pdev); @@ -737,6 +739,26 @@ int radeon_resume_kms(struct drm_device *dev) return 0; } +int radeon_gpu_reset(struct radeon_device *rdev) +{ + int r; + + radeon_save_bios_scratch_regs(rdev); + radeon_suspend(rdev); + + r = radeon_asic_reset(rdev); + if (!r) { + dev_info(rdev->dev, "GPU reset succeed\n"); + radeon_resume(rdev); + radeon_restore_bios_scratch_regs(rdev); + drm_helper_resume_force_mode(rdev->ddev); + return 0; + } + /* bad news, how to tell it to userspace ? */ + dev_info(rdev->dev, "GPU reset failed\n"); + return r; +} + /* * Debugfs diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 2560740ff92..fcd7802d8a7 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -209,8 +209,9 @@ retry: r = wait_event_interruptible_timeout(rdev->fence_drv.queue, radeon_fence_signaled(fence), timeout); radeon_irq_kms_sw_irq_put(rdev); - if (unlikely(r < 0)) + if (unlikely(r < 0)) { return r; + } } else { radeon_irq_kms_sw_irq_get(rdev); r = wait_event_timeout(rdev->fence_drv.queue, @@ -230,14 +231,16 @@ retry: */ if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) { /* good news we believe it's a lockup */ - dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq); - r = radeon_asic_reset(rdev); - if (r) - return r; + WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq); /* FIXME: what should we do ? marking everyone * as signaled for now */ + rdev->gpu_lockup = true; WREG32(rdev->fence_drv.scratch_reg, fence->seq); + r = radeon_gpu_reset(rdev); + if (r) + return r; + rdev->gpu_lockup = false; } timeout = RADEON_FENCE_JIFFIES_TIMEOUT; write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 1770d3c07fd..e65b90317fa 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -173,7 +173,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int i, j; if (!rdev->gart.ready) { - DRM_ERROR("trying to bind memory to unitialized GART !\n"); + WARN(1, "trying to bind memory to unitialized GART !\n"); return -EINVAL; } t = offset / RADEON_GPU_PAGE_SIZE; diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 3deec218508..9420c20dc14 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -242,8 +242,6 @@ int rs400_mc_wait_for_idle(struct radeon_device *rdev) void rs400_gpu_init(struct radeon_device *rdev) { - /* FIXME: HDP same place on rs400 ? */ - r100_hdp_reset(rdev); /* FIXME: is this correct ? */ r420_pipes_init(rdev); if (rs400_mc_wait_for_idle(rdev)) { diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index c1be20afd42..a16d9d79f36 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -147,6 +147,78 @@ void rs600_hpd_fini(struct radeon_device *rdev) } } +void rs600_bm_disable(struct radeon_device *rdev) +{ + u32 tmp; + + /* disable bus mastering */ + pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp); + pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); + mdelay(1); +} + +int rs600_asic_reset(struct radeon_device *rdev) +{ + u32 status, tmp; + + struct rv515_mc_save save; + + /* Stops all mc clients */ + rv515_mc_stop(rdev, &save); + status = RREG32(R_000E40_RBBM_STATUS); + if (!G_000E40_GUI_ACTIVE(status)) { + return 0; + } + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* stop CP */ + WREG32(RADEON_CP_CSQ_CNTL, 0); + tmp = RREG32(RADEON_CP_RB_CNTL); + WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); + WREG32(RADEON_CP_RB_RPTR_WR, 0); + WREG32(RADEON_CP_RB_WPTR, 0); + WREG32(RADEON_CP_RB_CNTL, tmp); + pci_save_state(rdev->pdev); + /* disable bus mastering */ + rs600_bm_disable(rdev); + /* reset GA+VAP */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | + S_0000F0_SOFT_RESET_GA(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* reset CP */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* reset MC */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* restore PCI & busmastering */ + pci_restore_state(rdev->pdev); + /* Check if GPU is idle */ + if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { + dev_err(rdev->dev, "failed to reset GPU\n"); + rdev->gpu_lockup = true; + return -1; + } + rv515_mc_resume(rdev, &save); + dev_info(rdev->dev, "GPU reset succeed\n"); + return 0; +} + /* * GART. */ @@ -454,7 +526,6 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev) void rs600_gpu_init(struct radeon_device *rdev) { - r100_hdp_reset(rdev); r420_pipes_init(rdev); /* Wait for mc idle */ if (rs600_mc_wait_for_idle(rdev)) diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h index e52d2695510..08c4bebd301 100644 --- a/drivers/gpu/drm/radeon/rs600d.h +++ b/drivers/gpu/drm/radeon/rs600d.h @@ -178,6 +178,52 @@ #define S_000074_MC_IND_DATA(x) (((x) & 0xFFFFFFFF) << 0) #define G_000074_MC_IND_DATA(x) (((x) >> 0) & 0xFFFFFFFF) #define C_000074_MC_IND_DATA 0x00000000 +#define R_0000F0_RBBM_SOFT_RESET 0x0000F0 +#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0) +#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1) +#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE +#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1) +#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1) +#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD +#define S_0000F0_SOFT_RESET_VAP(x) (((x) & 0x1) << 2) +#define G_0000F0_SOFT_RESET_VAP(x) (((x) >> 2) & 0x1) +#define C_0000F0_SOFT_RESET_VAP 0xFFFFFFFB +#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3) +#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1) +#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7 +#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4) +#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1) +#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF +#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5) +#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1) +#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF +#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6) +#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1) +#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF +#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7) +#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1) +#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F +#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8) +#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1) +#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF +#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9) +#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1) +#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF +#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10) +#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1) +#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF +#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11) +#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1) +#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF +#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12) +#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1) +#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF +#define S_0000F0_SOFT_RESET_GA(x) (((x) & 0x1) << 13) +#define G_0000F0_SOFT_RESET_GA(x) (((x) >> 13) & 0x1) +#define C_0000F0_SOFT_RESET_GA 0xFFFFDFFF +#define S_0000F0_SOFT_RESET_IDCT(x) (((x) & 0x1) << 14) +#define G_0000F0_SOFT_RESET_IDCT(x) (((x) >> 14) & 0x1) +#define C_0000F0_SOFT_RESET_IDCT 0xFFFFBFFF #define R_000134_HDP_FB_LOCATION 0x000134 #define S_000134_HDP_FB_START(x) (((x) & 0xFFFF) << 0) #define G_000134_HDP_FB_START(x) (((x) >> 0) & 0xFFFF) diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index ef35e0468f1..56a0aec84af 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -48,8 +48,6 @@ static int rs690_mc_wait_for_idle(struct radeon_device *rdev) static void rs690_gpu_init(struct radeon_device *rdev) { - /* FIXME: HDP same place on rs690 ? */ - r100_hdp_reset(rdev); /* FIXME: is this correct ? */ r420_pipes_init(rdev); if (rs690_mc_wait_for_idle(rdev)) { diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 2a4c01f5cf1..b42f8d90a0f 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -146,16 +146,11 @@ void rv515_gpu_init(struct radeon_device *rdev) { unsigned pipe_select_current, gb_pipe_select, tmp; - r100_hdp_reset(rdev); - r100_rb2d_reset(rdev); - if (r100_gui_wait_for_idle(rdev)) { printk(KERN_WARNING "Failed to wait GUI idle while " "reseting GPU. Bad things might happen.\n"); } - rv515_vga_render_disable(rdev); - r420_pipes_init(rdev); gb_pipe_select = RREG32(0x402C); tmp = RREG32(0x170C); @@ -173,91 +168,6 @@ void rv515_gpu_init(struct radeon_device *rdev) } } -int rv515_ga_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - bool reinit_cp; - int i; - - reinit_cp = rdev->cp.ready; - rdev->cp.ready = false; - for (i = 0; i < rdev->usec_timeout; i++) { - WREG32(CP_CSQ_MODE, 0); - WREG32(CP_CSQ_CNTL, 0); - WREG32(RBBM_SOFT_RESET, 0x32005); - (void)RREG32(RBBM_SOFT_RESET); - udelay(200); - WREG32(RBBM_SOFT_RESET, 0); - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - tmp = RREG32(RBBM_STATUS); - if (tmp & ((1 << 20) | (1 << 26))) { - DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)\n", tmp); - /* GA still busy soft reset it */ - WREG32(0x429C, 0x200); - WREG32(VAP_PVS_STATE_FLUSH_REG, 0); - WREG32(0x43E0, 0); - WREG32(0x43E4, 0); - WREG32(0x24AC, 0); - } - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - tmp = RREG32(RBBM_STATUS); - if (!(tmp & ((1 << 20) | (1 << 26)))) { - break; - } - } - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RBBM_STATUS); - if (!(tmp & ((1 << 20) | (1 << 26)))) { - DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", - tmp); - DRM_INFO("GA_IDLE=0x%08X\n", RREG32(0x425C)); - DRM_INFO("RB3D_RESET_STATUS=0x%08X\n", RREG32(0x46f0)); - DRM_INFO("ISYNC_CNTL=0x%08X\n", RREG32(0x1724)); - if (reinit_cp) { - return r100_cp_init(rdev, rdev->cp.ring_size); - } - return 0; - } - DRM_UDELAY(1); - } - tmp = RREG32(RBBM_STATUS); - DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); - return -1; -} - -int rv515_asic_reset(struct radeon_device *rdev) -{ - uint32_t status; - - /* reset order likely matter */ - status = RREG32(RBBM_STATUS); - /* reset HDP */ - r100_hdp_reset(rdev); - /* reset rb2d */ - if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { - r100_rb2d_reset(rdev); - } - /* reset GA */ - if (status & ((1 << 20) | (1 << 26))) { - rv515_ga_reset(rdev); - } - /* reset CP */ - status = RREG32(RBBM_STATUS); - if (status & (1 << 16)) { - r100_cp_reset(rdev); - } - /* Check if GPU is idle */ - status = RREG32(RBBM_STATUS); - if (status & (1 << 31)) { - DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); - return -1; - } - DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); - return 0; -} - static void rv515_vram_get_type(struct radeon_device *rdev) { uint32_t tmp; diff --git a/drivers/gpu/drm/radeon/rv515d.h b/drivers/gpu/drm/radeon/rv515d.h index fc216e49384..590309a710b 100644 --- a/drivers/gpu/drm/radeon/rv515d.h +++ b/drivers/gpu/drm/radeon/rv515d.h @@ -217,6 +217,52 @@ #define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) /* Registers */ +#define R_0000F0_RBBM_SOFT_RESET 0x0000F0 +#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0) +#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1) +#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE +#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1) +#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1) +#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD +#define S_0000F0_SOFT_RESET_VAP(x) (((x) & 0x1) << 2) +#define G_0000F0_SOFT_RESET_VAP(x) (((x) >> 2) & 0x1) +#define C_0000F0_SOFT_RESET_VAP 0xFFFFFFFB +#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3) +#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1) +#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7 +#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4) +#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1) +#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF +#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5) +#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1) +#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF +#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6) +#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1) +#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF +#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7) +#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1) +#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F +#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8) +#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1) +#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF +#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9) +#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1) +#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF +#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10) +#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1) +#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF +#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11) +#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1) +#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF +#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12) +#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1) +#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF +#define S_0000F0_SOFT_RESET_GA(x) (((x) & 0x1) << 13) +#define G_0000F0_SOFT_RESET_GA(x) (((x) >> 13) & 0x1) +#define C_0000F0_SOFT_RESET_GA 0xFFFFDFFF +#define S_0000F0_SOFT_RESET_IDCT(x) (((x) & 0x1) << 14) +#define G_0000F0_SOFT_RESET_IDCT(x) (((x) >> 14) & 0x1) +#define C_0000F0_SOFT_RESET_IDCT 0xFFFFBFFF #define R_0000F8_CONFIG_MEMSIZE 0x0000F8 #define S_0000F8_CONFIG_MEMSIZE(x) (((x) & 0xFFFFFFFF) << 0) #define G_0000F8_CONFIG_MEMSIZE(x) (((x) >> 0) & 0xFFFFFFFF) -- cgit v1.2.3-70-g09d2 From fe251e2fffa1ebc17c8e6e895b0374ae4e732fa5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:36:43 -0400 Subject: drm/radeon/kms/evergreen: setup and enable the CP The command processor (CP) fetches command buffers and feeds the GPU. This patch requires the evergreen family me and pfp ucode files. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 117 ++++++++++++++++++++++++++++------- drivers/gpu/drm/radeon/evergreend.h | 2 + drivers/gpu/drm/radeon/r600.c | 47 ++++++++++++-- drivers/gpu/drm/radeon/radeon.h | 4 ++ drivers/gpu/drm/radeon/radeon_asic.c | 6 +- drivers/gpu/drm/radeon/rv770.c | 10 ++- 6 files changed, 154 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 26b219bb138..57fe569682d 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -32,6 +32,9 @@ #include "avivod.h" #include "evergreen_reg.h" +#define EVERGREEN_PFP_UCODE_SIZE 1120 +#define EVERGREEN_PM4_UCODE_SIZE 1376 + static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); @@ -418,23 +421,91 @@ static void evergreen_mc_program(struct radeon_device *rdev) rv515_vga_render_disable(rdev); } -#if 0 /* * CP. */ -static void evergreen_cp_stop(struct radeon_device *rdev) -{ - /* XXX */ -} - static int evergreen_cp_load_microcode(struct radeon_device *rdev) { - /* XXX */ + const __be32 *fw_data; + int i; + + if (!rdev->me_fw || !rdev->pfp_fw) + return -EINVAL; + r700_cp_stop(rdev); + WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0)); + + fw_data = (const __be32 *)rdev->pfp_fw->data; + WREG32(CP_PFP_UCODE_ADDR, 0); + for (i = 0; i < EVERGREEN_PFP_UCODE_SIZE; i++) + WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_PFP_UCODE_ADDR, 0); + + fw_data = (const __be32 *)rdev->me_fw->data; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < EVERGREEN_PM4_UCODE_SIZE; i++) + WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); + + WREG32(CP_PFP_UCODE_ADDR, 0); + WREG32(CP_ME_RAM_WADDR, 0); + WREG32(CP_ME_RAM_RADDR, 0); return 0; } + +int evergreen_cp_resume(struct radeon_device *rdev) +{ + u32 tmp; + u32 rb_bufsz; + int r; + + /* Reset cp; if cp is reset, then PA, SH, VGT also need to be reset */ + WREG32(GRBM_SOFT_RESET, (SOFT_RESET_CP | + SOFT_RESET_PA | + SOFT_RESET_SH | + SOFT_RESET_VGT | + SOFT_RESET_SX)); + RREG32(GRBM_SOFT_RESET); + mdelay(15); + WREG32(GRBM_SOFT_RESET, 0); + RREG32(GRBM_SOFT_RESET); + + /* Set ring buffer size */ + rb_bufsz = drm_order(rdev->cp.ring_size / 8); + tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; +#ifdef __BIG_ENDIAN + tmp |= BUF_SWAP_32BIT; #endif + WREG32(CP_RB_CNTL, tmp); + WREG32(CP_SEM_WAIT_TIMER, 0x4); + + /* Set the write pointer delay */ + WREG32(CP_RB_WPTR_DELAY, 0); + + /* Initialize the ring buffer's read and write pointers */ + WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA); + WREG32(CP_RB_RPTR_WR, 0); + WREG32(CP_RB_WPTR, 0); + WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF); + WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr)); + mdelay(1); + WREG32(CP_RB_CNTL, tmp); + + WREG32(CP_RB_BASE, rdev->cp.gpu_addr >> 8); + WREG32(CP_DEBUG, (1 << 27) | (1 << 28)); + + rdev->cp.rptr = RREG32(CP_RB_RPTR); + rdev->cp.wptr = RREG32(CP_RB_WPTR); + + r600_cp_start(rdev); + rdev->cp.ready = true; + r = radeon_ring_test(rdev); + if (r) { + rdev->cp.ready = false; + return r; + } + return 0; +} /* * Core functions @@ -1138,15 +1209,15 @@ static int evergreen_startup(struct radeon_device *rdev) { int r; -#if 0 - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + /* XXX until interrupts are supported */ + if (!rdev->me_fw || !rdev->pfp_fw /*|| !rdev->rlc_fw*/) { r = r600_init_microcode(rdev); if (r) { DRM_ERROR("Failed to load firmware!\n"); return r; } } -#endif + evergreen_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { evergreen_agp_enable(rdev); @@ -1184,6 +1255,7 @@ static int evergreen_startup(struct radeon_device *rdev) return r; } r600_irq_set(rdev); +#endif r = radeon_ring_init(rdev, rdev->cp.ring_size); if (r) @@ -1191,12 +1263,12 @@ static int evergreen_startup(struct radeon_device *rdev) r = evergreen_cp_load_microcode(rdev); if (r) return r; - r = r600_cp_resume(rdev); + r = evergreen_cp_resume(rdev); if (r) return r; /* write back buffer are not vital so don't worry about failure */ r600_wb_enable(rdev); -#endif + return 0; } @@ -1221,13 +1293,13 @@ int evergreen_resume(struct radeon_device *rdev) DRM_ERROR("r600 startup failed on resume\n"); return r; } -#if 0 + r = r600_ib_test(rdev); if (r) { DRM_ERROR("radeon: failled testing IB (%d).\n", r); return r; } -#endif + return r; } @@ -1236,12 +1308,11 @@ int evergreen_suspend(struct radeon_device *rdev) { #if 0 int r; - +#endif /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); rdev->cp.ready = false; r600_wb_disable(rdev); -#endif evergreen_pcie_gart_disable(rdev); #if 0 @@ -1348,10 +1419,10 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_irq_kms_init(rdev); if (r) return r; - +#endif rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); - +#if 0 rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); #endif @@ -1362,9 +1433,13 @@ int evergreen_init(struct radeon_device *rdev) rdev->accel_working = false; r = evergreen_startup(rdev); if (r) { - evergreen_suspend(rdev); - /*r600_wb_fini(rdev);*/ - /*radeon_ring_fini(rdev);*/ + dev_err(rdev->dev, "disabling GPU acceleration\n"); + r700_cp_fini(rdev); + r600_wb_fini(rdev); +#if 0 + r600_irq_fini(rdev); + radeon_irq_kms_fini(rdev); +#endif evergreen_pcie_gart_fini(rdev); rdev->accel_working = false; } diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index effe335356c..10e9768534d 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -89,6 +89,7 @@ #define CP_QUEUE_THRESHOLDS 0x8760 #define ROQ_IB1_START(x) ((x) << 0) #define ROQ_IB2_START(x) ((x) << 8) +#define CP_RB_BASE 0xC100 #define CP_RB_CNTL 0xC104 #define RB_BUFSZ(x) ((x) << 0) #define RB_BLKSZ(x) ((x) << 8) @@ -104,6 +105,7 @@ #define CP_RB_WPTR_ADDR_HI 0xC11C #define CP_RB_WPTR_DELAY 0x8704 #define CP_SEM_WAIT_TIMER 0x85BC +#define CP_DEBUG 0xC1FC #define GC_USER_SHADER_PIPE_CONFIG 0x8954 diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 13c9cc34231..4b0225715b9 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -43,6 +43,8 @@ #define R700_PFP_UCODE_SIZE 848 #define R700_PM4_UCODE_SIZE 1360 #define R700_RLC_UCODE_SIZE 1024 +#define EVERGREEN_PFP_UCODE_SIZE 1120 +#define EVERGREEN_PM4_UCODE_SIZE 1376 /* Firmware Names */ MODULE_FIRMWARE("radeon/R600_pfp.bin"); @@ -67,6 +69,14 @@ MODULE_FIRMWARE("radeon/RV710_pfp.bin"); MODULE_FIRMWARE("radeon/RV710_me.bin"); MODULE_FIRMWARE("radeon/R600_rlc.bin"); MODULE_FIRMWARE("radeon/R700_rlc.bin"); +MODULE_FIRMWARE("radeon/CEDAR_pfp.bin"); +MODULE_FIRMWARE("radeon/CEDAR_me.bin"); +MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin"); +MODULE_FIRMWARE("radeon/REDWOOD_me.bin"); +MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin"); +MODULE_FIRMWARE("radeon/JUNIPER_me.bin"); +MODULE_FIRMWARE("radeon/CYRPESS_pfp.bin"); +MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); int r600_debugfs_mc_info_init(struct radeon_device *rdev); @@ -1449,10 +1459,31 @@ int r600_init_microcode(struct radeon_device *rdev) chip_name = "RV710"; rlc_chip_name = "R700"; break; + case CHIP_CEDAR: + chip_name = "CEDAR"; + rlc_chip_name = ""; + break; + case CHIP_REDWOOD: + chip_name = "REDWOOD"; + rlc_chip_name = ""; + break; + case CHIP_JUNIPER: + chip_name = "JUNIPER"; + rlc_chip_name = ""; + break; + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + chip_name = "CYPRESS"; + rlc_chip_name = ""; + break; default: BUG(); } - if (rdev->family >= CHIP_RV770) { + if (rdev->family >= CHIP_CEDAR) { + pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4; + me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; + rlc_req_size = 0; + } else if (rdev->family >= CHIP_RV770) { pfp_req_size = R700_PFP_UCODE_SIZE * 4; me_req_size = R700_PM4_UCODE_SIZE * 4; rlc_req_size = R700_RLC_UCODE_SIZE * 4; @@ -1487,6 +1518,8 @@ int r600_init_microcode(struct radeon_device *rdev) err = -EINVAL; } + /* XXX until evergreen interrupts are supported */ + if (rdev->family < CHIP_CEDAR) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); if (err) @@ -1497,6 +1530,7 @@ int r600_init_microcode(struct radeon_device *rdev) rdev->rlc_fw->size, fw_name); err = -EINVAL; } + } out: platform_device_unregister(pdev); @@ -1566,12 +1600,15 @@ int r600_cp_start(struct radeon_device *rdev) } radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5)); radeon_ring_write(rdev, 0x1); - if (rdev->family < CHIP_RV770) { - radeon_ring_write(rdev, 0x3); - radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1); - } else { + if (rdev->family >= CHIP_CEDAR) { + radeon_ring_write(rdev, 0x0); + radeon_ring_write(rdev, rdev->config.evergreen.max_hw_contexts - 1); + } else if (rdev->family >= CHIP_RV770) { radeon_ring_write(rdev, 0x0); radeon_ring_write(rdev, rdev->config.rv770.max_hw_contexts - 1); + } else { + radeon_ring_write(rdev, 0x3); + radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1); } radeon_ring_write(rdev, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(rdev, 0); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a77a8620399..acf21d7e3cb 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1300,6 +1300,7 @@ extern void rs690_line_buffer_adjust(struct radeon_device *rdev, extern void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); extern bool r600_card_posted(struct radeon_device *rdev); extern void r600_cp_stop(struct radeon_device *rdev); +extern int r600_cp_start(struct radeon_device *rdev); extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_cp_resume(struct radeon_device *rdev); extern void r600_cp_fini(struct radeon_device *rdev); @@ -1340,6 +1341,9 @@ extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, uint8_t status_bits, uint8_t category_code); +extern void r700_cp_stop(struct radeon_device *rdev); +extern void r700_cp_fini(struct radeon_device *rdev); + /* evergreen */ struct evergreen_mc_save { u32 vga_control[6]; diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index d923e4b234d..3a576ab805c 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -635,14 +635,14 @@ static struct radeon_asic evergreen_asic = { .fini = &evergreen_fini, .suspend = &evergreen_suspend, .resume = &evergreen_resume, - .cp_commit = NULL, + .cp_commit = &r600_cp_commit, .gpu_is_lockup = &evergreen_gpu_is_lockup, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, - .ring_test = NULL, - .ring_ib_execute = NULL, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, .irq_set = NULL, .irq_process = NULL, .get_vblank_counter = NULL, diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 2b8a4e17065..2642d264264 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -236,7 +236,6 @@ void r700_cp_stop(struct radeon_device *rdev) WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT)); } - static int rv770_cp_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data; @@ -271,6 +270,11 @@ static int rv770_cp_load_microcode(struct radeon_device *rdev) return 0; } +void r700_cp_fini(struct radeon_device *rdev) +{ + r700_cp_stop(rdev); + radeon_ring_fini(rdev); +} /* * Core functions @@ -1125,7 +1129,7 @@ int rv770_init(struct radeon_device *rdev) r = rv770_startup(rdev); if (r) { dev_err(rdev->dev, "disabling GPU acceleration\n"); - r600_cp_fini(rdev); + r700_cp_fini(rdev); r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); @@ -1159,7 +1163,7 @@ void rv770_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); r600_blit_fini(rdev); - r600_cp_fini(rdev); + r700_cp_fini(rdev); r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); -- cgit v1.2.3-70-g09d2 From 45f9a39bedc3afab3fc85567792efc0103f34a55 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:55:51 -0400 Subject: drm/radeon/kms/evergreen: implement irq support Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 8 +- drivers/gpu/drm/radeon/evergreen.c | 549 ++++++++++++++++++++++++++++++++- drivers/gpu/drm/radeon/evergreend.h | 148 +++++++++ drivers/gpu/drm/radeon/r600.c | 40 ++- drivers/gpu/drm/radeon/radeon.h | 5 +- drivers/gpu/drm/radeon/radeon_asic.c | 6 +- drivers/gpu/drm/radeon/radeon_asic.h | 4 + 7 files changed, 719 insertions(+), 41 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index fd4ef6d1884..6300675dd48 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -249,17 +249,13 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); atombios_blank_crtc(crtc, ATOM_DISABLE); - /* XXX re-enable when interrupt support is added */ - if (!ASIC_IS_DCE4(rdev)) - drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); + drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - /* XXX re-enable when interrupt support is added */ - if (!ASIC_IS_DCE4(rdev)) - drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); + drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); atombios_blank_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 57fe569682d..5c34349058c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1205,12 +1205,532 @@ int evergreen_asic_reset(struct radeon_device *rdev) return evergreen_gpu_soft_reset(rdev); } +/* Interrupts */ + +u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc) +{ + switch (crtc) { + case 0: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC0_REGISTER_OFFSET); + case 1: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC1_REGISTER_OFFSET); + case 2: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC2_REGISTER_OFFSET); + case 3: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC3_REGISTER_OFFSET); + case 4: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC4_REGISTER_OFFSET); + case 5: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC5_REGISTER_OFFSET); + default: + return 0; + } +} + +void evergreen_disable_interrupt_state(struct radeon_device *rdev) +{ + u32 tmp; + + WREG32(CP_INT_CNTL, 0); + WREG32(GRBM_INT_CNTL, 0); + WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + + WREG32(DACA_AUTODETECT_INT_CONTROL, 0); + WREG32(DACB_AUTODETECT_INT_CONTROL, 0); + + tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD1_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD2_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD3_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD4_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD5_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD6_INT_CONTROL, tmp); + +} + +int evergreen_irq_set(struct radeon_device *rdev) +{ + u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; + u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0; + u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; + + if (!rdev->irq.installed) { + WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); + return -EINVAL; + } + /* don't enable anything if the ih is disabled */ + if (!rdev->ih.enabled) { + r600_disable_interrupts(rdev); + /* force the active interrupt state to all disabled */ + evergreen_disable_interrupt_state(rdev); + return 0; + } + + hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; + + if (rdev->irq.sw_int) { + DRM_DEBUG("evergreen_irq_set: sw int\n"); + cp_int_cntl |= RB_INT_ENABLE; + } + if (rdev->irq.crtc_vblank_int[0]) { + DRM_DEBUG("evergreen_irq_set: vblank 0\n"); + crtc1 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[1]) { + DRM_DEBUG("evergreen_irq_set: vblank 1\n"); + crtc2 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[2]) { + DRM_DEBUG("evergreen_irq_set: vblank 2\n"); + crtc3 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[3]) { + DRM_DEBUG("evergreen_irq_set: vblank 3\n"); + crtc4 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[4]) { + DRM_DEBUG("evergreen_irq_set: vblank 4\n"); + crtc5 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[5]) { + DRM_DEBUG("evergreen_irq_set: vblank 5\n"); + crtc6 |= VBLANK_INT_MASK; + } + if (rdev->irq.hpd[0]) { + DRM_DEBUG("evergreen_irq_set: hpd 1\n"); + hpd1 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[1]) { + DRM_DEBUG("evergreen_irq_set: hpd 2\n"); + hpd2 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[2]) { + DRM_DEBUG("evergreen_irq_set: hpd 3\n"); + hpd3 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[3]) { + DRM_DEBUG("evergreen_irq_set: hpd 4\n"); + hpd4 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[4]) { + DRM_DEBUG("evergreen_irq_set: hpd 5\n"); + hpd5 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[5]) { + DRM_DEBUG("evergreen_irq_set: hpd 6\n"); + hpd6 |= DC_HPDx_INT_EN; + } + + WREG32(CP_INT_CNTL, cp_int_cntl); + + WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); + WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); + WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); + WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); + WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); + WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); + + WREG32(DC_HPD1_INT_CONTROL, hpd1); + WREG32(DC_HPD2_INT_CONTROL, hpd2); + WREG32(DC_HPD3_INT_CONTROL, hpd3); + WREG32(DC_HPD4_INT_CONTROL, hpd4); + WREG32(DC_HPD5_INT_CONTROL, hpd5); + WREG32(DC_HPD6_INT_CONTROL, hpd6); + + return 0; +} + +static inline void evergreen_irq_ack(struct radeon_device *rdev, + u32 *disp_int, + u32 *disp_int_cont, + u32 *disp_int_cont2, + u32 *disp_int_cont3, + u32 *disp_int_cont4, + u32 *disp_int_cont5) +{ + u32 tmp; + + *disp_int = RREG32(DISP_INTERRUPT_STATUS); + *disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); + *disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2); + *disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3); + *disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4); + *disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5); + + if (*disp_int & LB_D1_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int & LB_D1_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont & LB_D2_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont & LB_D2_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont2 & LB_D3_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont3 & LB_D4_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont4 & LB_D5_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont5 & LB_D6_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int & DC_HPD1_INTERRUPT) { + tmp = RREG32(DC_HPD1_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD1_INT_CONTROL, tmp); + } + if (*disp_int_cont & DC_HPD2_INTERRUPT) { + tmp = RREG32(DC_HPD2_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD2_INT_CONTROL, tmp); + } + if (*disp_int_cont2 & DC_HPD3_INTERRUPT) { + tmp = RREG32(DC_HPD3_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD3_INT_CONTROL, tmp); + } + if (*disp_int_cont3 & DC_HPD4_INTERRUPT) { + tmp = RREG32(DC_HPD4_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD4_INT_CONTROL, tmp); + } + if (*disp_int_cont4 & DC_HPD5_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD5_INT_CONTROL, tmp); + } + if (*disp_int_cont5 & DC_HPD6_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD6_INT_CONTROL, tmp); + } +} + +void evergreen_irq_disable(struct radeon_device *rdev) +{ + u32 disp_int, disp_int_cont, disp_int_cont2; + u32 disp_int_cont3, disp_int_cont4, disp_int_cont5; + + r600_disable_interrupts(rdev); + /* Wait and acknowledge irq */ + mdelay(1); + evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2, + &disp_int_cont3, &disp_int_cont4, &disp_int_cont5); + evergreen_disable_interrupt_state(rdev); +} + +static void evergreen_irq_suspend(struct radeon_device *rdev) +{ + evergreen_irq_disable(rdev); + r600_rlc_stop(rdev); +} + +static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev) +{ + u32 wptr, tmp; + + /* XXX use writeback */ + wptr = RREG32(IH_RB_WPTR); + + if (wptr & RB_OVERFLOW) { + /* When a ring buffer overflow happen start parsing interrupt + * from the last not overwritten vector (wptr + 16). Hopefully + * this should allow us to catchup. + */ + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", + wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; + tmp = RREG32(IH_RB_CNTL); + tmp |= IH_WPTR_OVERFLOW_CLEAR; + WREG32(IH_RB_CNTL, tmp); + } + return (wptr & rdev->ih.ptr_mask); +} + +int evergreen_irq_process(struct radeon_device *rdev) +{ + u32 wptr = evergreen_get_ih_wptr(rdev); + u32 rptr = rdev->ih.rptr; + u32 src_id, src_data; + u32 ring_index; + u32 disp_int, disp_int_cont, disp_int_cont2; + u32 disp_int_cont3, disp_int_cont4, disp_int_cont5; + unsigned long flags; + bool queue_hotplug = false; + + DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + if (!rdev->ih.enabled) + return IRQ_NONE; + + spin_lock_irqsave(&rdev->ih.lock, flags); + + if (rptr == wptr) { + spin_unlock_irqrestore(&rdev->ih.lock, flags); + return IRQ_NONE; + } + if (rdev->shutdown) { + spin_unlock_irqrestore(&rdev->ih.lock, flags); + return IRQ_NONE; + } + +restart_ih: + /* display interrupts */ + evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2, + &disp_int_cont3, &disp_int_cont4, &disp_int_cont5); + + rdev->ih.wptr = wptr; + while (rptr != wptr) { + /* wptr/rptr are in bytes! */ + ring_index = rptr / 4; + src_id = rdev->ih.ring[ring_index] & 0xff; + src_data = rdev->ih.ring[ring_index + 1] & 0xfffffff; + + switch (src_id) { + case 1: /* D1 vblank/vline */ + switch (src_data) { + case 0: /* D1 vblank */ + if (disp_int & LB_D1_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 0); + wake_up(&rdev->irq.vblank_queue); + disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + } + break; + case 1: /* D1 vline */ + if (disp_int & LB_D1_VLINE_INTERRUPT) { + disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 2: /* D2 vblank/vline */ + switch (src_data) { + case 0: /* D2 vblank */ + if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 1); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + } + break; + case 1: /* D2 vline */ + if (disp_int_cont & LB_D2_VLINE_INTERRUPT) { + disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 3: /* D3 vblank/vline */ + switch (src_data) { + case 0: /* D3 vblank */ + if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 2); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + } + break; + case 1: /* D3 vline */ + if (disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { + disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 4: /* D4 vblank/vline */ + switch (src_data) { + case 0: /* D4 vblank */ + if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 3); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + } + break; + case 1: /* D4 vline */ + if (disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { + disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 5: /* D5 vblank/vline */ + switch (src_data) { + case 0: /* D5 vblank */ + if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 4); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + } + break; + case 1: /* D5 vline */ + if (disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { + disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 6: /* D6 vblank/vline */ + switch (src_data) { + case 0: /* D6 vblank */ + if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 5); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + } + break; + case 1: /* D6 vline */ + if (disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { + disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 42: /* HPD hotplug */ + switch (src_data) { + case 0: + if (disp_int & DC_HPD1_INTERRUPT) { + disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); + } + break; + case 1: + if (disp_int_cont & DC_HPD2_INTERRUPT) { + disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); + } + break; + case 2: + if (disp_int_cont2 & DC_HPD3_INTERRUPT) { + disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); + } + break; + case 3: + if (disp_int_cont3 & DC_HPD4_INTERRUPT) { + disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); + } + break; + case 4: + if (disp_int_cont4 & DC_HPD5_INTERRUPT) { + disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); + } + break; + case 5: + if (disp_int_cont5 & DC_HPD6_INTERRUPT) { + disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 176: /* CP_INT in ring buffer */ + case 177: /* CP_INT in IB1 */ + case 178: /* CP_INT in IB2 */ + DRM_DEBUG("IH: CP int: 0x%08x\n", src_data); + radeon_fence_process(rdev); + break; + case 181: /* CP EOP event */ + DRM_DEBUG("IH: CP EOP\n"); + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + + /* wptr/rptr are in bytes! */ + rptr += 16; + rptr &= rdev->ih.ptr_mask; + } + /* make sure wptr hasn't changed while processing */ + wptr = evergreen_get_ih_wptr(rdev); + if (wptr != rdev->ih.wptr) + goto restart_ih; + if (queue_hotplug) + queue_work(rdev->wq, &rdev->hotplug_work); + rdev->ih.rptr = rptr; + WREG32(IH_RB_RPTR, rdev->ih.rptr); + spin_unlock_irqrestore(&rdev->ih.lock, flags); + return IRQ_HANDLED; +} + static int evergreen_startup(struct radeon_device *rdev) { int r; - /* XXX until interrupts are supported */ - if (!rdev->me_fw || !rdev->pfp_fw /*|| !rdev->rlc_fw*/) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { DRM_ERROR("Failed to load firmware!\n"); @@ -1246,6 +1766,7 @@ static int evergreen_startup(struct radeon_device *rdev) DRM_ERROR("failed to pin blit object %d\n", r); return r; } +#endif /* Enable IRQ */ r = r600_irq_init(rdev); @@ -1254,8 +1775,7 @@ static int evergreen_startup(struct radeon_device *rdev) radeon_irq_kms_fini(rdev); return r; } - r600_irq_set(rdev); -#endif + evergreen_irq_set(rdev); r = radeon_ring_init(rdev, rdev->cp.ring_size); if (r) @@ -1312,8 +1832,8 @@ int evergreen_suspend(struct radeon_device *rdev) /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); rdev->cp.ready = false; + evergreen_irq_suspend(rdev); r600_wb_disable(rdev); - evergreen_pcie_gart_disable(rdev); #if 0 /* unpin shaders bo */ @@ -1415,17 +1935,17 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_bo_init(rdev); if (r) return r; -#if 0 + r = radeon_irq_kms_init(rdev); if (r) return r; -#endif + rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); -#if 0 + rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); -#endif + r = r600_pcie_gart_init(rdev); if (r) return r; @@ -1436,10 +1956,8 @@ int evergreen_init(struct radeon_device *rdev) dev_err(rdev->dev, "disabling GPU acceleration\n"); r700_cp_fini(rdev); r600_wb_fini(rdev); -#if 0 r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); -#endif evergreen_pcie_gart_fini(rdev); rdev->accel_working = false; } @@ -1461,14 +1979,11 @@ int evergreen_init(struct radeon_device *rdev) void evergreen_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - evergreen_suspend(rdev); -#if 0 - r600_blit_fini(rdev); + /*r600_blit_fini(rdev);*/ + r700_cp_fini(rdev); + r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); - radeon_ring_fini(rdev); - r600_wb_fini(rdev); -#endif evergreen_pcie_gart_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 10e9768534d..93e9e17ad54 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -405,4 +405,152 @@ #define SOFT_RESET_REGBB (1 << 22) #define SOFT_RESET_ORB (1 << 23) +#define IH_RB_CNTL 0x3e00 +# define IH_RB_ENABLE (1 << 0) +# define IH_IB_SIZE(x) ((x) << 1) /* log2 */ +# define IH_RB_FULL_DRAIN_ENABLE (1 << 6) +# define IH_WPTR_WRITEBACK_ENABLE (1 << 8) +# define IH_WPTR_WRITEBACK_TIMER(x) ((x) << 9) /* log2 */ +# define IH_WPTR_OVERFLOW_ENABLE (1 << 16) +# define IH_WPTR_OVERFLOW_CLEAR (1 << 31) +#define IH_RB_BASE 0x3e04 +#define IH_RB_RPTR 0x3e08 +#define IH_RB_WPTR 0x3e0c +# define RB_OVERFLOW (1 << 0) +# define WPTR_OFFSET_MASK 0x3fffc +#define IH_RB_WPTR_ADDR_HI 0x3e10 +#define IH_RB_WPTR_ADDR_LO 0x3e14 +#define IH_CNTL 0x3e18 +# define ENABLE_INTR (1 << 0) +# define IH_MC_SWAP(x) ((x) << 2) +# define IH_MC_SWAP_NONE 0 +# define IH_MC_SWAP_16BIT 1 +# define IH_MC_SWAP_32BIT 2 +# define IH_MC_SWAP_64BIT 3 +# define RPTR_REARM (1 << 4) +# define MC_WRREQ_CREDIT(x) ((x) << 15) +# define MC_WR_CLEAN_CNT(x) ((x) << 20) + +#define CP_INT_CNTL 0xc124 +# define CNTX_BUSY_INT_ENABLE (1 << 19) +# define CNTX_EMPTY_INT_ENABLE (1 << 20) +# define SCRATCH_INT_ENABLE (1 << 25) +# define TIME_STAMP_INT_ENABLE (1 << 26) +# define IB2_INT_ENABLE (1 << 29) +# define IB1_INT_ENABLE (1 << 30) +# define RB_INT_ENABLE (1 << 31) +#define CP_INT_STATUS 0xc128 +# define SCRATCH_INT_STAT (1 << 25) +# define TIME_STAMP_INT_STAT (1 << 26) +# define IB2_INT_STAT (1 << 29) +# define IB1_INT_STAT (1 << 30) +# define RB_INT_STAT (1 << 31) + +#define GRBM_INT_CNTL 0x8060 +# define RDERR_INT_ENABLE (1 << 0) +# define GUI_IDLE_INT_ENABLE (1 << 19) + +/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */ +#define CRTC_STATUS_FRAME_COUNT 0x6e98 + +/* 0x6bb8, 0x77b8, 0x103b8, 0x10fb8, 0x11bb8, 0x127b8 */ +#define VLINE_STATUS 0x6bb8 +# define VLINE_OCCURRED (1 << 0) +# define VLINE_ACK (1 << 4) +# define VLINE_STAT (1 << 12) +# define VLINE_INTERRUPT (1 << 16) +# define VLINE_INTERRUPT_TYPE (1 << 17) +/* 0x6bbc, 0x77bc, 0x103bc, 0x10fbc, 0x11bbc, 0x127bc */ +#define VBLANK_STATUS 0x6bbc +# define VBLANK_OCCURRED (1 << 0) +# define VBLANK_ACK (1 << 4) +# define VBLANK_STAT (1 << 12) +# define VBLANK_INTERRUPT (1 << 16) +# define VBLANK_INTERRUPT_TYPE (1 << 17) + +/* 0x6b40, 0x7740, 0x10340, 0x10f40, 0x11b40, 0x12740 */ +#define INT_MASK 0x6b40 +# define VBLANK_INT_MASK (1 << 0) +# define VLINE_INT_MASK (1 << 4) + +#define DISP_INTERRUPT_STATUS 0x60f4 +# define LB_D1_VLINE_INTERRUPT (1 << 2) +# define LB_D1_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD1_INTERRUPT (1 << 17) +# define DC_HPD1_RX_INTERRUPT (1 << 18) +# define DACA_AUTODETECT_INTERRUPT (1 << 22) +# define DACB_AUTODETECT_INTERRUPT (1 << 23) +# define DC_I2C_SW_DONE_INTERRUPT (1 << 24) +# define DC_I2C_HW_DONE_INTERRUPT (1 << 25) +#define DISP_INTERRUPT_STATUS_CONTINUE 0x60f8 +# define LB_D2_VLINE_INTERRUPT (1 << 2) +# define LB_D2_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD2_INTERRUPT (1 << 17) +# define DC_HPD2_RX_INTERRUPT (1 << 18) +# define DISP_TIMER_INTERRUPT (1 << 24) +#define DISP_INTERRUPT_STATUS_CONTINUE2 0x60fc +# define LB_D3_VLINE_INTERRUPT (1 << 2) +# define LB_D3_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD3_INTERRUPT (1 << 17) +# define DC_HPD3_RX_INTERRUPT (1 << 18) +#define DISP_INTERRUPT_STATUS_CONTINUE3 0x6100 +# define LB_D4_VLINE_INTERRUPT (1 << 2) +# define LB_D4_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD4_INTERRUPT (1 << 17) +# define DC_HPD4_RX_INTERRUPT (1 << 18) +#define DISP_INTERRUPT_STATUS_CONTINUE4 0x614c +# define LB_D5_VLINE_INTERRUPT (1 << 2) +# define LB_D5_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD5_INTERRUPT (1 << 17) +# define DC_HPD5_RX_INTERRUPT (1 << 18) +#define DISP_INTERRUPT_STATUS_CONTINUE5 0x6050 +# define LB_D6_VLINE_INTERRUPT (1 << 2) +# define LB_D6_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD6_INTERRUPT (1 << 17) +# define DC_HPD6_RX_INTERRUPT (1 << 18) + +/* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */ +#define GRPH_INT_STATUS 0x6858 +# define GRPH_PFLIP_INT_OCCURRED (1 << 0) +# define GRPH_PFLIP_INT_CLEAR (1 << 8) +/* 0x685c, 0x745c, 0x1005c, 0x10c5c, 0x1185c, 0x1245c */ +#define GRPH_INT_CONTROL 0x685c +# define GRPH_PFLIP_INT_MASK (1 << 0) +# define GRPH_PFLIP_INT_TYPE (1 << 8) + +#define DACA_AUTODETECT_INT_CONTROL 0x66c8 +#define DACB_AUTODETECT_INT_CONTROL 0x67c8 + +#define DC_HPD1_INT_STATUS 0x601c +#define DC_HPD2_INT_STATUS 0x6028 +#define DC_HPD3_INT_STATUS 0x6034 +#define DC_HPD4_INT_STATUS 0x6040 +#define DC_HPD5_INT_STATUS 0x604c +#define DC_HPD6_INT_STATUS 0x6058 +# define DC_HPDx_INT_STATUS (1 << 0) +# define DC_HPDx_SENSE (1 << 1) +# define DC_HPDx_RX_INT_STATUS (1 << 8) + +#define DC_HPD1_INT_CONTROL 0x6020 +#define DC_HPD2_INT_CONTROL 0x602c +#define DC_HPD3_INT_CONTROL 0x6038 +#define DC_HPD4_INT_CONTROL 0x6044 +#define DC_HPD5_INT_CONTROL 0x6050 +#define DC_HPD6_INT_CONTROL 0x605c +# define DC_HPDx_INT_ACK (1 << 0) +# define DC_HPDx_INT_POLARITY (1 << 8) +# define DC_HPDx_INT_EN (1 << 16) +# define DC_HPDx_RX_INT_ACK (1 << 20) +# define DC_HPDx_RX_INT_EN (1 << 24) + +#define DC_HPD1_CONTROL 0x6024 +#define DC_HPD2_CONTROL 0x6030 +#define DC_HPD3_CONTROL 0x603c +#define DC_HPD4_CONTROL 0x6048 +#define DC_HPD5_CONTROL 0x6054 +#define DC_HPD6_CONTROL 0x6060 +# define DC_HPDx_CONNECTION_TIMER(x) ((x) << 0) +# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) +# define DC_HPDx_EN (1 << 28) + #endif diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4b0225715b9..d178fa826ee 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -45,6 +45,7 @@ #define R700_RLC_UCODE_SIZE 1024 #define EVERGREEN_PFP_UCODE_SIZE 1120 #define EVERGREEN_PM4_UCODE_SIZE 1376 +#define EVERGREEN_RLC_UCODE_SIZE 768 /* Firmware Names */ MODULE_FIRMWARE("radeon/R600_pfp.bin"); @@ -71,12 +72,16 @@ MODULE_FIRMWARE("radeon/R600_rlc.bin"); MODULE_FIRMWARE("radeon/R700_rlc.bin"); MODULE_FIRMWARE("radeon/CEDAR_pfp.bin"); MODULE_FIRMWARE("radeon/CEDAR_me.bin"); +MODULE_FIRMWARE("radeon/CEDAR_rlc.bin"); MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin"); MODULE_FIRMWARE("radeon/REDWOOD_me.bin"); +MODULE_FIRMWARE("radeon/REDWOOD_rlc.bin"); MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin"); MODULE_FIRMWARE("radeon/JUNIPER_me.bin"); +MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin"); MODULE_FIRMWARE("radeon/CYRPESS_pfp.bin"); MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); +MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin"); int r600_debugfs_mc_info_init(struct radeon_device *rdev); @@ -84,6 +89,7 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev); int r600_mc_wait_for_idle(struct radeon_device *rdev); void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); +void r600_irq_disable(struct radeon_device *rdev); /* hpd for digital panel detect/disconnect */ bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) @@ -1461,20 +1467,20 @@ int r600_init_microcode(struct radeon_device *rdev) break; case CHIP_CEDAR: chip_name = "CEDAR"; - rlc_chip_name = ""; + rlc_chip_name = "CEDAR"; break; case CHIP_REDWOOD: chip_name = "REDWOOD"; - rlc_chip_name = ""; + rlc_chip_name = "REDWOOD"; break; case CHIP_JUNIPER: chip_name = "JUNIPER"; - rlc_chip_name = ""; + rlc_chip_name = "JUNIPER"; break; case CHIP_CYPRESS: case CHIP_HEMLOCK: chip_name = "CYPRESS"; - rlc_chip_name = ""; + rlc_chip_name = "CYPRESS"; break; default: BUG(); } @@ -1482,7 +1488,7 @@ int r600_init_microcode(struct radeon_device *rdev) if (rdev->family >= CHIP_CEDAR) { pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4; me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; - rlc_req_size = 0; + rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4; } else if (rdev->family >= CHIP_RV770) { pfp_req_size = R700_PFP_UCODE_SIZE * 4; me_req_size = R700_PM4_UCODE_SIZE * 4; @@ -1518,8 +1524,6 @@ int r600_init_microcode(struct radeon_device *rdev) err = -EINVAL; } - /* XXX until evergreen interrupts are supported */ - if (rdev->family < CHIP_CEDAR) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); if (err) @@ -1530,7 +1534,6 @@ int r600_init_microcode(struct radeon_device *rdev) rdev->rlc_fw->size, fw_name); err = -EINVAL; } - } out: platform_device_unregister(pdev); @@ -2309,10 +2312,11 @@ static void r600_ih_ring_fini(struct radeon_device *rdev) } } -static void r600_rlc_stop(struct radeon_device *rdev) +void r600_rlc_stop(struct radeon_device *rdev) { - if (rdev->family >= CHIP_RV770) { + if ((rdev->family >= CHIP_RV770) && + (rdev->family <= CHIP_RV740)) { /* r7xx asics need to soft reset RLC before halting */ WREG32(SRBM_SOFT_RESET, SOFT_RESET_RLC); RREG32(SRBM_SOFT_RESET); @@ -2349,7 +2353,12 @@ static int r600_rlc_init(struct radeon_device *rdev) WREG32(RLC_UCODE_CNTL, 0); fw_data = (const __be32 *)rdev->rlc_fw->data; - if (rdev->family >= CHIP_RV770) { + if (rdev->family >= CHIP_CEDAR) { + for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) { + WREG32(RLC_UCODE_ADDR, i); + WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); + } + } else if (rdev->family >= CHIP_RV770) { for (i = 0; i < R700_RLC_UCODE_SIZE; i++) { WREG32(RLC_UCODE_ADDR, i); WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); @@ -2379,7 +2388,7 @@ static void r600_enable_interrupts(struct radeon_device *rdev) rdev->ih.enabled = true; } -static void r600_disable_interrupts(struct radeon_device *rdev) +void r600_disable_interrupts(struct radeon_device *rdev) { u32 ih_rb_cntl = RREG32(IH_RB_CNTL); u32 ih_cntl = RREG32(IH_CNTL); @@ -2494,7 +2503,10 @@ int r600_irq_init(struct radeon_device *rdev) WREG32(IH_CNTL, ih_cntl); /* force the active interrupt state to all disabled */ - r600_disable_interrupt_state(rdev); + if (rdev->family >= CHIP_CEDAR) + evergreen_disable_interrupt_state(rdev); + else + r600_disable_interrupt_state(rdev); /* enable irqs */ r600_enable_interrupts(rdev); @@ -2504,7 +2516,7 @@ int r600_irq_init(struct radeon_device *rdev) void r600_irq_suspend(struct radeon_device *rdev) { - r600_disable_interrupts(rdev); + r600_irq_disable(rdev); r600_rlc_stop(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index acf21d7e3cb..e0132ef093b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -372,7 +372,7 @@ struct radeon_irq { bool installed; bool sw_int; /* FIXME: use a define max crtc rather than hardcode it */ - bool crtc_vblank_int[2]; + bool crtc_vblank_int[6]; wait_queue_head_t vblank_queue; /* FIXME: use defines for max hpd/dacs */ bool hpd[6]; @@ -1324,6 +1324,8 @@ extern void r600_irq_fini(struct radeon_device *rdev); extern void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_irq_set(struct radeon_device *rdev); extern void r600_irq_suspend(struct radeon_device *rdev); +extern void r600_disable_interrupts(struct radeon_device *rdev); +extern void r600_rlc_stop(struct radeon_device *rdev); /* r600 audio */ extern int r600_audio_init(struct radeon_device *rdev); extern int r600_audio_tmds_index(struct drm_encoder *encoder); @@ -1343,6 +1345,7 @@ extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, extern void r700_cp_stop(struct radeon_device *rdev); extern void r700_cp_fini(struct radeon_device *rdev); +void evergreen_disable_interrupt_state(struct radeon_device *rdev); /* evergreen */ struct evergreen_mc_save { diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 3a576ab805c..f835333c1b6 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -643,9 +643,9 @@ static struct radeon_asic evergreen_asic = { .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, .ring_ib_execute = &r600_ring_ib_execute, - .irq_set = NULL, - .irq_process = NULL, - .get_vblank_counter = NULL, + .irq_set = &evergreen_irq_set, + .irq_process = &evergreen_irq_process, + .get_vblank_counter = &evergreen_get_vblank_counter, .fence_ring_emit = NULL, .cs_parse = NULL, .copy_blit = NULL, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 1d451ff0367..ef2c7ba1bdc 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -294,4 +294,8 @@ void evergreen_hpd_fini(struct radeon_device *rdev); bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void evergreen_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); +u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc); +int evergreen_irq_set(struct radeon_device *rdev); +int evergreen_irq_process(struct radeon_device *rdev); + #endif -- cgit v1.2.3-70-g09d2 From a7433742d62c6e0e1173bd144a4aef7724b48d60 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 9 Apr 2010 15:31:09 +1000 Subject: drm/radeon: fix cypress firmware typo. Pointed out by Dave Witbrodt. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d178fa826ee..25aa2f80893 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -79,7 +79,7 @@ MODULE_FIRMWARE("radeon/REDWOOD_rlc.bin"); MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin"); MODULE_FIRMWARE("radeon/JUNIPER_me.bin"); MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin"); -MODULE_FIRMWARE("radeon/CYRPESS_pfp.bin"); +MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin"); MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin"); -- cgit v1.2.3-70-g09d2 From 6b8b1786a8c29ce6e32298b93ac8d4a18a2b11c4 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 7 Apr 2010 10:21:31 +0000 Subject: drm/radeon/kms: enable use of unmappable VRAM V2 This patch enable the use of unmappable VRAM thanks to previous TTM infrastructure change. V2 update after io_mem_reserve/io_mem_free callback balancing Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 5 ----- drivers/gpu/drm/radeon/r100.c | 5 ----- drivers/gpu/drm/radeon/r600.c | 5 ----- drivers/gpu/drm/radeon/rv770.c | 5 ----- 4 files changed, 20 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 647a0efdc35..5c7c5c39930 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -475,11 +475,6 @@ int evergreen_mc_init(struct radeon_device *rdev) rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; rdev->mc.visible_vram_size = rdev->mc.aper_size; - /* FIXME remove this once we support unmappable VRAM */ - if (rdev->mc.mc_vram_size > rdev->mc.aper_size) { - rdev->mc.mc_vram_size = rdev->mc.aper_size; - rdev->mc.real_vram_size = rdev->mc.aper_size; - } r600_vram_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 3ae51ada1ab..3ce549706c2 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2001,11 +2001,6 @@ void r100_vram_init_sizes(struct radeon_device *rdev) else rdev->mc.mc_vram_size = rdev->mc.real_vram_size; } - /* FIXME remove this once we support unmappable VRAM */ - if (rdev->mc.mc_vram_size > rdev->mc.aper_size) { - rdev->mc.mc_vram_size = rdev->mc.aper_size; - rdev->mc.real_vram_size = rdev->mc.aper_size; - } } void r100_vga_set_state(struct radeon_device *rdev, bool state) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 5509354c7c8..dce41b167f8 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -713,11 +713,6 @@ int r600_mc_init(struct radeon_device *rdev) rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.visible_vram_size = rdev->mc.aper_size; - /* FIXME remove this once we support unmappable VRAM */ - if (rdev->mc.mc_vram_size > rdev->mc.aper_size) { - rdev->mc.mc_vram_size = rdev->mc.aper_size; - rdev->mc.real_vram_size = rdev->mc.aper_size; - } r600_vram_gtt_location(rdev, &rdev->mc); if (rdev->flags & RADEON_IS_IGP) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 9f37d2efb0a..e2089faa959 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -905,11 +905,6 @@ int rv770_mc_init(struct radeon_device *rdev) rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.visible_vram_size = rdev->mc.aper_size; - /* FIXME remove this once we support unmappable VRAM */ - if (rdev->mc.mc_vram_size > rdev->mc.aper_size) { - rdev->mc.mc_vram_size = rdev->mc.aper_size; - rdev->mc.real_vram_size = rdev->mc.aper_size; - } r600_vram_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); -- cgit v1.2.3-70-g09d2 From f2594933df9719bd2b0aaaa8ea9b2b850d6e1c42 Mon Sep 17 00:00:00 2001 From: Christian Koenig Date: Sat, 10 Apr 2010 03:13:16 +0200 Subject: drm/radeon/kms: HDMI irq support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements irq support for HDMI audio output. Now the polling timer is only enabled if irq support isn't available. Signed-off-by: Christian König Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 33 +++++++++++++++++++++ drivers/gpu/drm/radeon/r600_audio.c | 21 ++++++++------ drivers/gpu/drm/radeon/r600_hdmi.c | 54 +++++++++++++++++++++-------------- drivers/gpu/drm/radeon/r600_reg.h | 57 +++++++++++++++++++------------------ drivers/gpu/drm/radeon/radeon.h | 3 ++ 5 files changed, 112 insertions(+), 56 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c325cb12105..2ec423c3f3f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2527,6 +2527,7 @@ int r600_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 mode_int = 0; u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0; + u32 hdmi1, hdmi2; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); @@ -2540,7 +2541,9 @@ int r600_irq_set(struct radeon_device *rdev) return 0; } + hdmi1 = RREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN; if (ASIC_IS_DCE3(rdev)) { + hdmi2 = RREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN; hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; @@ -2550,6 +2553,7 @@ int r600_irq_set(struct radeon_device *rdev) hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; } } else { + hdmi2 = RREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN; hpd1 = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd2 = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd3 = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & ~DC_HPDx_INT_EN; @@ -2591,10 +2595,20 @@ int r600_irq_set(struct radeon_device *rdev) DRM_DEBUG("r600_irq_set: hpd 6\n"); hpd6 |= DC_HPDx_INT_EN; } + if (rdev->irq.hdmi[0]) { + DRM_DEBUG("r600_irq_set: hdmi 1\n"); + hdmi1 |= R600_HDMI_INT_EN; + } + if (rdev->irq.hdmi[1]) { + DRM_DEBUG("r600_irq_set: hdmi 2\n"); + hdmi2 |= R600_HDMI_INT_EN; + } WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(DxMODE_INT_MASK, mode_int); + WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1); if (ASIC_IS_DCE3(rdev)) { + WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2); WREG32(DC_HPD1_INT_CONTROL, hpd1); WREG32(DC_HPD2_INT_CONTROL, hpd2); WREG32(DC_HPD3_INT_CONTROL, hpd3); @@ -2604,6 +2618,7 @@ int r600_irq_set(struct radeon_device *rdev) WREG32(DC_HPD6_INT_CONTROL, hpd6); } } else { + WREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, hdmi2); WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1); WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2); WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, hpd3); @@ -2687,6 +2702,18 @@ static inline void r600_irq_ack(struct radeon_device *rdev, WREG32(DC_HPD6_INT_CONTROL, tmp); } } + if (RREG32(R600_HDMI_BLOCK1 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) { + WREG32_P(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK); + } + if (ASIC_IS_DCE3(rdev)) { + if (RREG32(R600_HDMI_BLOCK3 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) { + WREG32_P(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK); + } + } else { + if (RREG32(R600_HDMI_BLOCK2 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) { + WREG32_P(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK); + } + } } void r600_irq_disable(struct radeon_device *rdev) @@ -2740,6 +2767,8 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) * 19 1 FP Hot plug detection B * 19 2 DAC A auto-detection * 19 3 DAC B auto-detection + * 21 4 HDMI block A + * 21 5 HDMI block B * 176 - CP_INT RB * 177 - CP_INT IB1 * 178 - CP_INT IB2 @@ -2879,6 +2908,10 @@ restart_ih: break; } break; + case 21: /* HDMI */ + DRM_DEBUG("IH: HDMI: 0x%x\n", src_data); + r600_audio_schedule_polling(rdev); + break; case 176: /* CP_INT in ring buffer */ case 177: /* CP_INT in IB1 */ case 178: /* CP_INT in IB2 */ diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index ed8d3989f17..2b26553c352 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -103,6 +103,15 @@ uint8_t r600_audio_category_code(struct radeon_device *rdev) return (RREG32(R600_AUDIO_STATUS_BITS) >> 8) & 0xff; } +/* + * schedule next audio update event + */ +void r600_audio_schedule_polling(struct radeon_device *rdev) +{ + mod_timer(&rdev->audio_timer, + jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL)); +} + /* * update all hdmi interfaces with current audio parameters */ @@ -136,16 +145,12 @@ static void r600_audio_update_hdmi(unsigned long param) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->audio_polling_active) { - still_going = 1; - if (changes || r600_hdmi_buffer_status_changed(encoder)) - r600_hdmi_update_audio_settings(encoder); - } + still_going |= radeon_encoder->audio_polling_active; + if (changes || r600_hdmi_buffer_status_changed(encoder)) + r600_hdmi_update_audio_settings(encoder); } - if(still_going) - mod_timer(&rdev->audio_timer, - jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL)); + if(still_going) r600_audio_schedule_polling(rdev); } /* diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index d014472d0d3..40b1aca6d1f 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -290,17 +290,15 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder) if (!offset) return; - if (r600_hdmi_is_audio_buffer_filled(encoder)) { - /* disable audio workaround and start delivering of audio frames */ - WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001); + if (!radeon_encoder->hdmi_audio_workaround || + r600_hdmi_is_audio_buffer_filled(encoder)) { - } else if (radeon_encoder->hdmi_audio_workaround) { - /* enable audio workaround and start delivering of audio frames */ - WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001); + /* disable audio workaround */ + WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001); } else { - /* disable audio workaround and stop delivering of audio frames */ - WREG32_P(offset+R600_HDMI_CNTL, 0x00000000, ~0x00001001); + /* enable audio workaround */ + WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001); } } @@ -345,9 +343,6 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod /* audio packets per line, does anyone know how to calc this ? */ WREG32_P(offset+R600_HDMI_CNTL, 0x00040000, ~0x001F0000); - - /* update? reset? don't realy know */ - WREG32_P(offset+R600_HDMI_CNTL, 0x14000000, ~0x14000000); } /* @@ -416,9 +411,6 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) r600_hdmi_audioinfoframe(encoder, channels-1, 0, 0, 0, 0, 0, 0, 0); r600_hdmi_audio_workaround(encoder); - - /* update? reset? don't realy know */ - WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000); } static int r600_hdmi_find_free_block(struct drm_device *dev) @@ -487,6 +479,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t offset; if (ASIC_IS_DCE4(rdev)) return; @@ -500,10 +493,10 @@ void r600_hdmi_enable(struct drm_encoder *encoder) } } + offset = radeon_encoder->hdmi_offset; if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1); } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { - int offset = radeon_encoder->hdmi_offset; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4); @@ -519,7 +512,20 @@ void r600_hdmi_enable(struct drm_encoder *encoder) } } - r600_audio_enable_polling(encoder); + if (rdev->irq.installed + && rdev->family != CHIP_RS600 + && rdev->family != CHIP_RS690 + && rdev->family != CHIP_RS740) { + + /* if irq is available use it */ + rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true; + radeon_irq_set(rdev); + + r600_audio_disable_polling(encoder); + } else { + /* if not fallback to polling */ + r600_audio_enable_polling(encoder); + } DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); @@ -533,24 +539,30 @@ void r600_hdmi_disable(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint8_t offset; if (ASIC_IS_DCE4(rdev)) return; - if (!radeon_encoder->hdmi_offset) { + offset = radeon_encoder->hdmi_offset; + if (!offset) { dev_err(rdev->dev, "Disabling not enabled HDMI\n"); return; } - r600_audio_disable_polling(encoder); - DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", - radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); + offset, radeon_encoder->encoder_id); + + /* disable irq */ + rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = false; + radeon_irq_set(rdev); + + /* disable polling */ + r600_audio_disable_polling(encoder); if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1); } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { - int offset = radeon_encoder->hdmi_offset; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4); diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h index 7b1d22370f6..d84612ae47e 100644 --- a/drivers/gpu/drm/radeon/r600_reg.h +++ b/drivers/gpu/drm/radeon/r600_reg.h @@ -157,33 +157,36 @@ #define R600_HDMI_BLOCK3 0x7800 /* HDMI registers */ -#define R600_HDMI_ENABLE 0x00 -#define R600_HDMI_STATUS 0x04 -#define R600_HDMI_CNTL 0x08 -#define R600_HDMI_UNKNOWN_0 0x0C -#define R600_HDMI_AUDIOCNTL 0x10 -#define R600_HDMI_VIDEOCNTL 0x14 -#define R600_HDMI_VERSION 0x18 -#define R600_HDMI_UNKNOWN_1 0x28 -#define R600_HDMI_VIDEOINFOFRAME_0 0x54 -#define R600_HDMI_VIDEOINFOFRAME_1 0x58 -#define R600_HDMI_VIDEOINFOFRAME_2 0x5c -#define R600_HDMI_VIDEOINFOFRAME_3 0x60 -#define R600_HDMI_32kHz_CTS 0xac -#define R600_HDMI_32kHz_N 0xb0 -#define R600_HDMI_44_1kHz_CTS 0xb4 -#define R600_HDMI_44_1kHz_N 0xb8 -#define R600_HDMI_48kHz_CTS 0xbc -#define R600_HDMI_48kHz_N 0xc0 -#define R600_HDMI_AUDIOINFOFRAME_0 0xcc -#define R600_HDMI_AUDIOINFOFRAME_1 0xd0 -#define R600_HDMI_IEC60958_1 0xd4 -#define R600_HDMI_IEC60958_2 0xd8 -#define R600_HDMI_UNKNOWN_2 0xdc -#define R600_HDMI_AUDIO_DEBUG_0 0xe0 -#define R600_HDMI_AUDIO_DEBUG_1 0xe4 -#define R600_HDMI_AUDIO_DEBUG_2 0xe8 -#define R600_HDMI_AUDIO_DEBUG_3 0xec +#define R600_HDMI_ENABLE 0x00 +#define R600_HDMI_STATUS 0x04 +# define R600_HDMI_INT_PENDING (1 << 29) +#define R600_HDMI_CNTL 0x08 +# define R600_HDMI_INT_EN (1 << 28) +# define R600_HDMI_INT_ACK (1 << 29) +#define R600_HDMI_UNKNOWN_0 0x0C +#define R600_HDMI_AUDIOCNTL 0x10 +#define R600_HDMI_VIDEOCNTL 0x14 +#define R600_HDMI_VERSION 0x18 +#define R600_HDMI_UNKNOWN_1 0x28 +#define R600_HDMI_VIDEOINFOFRAME_0 0x54 +#define R600_HDMI_VIDEOINFOFRAME_1 0x58 +#define R600_HDMI_VIDEOINFOFRAME_2 0x5c +#define R600_HDMI_VIDEOINFOFRAME_3 0x60 +#define R600_HDMI_32kHz_CTS 0xac +#define R600_HDMI_32kHz_N 0xb0 +#define R600_HDMI_44_1kHz_CTS 0xb4 +#define R600_HDMI_44_1kHz_N 0xb8 +#define R600_HDMI_48kHz_CTS 0xbc +#define R600_HDMI_48kHz_N 0xc0 +#define R600_HDMI_AUDIOINFOFRAME_0 0xcc +#define R600_HDMI_AUDIOINFOFRAME_1 0xd0 +#define R600_HDMI_IEC60958_1 0xd4 +#define R600_HDMI_IEC60958_2 0xd8 +#define R600_HDMI_UNKNOWN_2 0xdc +#define R600_HDMI_AUDIO_DEBUG_0 0xe0 +#define R600_HDMI_AUDIO_DEBUG_1 0xe4 +#define R600_HDMI_AUDIO_DEBUG_2 0xe8 +#define R600_HDMI_AUDIO_DEBUG_3 0xec /* HDMI additional config base register addresses */ #define R600_HDMI_CONFIG1 0x7600 diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 42217af5814..ab29d972a16 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -376,6 +376,8 @@ struct radeon_irq { wait_queue_head_t vblank_queue; /* FIXME: use defines for max hpd/dacs */ bool hpd[6]; + /* FIXME: use defines for max HDMI blocks */ + bool hdmi[2]; spinlock_t sw_lock; int sw_refcount; }; @@ -1332,6 +1334,7 @@ extern int r600_audio_bits_per_sample(struct radeon_device *rdev); extern int r600_audio_rate(struct radeon_device *rdev); extern uint8_t r600_audio_status_bits(struct radeon_device *rdev); extern uint8_t r600_audio_category_code(struct radeon_device *rdev); +extern void r600_audio_schedule_polling(struct radeon_device *rdev); extern void r600_audio_enable_polling(struct drm_encoder *encoder); extern void r600_audio_disable_polling(struct drm_encoder *encoder); extern void r600_audio_fini(struct radeon_device *rdev); -- cgit v1.2.3-70-g09d2 From def9ba9cf6a8266ee1ffd72556db002c3a2663db Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 12:39:58 -0400 Subject: drm/radeon/kms: add gui_idle callback Check to see if the GUI engine and related blocks (2D, 3D, CP, etc) are idle or not. There are a number of cases when we need to know if the drawing engine is busy. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 8 ++++++++ drivers/gpu/drm/radeon/r600.c | 8 ++++++++ drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_asic.c | 14 ++++++++++++++ drivers/gpu/drm/radeon/radeon_asic.h | 2 ++ 5 files changed, 34 insertions(+) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 9bdccb96499..e62116e222a 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -67,6 +67,14 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +bool r100_gui_idle(struct radeon_device *rdev) +{ + if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) + return false; + else + return true; +} + /* hpd for digital panel detect/disconnect */ bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 2ec423c3f3f..1c85dcb168a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,6 +92,14 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); +bool r600_gui_idle(struct radeon_device *rdev) +{ + if (RREG32(GRBM_STATUS) & GUI_ACTIVE) + return false; + else + return true; +} + /* hpd for digital panel detect/disconnect */ bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index ab29d972a16..bb4a2a66f07 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -803,6 +803,7 @@ struct radeon_asic { * through ring. */ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); + bool (*gui_idle)(struct radeon_device *rdev); }; /* @@ -1209,6 +1210,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_fini(rdev) (rdev)->asic->hpd_fini((rdev)) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) +#define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index f835333c1b6..42708462fd4 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -165,6 +165,7 @@ static struct radeon_asic r100_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r200_asic = { @@ -203,6 +204,7 @@ static struct radeon_asic r200_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r300_asic = { @@ -242,6 +244,7 @@ static struct radeon_asic r300_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r300_asic_pcie = { @@ -280,6 +283,7 @@ static struct radeon_asic r300_asic_pcie = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r420_asic = { @@ -319,6 +323,7 @@ static struct radeon_asic r420_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic rs400_asic = { @@ -358,6 +363,7 @@ static struct radeon_asic rs400_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic rs600_asic = { @@ -397,6 +403,7 @@ static struct radeon_asic rs600_asic = { .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic rs690_asic = { @@ -436,6 +443,7 @@ static struct radeon_asic rs690_asic = { .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic rv515_asic = { @@ -475,6 +483,7 @@ static struct radeon_asic rv515_asic = { .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r520_asic = { @@ -514,6 +523,7 @@ static struct radeon_asic r520_asic = { .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r600_asic = { @@ -552,6 +562,7 @@ static struct radeon_asic r600_asic = { .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, + .gui_idle = &r600_gui_idle, }; static struct radeon_asic rs780_asic = { @@ -590,6 +601,7 @@ static struct radeon_asic rs780_asic = { .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, + .gui_idle = &r600_gui_idle, }; static struct radeon_asic rv770_asic = { @@ -628,6 +640,7 @@ static struct radeon_asic rv770_asic = { .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, + .gui_idle = &r600_gui_idle, }; static struct radeon_asic evergreen_asic = { @@ -664,6 +677,7 @@ static struct radeon_asic evergreen_asic = { .hpd_fini = &evergreen_hpd_fini, .hpd_sense = &evergreen_hpd_sense, .hpd_set_polarity = &evergreen_hpd_set_polarity, + .gui_idle = &r600_gui_idle, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index ef2c7ba1bdc..c74bf9bd26c 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -126,6 +126,7 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p, void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); +extern bool r100_gui_idle(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 */ @@ -269,6 +270,7 @@ bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); +extern bool r600_gui_idle(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 -- cgit v1.2.3-70-g09d2 From 2031f77ca9c17133869b265210418959a909d259 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 12:52:11 -0400 Subject: drm/radeon/kms: add support for gui idle interrupts (v4) Useful for certain power management operations. You need to wait for the GUI engine (2D, 3D, CP, etc.) to be idle before changing clocks or adjusting engine parameters. (v2) Fix gui idle enable on pre-r6xx asics (v3) The gui idle interrrupt status bit is permanently asserted on pre-r6xx chips, but the interrrupt is still generated. workaround it in the driver. (v4) Add support for evergreen Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 11 +++++++++++ drivers/gpu/drm/radeon/r100.c | 20 ++++++++++++++++++++ drivers/gpu/drm/radeon/r600.c | 11 +++++++++++ drivers/gpu/drm/radeon/radeon.h | 4 ++++ drivers/gpu/drm/radeon/radeon_device.c | 1 + drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 ++ drivers/gpu/drm/radeon/radeon_pm.c | 1 + drivers/gpu/drm/radeon/radeon_reg.h | 3 +++ drivers/gpu/drm/radeon/rs600.c | 22 +++++++++++++++++++++- 9 files changed, 74 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index b3d168fb89e..0137a4cd90f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1418,6 +1418,7 @@ int evergreen_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0; u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; + u32 grbm_int_cntl = 0; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); @@ -1490,8 +1491,13 @@ int evergreen_irq_set(struct radeon_device *rdev) DRM_DEBUG("evergreen_irq_set: hpd 6\n"); hpd6 |= DC_HPDx_INT_EN; } + if (rdev->irq.gui_idle) { + DRM_DEBUG("gui idle\n"); + grbm_int_cntl |= GUI_IDLE_INT_ENABLE; + } WREG32(CP_INT_CNTL, cp_int_cntl); + WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); @@ -1853,6 +1859,11 @@ restart_ih: case 181: /* CP EOP event */ DRM_DEBUG("IH: CP EOP\n"); break; + case 233: /* GUI IDLE */ + DRM_DEBUG("IH: CP EOP\n"); + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index e62116e222a..d35298684f3 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -262,6 +262,9 @@ int r100_irq_set(struct radeon_device *rdev) if (rdev->irq.sw_int) { tmp |= RADEON_SW_INT_ENABLE; } + if (rdev->irq.gui_idle) { + tmp |= RADEON_GUI_IDLE_MASK; + } if (rdev->irq.crtc_vblank_int[0]) { tmp |= RADEON_CRTC_VBLANK_MASK; } @@ -296,6 +299,12 @@ static inline uint32_t r100_irq_ack(struct radeon_device *rdev) RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT | RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT; + /* the interrupt works, but the status bit is permanently asserted */ + if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) { + if (!rdev->irq.gui_idle_acked) + irq_mask |= RADEON_GUI_IDLE_STAT; + } + if (irqs) { WREG32(RADEON_GEN_INT_STATUS, irqs); } @@ -307,6 +316,9 @@ int r100_irq_process(struct radeon_device *rdev) uint32_t status, msi_rearm; bool queue_hotplug = false; + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; + status = r100_irq_ack(rdev); if (!status) { return IRQ_NONE; @@ -319,6 +331,12 @@ int r100_irq_process(struct radeon_device *rdev) if (status & RADEON_SW_INT_TEST) { radeon_fence_process(rdev); } + /* gui idle interrupt */ + if (status & RADEON_GUI_IDLE_STAT) { + rdev->irq.gui_idle_acked = true; + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + } /* Vertical blank interrupts */ if (status & RADEON_CRTC_VBLANK_STAT) { drm_handle_vblank(rdev->ddev, 0); @@ -340,6 +358,8 @@ int r100_irq_process(struct radeon_device *rdev) } status = r100_irq_ack(rdev); } + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; if (queue_hotplug) queue_work(rdev->wq, &rdev->hotplug_work); if (rdev->msi_enabled) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1c85dcb168a..094c29dd96e 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2535,6 +2535,7 @@ int r600_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 mode_int = 0; u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0; + u32 grbm_int_cntl = 0; u32 hdmi1, hdmi2; if (!rdev->irq.installed) { @@ -2611,9 +2612,14 @@ int r600_irq_set(struct radeon_device *rdev) DRM_DEBUG("r600_irq_set: hdmi 2\n"); hdmi2 |= R600_HDMI_INT_EN; } + if (rdev->irq.gui_idle) { + DRM_DEBUG("gui idle\n"); + grbm_int_cntl |= GUI_IDLE_INT_ENABLE; + } WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(DxMODE_INT_MASK, mode_int); + WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1); if (ASIC_IS_DCE3(rdev)) { WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2); @@ -2929,6 +2935,11 @@ restart_ih: case 181: /* CP EOP event */ DRM_DEBUG("IH: CP EOP\n"); break; + case 233: /* GUI IDLE */ + DRM_DEBUG("IH: CP EOP\n"); + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bb4a2a66f07..433937109af 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -376,6 +376,9 @@ struct radeon_irq { wait_queue_head_t vblank_queue; /* FIXME: use defines for max hpd/dacs */ bool hpd[6]; + bool gui_idle; + bool gui_idle_acked; + wait_queue_head_t idle_queue; /* FIXME: use defines for max HDMI blocks */ bool hdmi[2]; spinlock_t sw_lock; @@ -694,6 +697,7 @@ struct radeon_pm { int active_crtcs; int req_vblank; bool vblank_sync; + bool gui_idle; fixed20_12 max_bandwidth; fixed20_12 igp_sideport_mclk; fixed20_12 igp_system_mclk; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 26217ffe035..53a2c27dd8f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -602,6 +602,7 @@ int radeon_device_init(struct radeon_device *rdev, rwlock_init(&rdev->fence_drv.lock); INIT_LIST_HEAD(&rdev->gem.objects); init_waitqueue_head(&rdev->irq.vblank_queue); + init_waitqueue_head(&rdev->irq.idle_queue); /* setup workqueue */ rdev->wq = create_workqueue("radeon"); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 8fa40ed397e..059bfa4098d 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -68,6 +68,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ rdev->irq.sw_int = false; + rdev->irq.gui_idle = false; for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; for (i = 0; i < 6; i++) @@ -97,6 +98,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) } /* Disable *all* interrupts */ rdev->irq.sw_int = false; + rdev->irq.gui_idle = false; for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; for (i = 0; i < 6; i++) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a4b57493aa7..6dfeb9cf16b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -27,6 +27,7 @@ #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 #define RADEON_WAIT_VBLANK_TIMEOUT 200 +#define RADEON_WAIT_IDLE_TIMEOUT 200 static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index eabbc9cf30a..74d1cbfa23a 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -995,6 +995,7 @@ # define RADEON_FP_DETECT_MASK (1 << 4) # define RADEON_CRTC2_VBLANK_MASK (1 << 9) # define RADEON_FP2_DETECT_MASK (1 << 10) +# define RADEON_GUI_IDLE_MASK (1 << 19) # define RADEON_SW_INT_ENABLE (1 << 25) #define RADEON_GEN_INT_STATUS 0x0044 # define AVIVO_DISPLAY_INT_STATUS (1 << 0) @@ -1006,6 +1007,8 @@ # define RADEON_CRTC2_VBLANK_STAT_ACK (1 << 9) # define RADEON_FP2_DETECT_STAT (1 << 10) # define RADEON_FP2_DETECT_STAT_ACK (1 << 10) +# define RADEON_GUI_IDLE_STAT (1 << 19) +# define RADEON_GUI_IDLE_STAT_ACK (1 << 19) # define RADEON_SW_INT_FIRE (1 << 26) # define RADEON_SW_INT_TEST (1 << 25) # define RADEON_SW_INT_TEST_ACK (1 << 25) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 5e3f21861f4..b312b72d76c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -382,6 +382,9 @@ int rs600_irq_set(struct radeon_device *rdev) if (rdev->irq.sw_int) { tmp |= S_000040_SW_INT_EN(1); } + if (rdev->irq.gui_idle) { + tmp |= S_000040_GUI_IDLE(1); + } if (rdev->irq.crtc_vblank_int[0]) { mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1); } @@ -404,9 +407,15 @@ int rs600_irq_set(struct radeon_device *rdev) static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_int) { uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS); - uint32_t irq_mask = ~C_000044_SW_INT; + uint32_t irq_mask = S_000044_SW_INT(1); u32 tmp; + /* the interrupt works, but the status bit is permanently asserted */ + if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) { + if (!rdev->irq.gui_idle_acked) + irq_mask |= S_000044_GUI_IDLE_STAT(1); + } + if (G_000044_DISPLAY_INT_STAT(irqs)) { *r500_disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS); if (G_007EDC_LB_D1_VBLANK_INTERRUPT(*r500_disp_int)) { @@ -454,6 +463,9 @@ int rs600_irq_process(struct radeon_device *rdev) uint32_t r500_disp_int; bool queue_hotplug = false; + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; + status = rs600_irq_ack(rdev, &r500_disp_int); if (!status && !r500_disp_int) { return IRQ_NONE; @@ -462,6 +474,12 @@ int rs600_irq_process(struct radeon_device *rdev) /* SW interrupt */ if (G_000044_SW_INT(status)) radeon_fence_process(rdev); + /* GUI idle */ + if (G_000040_GUI_IDLE(status)) { + rdev->irq.gui_idle_acked = true; + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + } /* Vertical blank interrupts */ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) { drm_handle_vblank(rdev->ddev, 0); @@ -483,6 +501,8 @@ int rs600_irq_process(struct radeon_device *rdev) } status = rs600_irq_ack(rdev, &r500_disp_int); } + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; if (queue_hotplug) queue_work(rdev->wq, &rdev->hotplug_work); if (rdev->msi_enabled) { -- cgit v1.2.3-70-g09d2 From bae6b5627387a950a8faf366d6027bd0a7a93078 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 13:38:05 -0400 Subject: drm/radeon/kms/pm: add asic specific callbacks for setting power state (v2) (v2) Add evergreen vbl checks Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_reg.h | 1 + drivers/gpu/drm/radeon/r100.c | 37 ++++++++++++ drivers/gpu/drm/radeon/r600.c | 37 ++++++++++++ drivers/gpu/drm/radeon/radeon.h | 4 ++ drivers/gpu/drm/radeon/radeon_asic.c | 14 +++++ drivers/gpu/drm/radeon/radeon_asic.h | 3 + drivers/gpu/drm/radeon/radeon_pm.c | 100 +++++++++++++++++---------------- drivers/gpu/drm/radeon/radeon_reg.h | 1 - 8 files changed, 148 insertions(+), 49 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index f7c7c964343..9dba6d97d9b 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -166,6 +166,7 @@ /* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */ #define EVERGREEN_CRTC_CONTROL 0x6e70 # define EVERGREEN_CRTC_MASTER_EN (1 << 0) +#define EVERGREEN_CRTC_STATUS 0x6e8c #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index d35298684f3..b076b96f8b6 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -67,6 +67,43 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +void r100_set_power_state(struct radeon_device *rdev) +{ + /* if *_clock_mode are the same, *_power_state are as well */ + if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) + return; + + DRM_INFO("Setting: e: %d m: %d p: %d\n", + rdev->pm.requested_clock_mode->sclk, + rdev->pm.requested_clock_mode->mclk, + rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + + /* set pcie lanes */ + /* TODO */ + + /* set voltage */ + /* TODO */ + + /* set engine clock */ + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + +#if 0 + /* set memory clock */ + if (rdev->asic->set_memory_clock) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + } +#endif + + rdev->pm.current_power_state = rdev->pm.requested_power_state; + rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; +} + bool r100_gui_idle(struct radeon_device *rdev) { if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 094c29dd96e..c2d1946535a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,6 +92,43 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); +void r600_set_power_state(struct radeon_device *rdev) +{ + /* if *_clock_mode are the same, *_power_state are as well */ + if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) + return; + + DRM_INFO("Setting: e: %d m: %d p: %d\n", + rdev->pm.requested_clock_mode->sclk, + rdev->pm.requested_clock_mode->mclk, + rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + + /* set pcie lanes */ + /* TODO */ + + /* set voltage */ + /* TODO */ + + /* set engine clock */ + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + +#if 0 + /* set memory clock */ + if (rdev->asic->set_memory_clock) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + } +#endif + + rdev->pm.current_power_state = rdev->pm.requested_power_state; + rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; +} + bool r600_gui_idle(struct radeon_device *rdev) { if (RREG32(GRBM_STATUS) & GUI_ACTIVE) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 433937109af..11fe1d1444c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -175,6 +175,8 @@ void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); +bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); +void radeon_sync_with_vblank(struct radeon_device *rdev); /* * Fences. @@ -808,6 +810,7 @@ struct radeon_asic { */ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); bool (*gui_idle)(struct radeon_device *rdev); + void (*set_power_state)(struct radeon_device *rdev); }; /* @@ -1215,6 +1218,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) +#define radeon_set_power_state(rdev) (rdev)->asic->set_power_state((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 42708462fd4..48893fbb658 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -166,6 +166,7 @@ static struct radeon_asic r100_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r200_asic = { @@ -205,6 +206,7 @@ static struct radeon_asic r200_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r300_asic = { @@ -245,6 +247,7 @@ static struct radeon_asic r300_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r300_asic_pcie = { @@ -284,6 +287,7 @@ static struct radeon_asic r300_asic_pcie = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r420_asic = { @@ -324,6 +328,7 @@ static struct radeon_asic r420_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic rs400_asic = { @@ -364,6 +369,7 @@ static struct radeon_asic rs400_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic rs600_asic = { @@ -404,6 +410,7 @@ static struct radeon_asic rs600_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic rs690_asic = { @@ -444,6 +451,7 @@ static struct radeon_asic rs690_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic rv515_asic = { @@ -484,6 +492,7 @@ static struct radeon_asic rv515_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r520_asic = { @@ -524,6 +533,7 @@ static struct radeon_asic r520_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r600_asic = { @@ -563,6 +573,7 @@ static struct radeon_asic r600_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .set_power_state = &r600_set_power_state, }; static struct radeon_asic rs780_asic = { @@ -602,6 +613,7 @@ static struct radeon_asic rs780_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .set_power_state = &r600_set_power_state, }; static struct radeon_asic rv770_asic = { @@ -641,6 +653,7 @@ static struct radeon_asic rv770_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .set_power_state = &r600_set_power_state, }; static struct radeon_asic evergreen_asic = { @@ -678,6 +691,7 @@ static struct radeon_asic evergreen_asic = { .hpd_sense = &evergreen_hpd_sense, .hpd_set_polarity = &evergreen_hpd_set_polarity, .gui_idle = &r600_gui_idle, + .set_power_state = &r600_set_power_state, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index c74bf9bd26c..90d8e6dee52 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -127,6 +127,8 @@ void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); extern bool r100_gui_idle(struct radeon_device *rdev); +extern void r100_set_power_state(struct radeon_device *rdev); + /* * r200,rv250,rs300,rv280 */ @@ -271,6 +273,7 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); extern bool r600_gui_idle(struct radeon_device *rdev); +extern void r600_set_power_state(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index ff3abd8c896..129956d003a 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -29,7 +29,6 @@ #define RADEON_WAIT_VBLANK_TIMEOUT 200 #define RADEON_WAIT_IDLE_TIMEOUT 200 -static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); static void radeon_pm_set_clocks(struct radeon_device *rdev); static void radeon_pm_idle_work_handler(struct work_struct *work); @@ -181,7 +180,7 @@ static void radeon_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state->non_clock_info.pcie_lanes); } -static inline void radeon_sync_with_vblank(struct radeon_device *rdev) +void radeon_sync_with_vblank(struct radeon_device *rdev) { if (rdev->pm.active_crtcs) { rdev->pm.vblank_sync = false; @@ -191,43 +190,6 @@ static inline void radeon_sync_with_vblank(struct radeon_device *rdev) } } -static void radeon_set_power_state(struct radeon_device *rdev) -{ - /* if *_clock_mode are the same, *_power_state are as well */ - if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) - return; - - DRM_INFO("Setting: e: %d m: %d p: %d\n", - rdev->pm.requested_clock_mode->sclk, - rdev->pm.requested_clock_mode->mclk, - rdev->pm.requested_power_state->non_clock_info.pcie_lanes); - - /* set pcie lanes */ - /* TODO */ - - /* set voltage */ - /* TODO */ - - /* set engine clock */ - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - -#if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - } -#endif - - rdev->pm.current_power_state = rdev->pm.requested_power_state; - rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; -} - int radeon_pm_init(struct radeon_device *rdev) { rdev->pm.state = PM_STATE_DISABLED; @@ -330,26 +292,68 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_unlock(&rdev->pm.mutex); } -static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) { - u32 stat_crtc1 = 0, stat_crtc2 = 0; + u32 stat_crtc = 0; bool in_vbl = true; - if (ASIC_IS_AVIVO(rdev)) { + if (ASIC_IS_DCE4(rdev)) { + if (rdev->pm.active_crtcs & (1 << 0)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 1)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 2)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 3)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 4)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 5)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + } else if (ASIC_IS_AVIVO(rdev)) { + if (rdev->pm.active_crtcs & (1 << 0)) { + stat_crtc = RREG32(D1CRTC_STATUS); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 1)) { + stat_crtc = RREG32(D2CRTC_STATUS); + if (!(stat_crtc & 1)) + in_vbl = false; + } + } else { if (rdev->pm.active_crtcs & (1 << 0)) { - stat_crtc1 = RREG32(D1CRTC_STATUS); - if (!(stat_crtc1 & 1)) + stat_crtc = RREG32(RADEON_CRTC_STATUS); + if (!(stat_crtc & 1)) in_vbl = false; } if (rdev->pm.active_crtcs & (1 << 1)) { - stat_crtc2 = RREG32(D2CRTC_STATUS); - if (!(stat_crtc2 & 1)) + stat_crtc = RREG32(RADEON_CRTC2_STATUS); + if (!(stat_crtc & 1)) in_vbl = false; } } if (in_vbl == false) - DRM_INFO("not in vbl for pm change %08x %08x at %s\n", stat_crtc1, - stat_crtc2, finish ? "exit" : "entry"); + DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc, + finish ? "exit" : "entry"); return in_vbl; } static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 74d1cbfa23a..c332f46340d 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -553,7 +553,6 @@ # define RADEON_CRTC_CRNT_VLINE_MASK (0x7ff << 16) #define RADEON_CRTC2_CRNT_FRAME 0x0314 #define RADEON_CRTC2_GUI_TRIG_VLINE 0x0318 -#define RADEON_CRTC2_STATUS 0x03fc #define RADEON_CRTC2_VLINE_CRNT_VLINE 0x0310 #define RADEON_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */ #define RADEON_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */ -- cgit v1.2.3-70-g09d2 From a48b9b4edb8bb87deb13b9f088a595cf71457b69 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 14:03:55 -0400 Subject: drm/radeon/kms/pm: add asic specific callbacks for getting power state (v2) This also simplifies the code and enables reclocking with multiple heads active by tracking whether the power states are single or multi-head capable. Eventually, we will want to select a power state based on external factors (AC/DC state, user selection, etc.). (v2) Update for evergreen Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 2 + drivers/gpu/drm/radeon/r100.c | 140 +++++++++++++++--- drivers/gpu/drm/radeon/r600.c | 217 ++++++++++++++++++++++++---- drivers/gpu/drm/radeon/radeon.h | 25 +++- drivers/gpu/drm/radeon/radeon_asic.c | 14 ++ drivers/gpu/drm/radeon/radeon_asic.h | 4 + drivers/gpu/drm/radeon/radeon_atombios.c | 91 ++++++------ drivers/gpu/drm/radeon/radeon_combios.c | 11 +- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 2 + drivers/gpu/drm/radeon/radeon_pm.c | 153 +++----------------- 10 files changed, 413 insertions(+), 246 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 12fb12a2bba..b11aa37ed6d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -251,6 +251,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_blank_crtc(crtc, ATOM_DISABLE); drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); + radeon_crtc->enabled = true; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -260,6 +261,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); + radeon_crtc->enabled = false; break; } diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index b076b96f8b6..a6b2aca36b4 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -67,41 +67,133 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +void r100_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action) +{ + int i; + rdev->pm.can_upclock = true; + rdev->pm.can_downclock = true; + + switch (action) { + case PM_ACTION_MINIMUM: + rdev->pm.requested_power_state_index = 0; + rdev->pm.can_downclock = false; + break; + case PM_ACTION_DOWNCLOCK: + if (rdev->pm.current_power_state_index == 0) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + rdev->pm.can_downclock = false; + } else { + if (rdev->pm.active_crtc_count > 1) { + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if (i >= rdev->pm.current_power_state_index) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + break; + } else { + rdev->pm.requested_power_state_index = i; + break; + } + } + } else + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index - 1; + } + break; + case PM_ACTION_UPCLOCK: + if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + rdev->pm.can_upclock = false; + } else { + if (rdev->pm.active_crtc_count > 1) { + for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if (i <= rdev->pm.current_power_state_index) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + break; + } else { + rdev->pm.requested_power_state_index = i; + break; + } + } + } else + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index + 1; + } + break; + case PM_ACTION_NONE: + default: + DRM_ERROR("Requested mode for not defined action\n"); + return; + } + /* only one clock mode per power state */ + rdev->pm.requested_clock_mode_index = 0; + + DRM_INFO("Requested: e: %d m: %d p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes); +} + void r100_set_power_state(struct radeon_device *rdev) { - /* if *_clock_mode are the same, *_power_state are as well */ - if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) + u32 sclk, mclk; + + if (rdev->pm.current_power_state_index == rdev->pm.requested_power_state_index) return; - DRM_INFO("Setting: e: %d m: %d p: %d\n", - rdev->pm.requested_clock_mode->sclk, - rdev->pm.requested_clock_mode->mclk, - rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + if (radeon_gui_idle(rdev)) { - /* set pcie lanes */ - /* TODO */ + sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk; + if (sclk > rdev->clock.default_sclk) + sclk = rdev->clock.default_sclk; - /* set voltage */ - /* TODO */ + mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk; + if (mclk > rdev->clock.default_mclk) + mclk = rdev->clock.default_mclk; + /* don't change the mclk with multiple crtcs */ + if (rdev->pm.active_crtc_count > 1) + mclk = rdev->clock.default_mclk; - /* set engine clock */ - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); - radeon_pm_debug_check_in_vbl(rdev, true); + /* set pcie lanes */ + /* TODO */ + + /* set voltage */ + /* TODO */ + + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } #if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } #endif - rdev->pm.current_power_state = rdev->pm.requested_power_state; - rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; + rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; + rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; + } else + DRM_INFO("GUI not idle!!!\n"); } bool r100_gui_idle(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c2d1946535a..cc2797949ee 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,41 +92,206 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); -void r600_set_power_state(struct radeon_device *rdev) +void r600_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action) { - /* if *_clock_mode are the same, *_power_state are as well */ - if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) - return; + int i; + + rdev->pm.can_upclock = true; + rdev->pm.can_downclock = true; + + /* power state array is low to high, default is first */ + if ((rdev->flags & RADEON_IS_IGP) || (rdev->family == CHIP_R600)) { + int min_power_state_index = 0; + + if (rdev->pm.num_power_states > 2) + min_power_state_index = 1; + + switch (action) { + case PM_ACTION_MINIMUM: + rdev->pm.requested_power_state_index = min_power_state_index; + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_downclock = false; + break; + case PM_ACTION_DOWNCLOCK: + if (rdev->pm.current_power_state_index == min_power_state_index) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + rdev->pm.can_downclock = false; + } else { + if (rdev->pm.active_crtc_count > 1) { + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if (i >= rdev->pm.current_power_state_index) { + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index; + break; + } else { + rdev->pm.requested_power_state_index = i; + break; + } + } + } else + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index - 1; + } + rdev->pm.requested_clock_mode_index = 0; + break; + case PM_ACTION_UPCLOCK: + if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + rdev->pm.can_upclock = false; + } else { + if (rdev->pm.active_crtc_count > 1) { + for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if (i <= rdev->pm.current_power_state_index) { + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index; + break; + } else { + rdev->pm.requested_power_state_index = i; + break; + } + } + } else + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index + 1; + } + rdev->pm.requested_clock_mode_index = 0; + break; + case PM_ACTION_NONE: + default: + DRM_ERROR("Requested mode for not defined action\n"); + return; + } + } else { + /* XXX select a power state based on AC/DC, single/dualhead, etc. */ + /* for now just select the first power state and switch between clock modes */ + /* power state array is low to high, default is first (0) */ + if (rdev->pm.active_crtc_count > 1) { + rdev->pm.requested_power_state_index = -1; + /* start at 1 as we don't want the default mode */ + for (i = 1; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) || + (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) { + rdev->pm.requested_power_state_index = i; + break; + } + } + /* if nothing selected, grab the default state. */ + if (rdev->pm.requested_power_state_index == -1) + rdev->pm.requested_power_state_index = 0; + } else + rdev->pm.requested_power_state_index = 1; + + switch (action) { + case PM_ACTION_MINIMUM: + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_downclock = false; + break; + case PM_ACTION_DOWNCLOCK: + if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { + if (rdev->pm.current_clock_mode_index == 0) { + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_downclock = false; + } else + rdev->pm.requested_clock_mode_index = + rdev->pm.current_clock_mode_index - 1; + } else { + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_downclock = false; + } + break; + case PM_ACTION_UPCLOCK: + if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { + if (rdev->pm.current_clock_mode_index == + (rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1)) { + rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index; + rdev->pm.can_upclock = false; + } else + rdev->pm.requested_clock_mode_index = + rdev->pm.current_clock_mode_index + 1; + } else { + rdev->pm.requested_clock_mode_index = + rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1; + rdev->pm.can_upclock = false; + } + break; + case PM_ACTION_NONE: + default: + DRM_ERROR("Requested mode for not defined action\n"); + return; + } + } - DRM_INFO("Setting: e: %d m: %d p: %d\n", - rdev->pm.requested_clock_mode->sclk, - rdev->pm.requested_clock_mode->mclk, - rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + DRM_INFO("Requested: e: %d m: %d p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes); +} - /* set pcie lanes */ - /* TODO */ +void r600_set_power_state(struct radeon_device *rdev) +{ + u32 sclk, mclk; - /* set voltage */ - /* TODO */ + if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && + (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) + return; - /* set engine clock */ - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); - radeon_pm_debug_check_in_vbl(rdev, true); + if (radeon_gui_idle(rdev)) { + + sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk; + if (sclk > rdev->clock.default_sclk) + sclk = rdev->clock.default_sclk; + + mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk; + if (mclk > rdev->clock.default_mclk) + mclk = rdev->clock.default_mclk; + /* don't change the mclk with multiple crtcs */ + if (rdev->pm.active_crtc_count > 1) + mclk = rdev->clock.default_mclk; + + /* set pcie lanes */ + /* TODO */ + + /* set voltage */ + /* TODO */ + + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } #if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } #endif - rdev->pm.current_power_state = rdev->pm.requested_power_state; - rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; + rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; + rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; + } else + DRM_INFO("GUI not idle!!!\n"); } bool r600_gui_idle(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 11fe1d1444c..b5eccc4094e 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -672,6 +672,9 @@ struct radeon_pm_clock_info { u32 flags; }; +/* state flags */ +#define RADEON_PM_SINGLE_DISPLAY_ONLY (1 << 0) + struct radeon_power_state { enum radeon_pm_state_type type; /* XXX: use a define for num clock modes */ @@ -682,6 +685,8 @@ struct radeon_power_state { /* non clock info about this state */ struct radeon_pm_non_clock_info non_clock_info; bool voltage_drop_active; + /* standardized state flags */ + u32 flags; }; /* @@ -695,8 +700,10 @@ struct radeon_pm { enum radeon_pm_state state; enum radeon_pm_action planned_action; unsigned long action_timeout; - bool downclocked; - int active_crtcs; + bool can_upclock; + bool can_downclock; + u32 active_crtcs; + int active_crtc_count; int req_vblank; bool vblank_sync; bool gui_idle; @@ -716,11 +723,13 @@ struct radeon_pm { struct radeon_power_state power_state[8]; /* number of valid power states */ int num_power_states; - struct radeon_power_state *current_power_state; - struct radeon_pm_clock_info *current_clock_mode; - struct radeon_power_state *requested_power_state; - struct radeon_pm_clock_info *requested_clock_mode; - struct radeon_power_state *default_power_state; + int current_power_state_index; + int current_clock_mode_index; + int requested_power_state_index; + int requested_clock_mode_index; + int default_power_state_index; + u32 current_sclk; + u32 current_mclk; struct radeon_i2c_chan *i2c_bus; }; @@ -810,6 +819,7 @@ struct radeon_asic { */ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); bool (*gui_idle)(struct radeon_device *rdev); + void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); void (*set_power_state)(struct radeon_device *rdev); }; @@ -1218,6 +1228,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) +#define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a)) #define radeon_set_power_state(rdev) (rdev)->asic->set_power_state((rdev)) /* Common functions */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 48893fbb658..1053115ba65 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -166,6 +166,7 @@ static struct radeon_asic r100_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -206,6 +207,7 @@ static struct radeon_asic r200_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -247,6 +249,7 @@ static struct radeon_asic r300_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -287,6 +290,7 @@ static struct radeon_asic r300_asic_pcie = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -328,6 +332,7 @@ static struct radeon_asic r420_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -369,6 +374,7 @@ static struct radeon_asic rs400_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -410,6 +416,7 @@ static struct radeon_asic rs600_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -451,6 +458,7 @@ static struct radeon_asic rs690_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -492,6 +500,7 @@ static struct radeon_asic rv515_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -533,6 +542,7 @@ static struct radeon_asic r520_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -573,6 +583,7 @@ static struct radeon_asic r600_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, }; @@ -613,6 +624,7 @@ static struct radeon_asic rs780_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, }; @@ -653,6 +665,7 @@ static struct radeon_asic rv770_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, }; @@ -691,6 +704,7 @@ static struct radeon_asic evergreen_asic = { .hpd_sense = &evergreen_hpd_sense, .hpd_set_polarity = &evergreen_hpd_set_polarity, .gui_idle = &r600_gui_idle, + .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, }; diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 90d8e6dee52..71b21bb4e5f 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -128,6 +128,8 @@ void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); extern bool r100_gui_idle(struct radeon_device *rdev); extern void r100_set_power_state(struct radeon_device *rdev); +extern void r100_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action); /* * r200,rv250,rs300,rv280 @@ -274,6 +276,8 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); extern bool r600_gui_idle(struct radeon_device *rdev); extern void r600_set_power_state(struct radeon_device *rdev); +extern void r600_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action); /* * rv770,rv730,rv710,rv740 diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index aa0a973a8af..dbfb837d224 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1489,7 +1489,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) int state_index = 0, mode_index = 0; struct radeon_i2c_bus_rec i2c_bus; - rdev->pm.default_power_state = NULL; + rdev->pm.default_power_state_index = -1; if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { @@ -1520,12 +1520,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[0].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = power_info->info.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); @@ -1547,6 +1541,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; } + rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1560,15 +1555,20 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) + if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; + } if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; } state_index++; break; @@ -1582,12 +1582,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[0].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); @@ -1610,6 +1604,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; } + rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1623,18 +1618,26 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) + if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; + } if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; + if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT) + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; } state_index++; break; @@ -1648,12 +1651,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[0].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); @@ -1682,6 +1679,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; } } + rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1695,16 +1693,19 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) + if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; + } if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; } @@ -1713,12 +1714,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } /* last mode is usually default */ - if (!rdev->pm.default_power_state) { + if (rdev->pm.default_power_state_index == -1) { rdev->pm.power_state[state_index - 1].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index - 1]; + rdev->pm.default_power_state_index = state_index - 1; rdev->pm.power_state[state_index - 1].default_clock_mode = &rdev->pm.power_state[state_index - 1].clock_info[0]; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; } } else { /* add the i2c bus for thermal/fan chip */ @@ -1774,10 +1777,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) /* skip invalid modes */ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) continue; - /* skip overclock modes for now */ - if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN) - continue; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = @@ -1801,12 +1800,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = @@ -1831,12 +1824,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = @@ -1865,10 +1852,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) POWER_STATE_TYPE_PERFORMANCE; break; } + rdev->pm.power_state[state_index].flags = 0; + if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) + rdev->pm.power_state[state_index].flags |= + RADEON_PM_SINGLE_DISPLAY_ONLY; if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; } @@ -1876,10 +1867,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } /* first mode is usually default */ - if (!rdev->pm.default_power_state) { + if (rdev->pm.default_power_state_index == -1) { rdev->pm.power_state[0].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[0]; + rdev->pm.default_power_state_index = 0; rdev->pm.power_state[0].default_clock_mode = &rdev->pm.power_state[0].clock_info[0]; } @@ -1898,15 +1889,15 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); else rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; + rdev->pm.power_state[state_index].flags = 0; state_index++; } rdev->pm.num_power_states = state_index; - rdev->pm.current_power_state = rdev->pm.default_power_state; - rdev->pm.current_clock_mode = - rdev->pm.default_power_state->default_clock_mode; + rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.current_clock_mode_index = 0; } void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 44198581ba9..6a9ec851126 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2368,7 +2368,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) u8 rev, blocks, tmp; int state_index = 0; - rdev->pm.default_power_state = NULL; + rdev->pm.default_power_state_index = -1; if (rdev->flags & RADEON_IS_MOBILITY) { offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE); @@ -2441,6 +2441,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) if (rev > 6) rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = RBIOS8(offset + 0x5 + 0x10); + rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; state_index++; } else { /* XXX figure out some good default low power mode for mobility cards w/out power tables */ @@ -2462,12 +2463,12 @@ default_mode: rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); else rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.power_state[state_index].flags = 0; + rdev->pm.default_power_state_index = state_index; rdev->pm.num_power_states = state_index + 1; - rdev->pm.current_power_state = rdev->pm.default_power_state; - rdev->pm.current_clock_mode = - rdev->pm.default_power_state->default_clock_mode; + rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.current_clock_mode_index = 0; } void radeon_external_tmds_setup(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 60c0dcb8e11..f4f9cb297e3 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -323,6 +323,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); + radeon_crtc->enabled = true; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -335,6 +336,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) RADEON_CRTC_DISP_REQ_EN_B)); WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); } + radeon_crtc->enabled = false; break; } diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 129956d003a..10ef8924799 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -56,7 +56,7 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states); for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.default_power_state == &rdev->pm.power_state[i]) + if (rdev->pm.default_power_state_index == i) is_default = true; else is_default = false; @@ -65,6 +65,8 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) is_default ? "(default)" : ""); if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes); + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + DRM_INFO("\tSingle display only\n"); DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { if (rdev->flags & RADEON_IS_IGP) @@ -80,106 +82,6 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) } } -static struct radeon_power_state * radeon_pick_power_state(struct radeon_device *rdev, - enum radeon_pm_state_type type) -{ - int i, j; - enum radeon_pm_state_type wanted_types[2]; - int wanted_count; - - switch (type) { - case POWER_STATE_TYPE_DEFAULT: - default: - return rdev->pm.default_power_state; - case POWER_STATE_TYPE_POWERSAVE: - if (rdev->flags & RADEON_IS_MOBILITY) { - wanted_types[0] = POWER_STATE_TYPE_POWERSAVE; - wanted_types[1] = POWER_STATE_TYPE_BATTERY; - wanted_count = 2; - } else { - wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE; - wanted_count = 1; - } - break; - case POWER_STATE_TYPE_BATTERY: - if (rdev->flags & RADEON_IS_MOBILITY) { - wanted_types[0] = POWER_STATE_TYPE_BATTERY; - wanted_types[1] = POWER_STATE_TYPE_POWERSAVE; - wanted_count = 2; - } else { - wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE; - wanted_count = 1; - } - break; - case POWER_STATE_TYPE_BALANCED: - case POWER_STATE_TYPE_PERFORMANCE: - wanted_types[0] = type; - wanted_count = 1; - break; - } - - for (i = 0; i < wanted_count; i++) { - for (j = 0; j < rdev->pm.num_power_states; j++) { - if (rdev->pm.power_state[j].type == wanted_types[i]) - return &rdev->pm.power_state[j]; - } - } - - return rdev->pm.default_power_state; -} - -static struct radeon_pm_clock_info * radeon_pick_clock_mode(struct radeon_device *rdev, - struct radeon_power_state *power_state, - enum radeon_pm_clock_mode_type type) -{ - switch (type) { - case POWER_MODE_TYPE_DEFAULT: - default: - return power_state->default_clock_mode; - case POWER_MODE_TYPE_LOW: - return &power_state->clock_info[0]; - case POWER_MODE_TYPE_MID: - if (power_state->num_clock_modes > 2) - return &power_state->clock_info[1]; - else - return &power_state->clock_info[0]; - break; - case POWER_MODE_TYPE_HIGH: - return &power_state->clock_info[power_state->num_clock_modes - 1]; - } - -} - -static void radeon_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action) -{ - switch (action) { - case PM_ACTION_MINIMUM: - rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_BATTERY); - rdev->pm.requested_clock_mode = - radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_LOW); - break; - case PM_ACTION_DOWNCLOCK: - rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_POWERSAVE); - rdev->pm.requested_clock_mode = - radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_MID); - break; - case PM_ACTION_UPCLOCK: - rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_DEFAULT); - rdev->pm.requested_clock_mode = - radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH); - break; - case PM_ACTION_NONE: - default: - DRM_ERROR("Requested mode for not defined action\n"); - return; - } - DRM_INFO("Requested: e: %d m: %d p: %d\n", - rdev->pm.requested_clock_mode->sclk, - rdev->pm.requested_clock_mode->mclk, - rdev->pm.requested_power_state->non_clock_info.pcie_lanes); -} - void radeon_sync_with_vblank(struct radeon_device *rdev) { if (rdev->pm.active_crtcs) { @@ -194,7 +96,8 @@ int radeon_pm_init(struct radeon_device *rdev) { rdev->pm.state = PM_STATE_DISABLED; rdev->pm.planned_action = PM_ACTION_NONE; - rdev->pm.downclocked = false; + rdev->pm.can_upclock = true; + rdev->pm.can_downclock = true; if (rdev->bios) { if (rdev->is_atom_bios) @@ -229,9 +132,8 @@ void radeon_pm_fini(struct radeon_device *rdev) void radeon_pm_compute_clocks(struct radeon_device *rdev) { struct drm_device *ddev = rdev->ddev; - struct drm_connector *connector; + struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; - int count = 0; if (rdev->pm.state == PM_STATE_DISABLED) return; @@ -239,29 +141,27 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; - list_for_each_entry(connector, - &ddev->mode_config.connector_list, head) { - if (connector->encoder && - connector->encoder->crtc && - connector->dpms != DRM_MODE_DPMS_OFF) { - radeon_crtc = to_radeon_crtc(connector->encoder->crtc); + rdev->pm.active_crtc_count = 0; + list_for_each_entry(crtc, + &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); - ++count; + rdev->pm.active_crtc_count++; } } - if (count > 1) { + if (rdev->pm.active_crtc_count > 1) { if (rdev->pm.state == PM_STATE_ACTIVE) { cancel_delayed_work(&rdev->pm.idle_work); rdev->pm.state = PM_STATE_PAUSED; rdev->pm.planned_action = PM_ACTION_UPCLOCK; - if (rdev->pm.downclocked) - radeon_pm_set_clocks(rdev); + radeon_pm_set_clocks(rdev); DRM_DEBUG("radeon: dynamic power management deactivated\n"); } - } else if (count == 1) { + } else if (rdev->pm.active_crtc_count == 1) { /* TODO: Increase clocks if needed for current mode */ if (rdev->pm.state == PM_STATE_MINIMUM) { @@ -271,15 +171,13 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); - } - else if (rdev->pm.state == PM_STATE_PAUSED) { + } else if (rdev->pm.state == PM_STATE_PAUSED) { rdev->pm.state = PM_STATE_ACTIVE; queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); DRM_DEBUG("radeon: dynamic power management activated\n"); } - } - else { /* count == 0 */ + } else { /* count == 0 */ if (rdev->pm.state != PM_STATE_MINIMUM) { cancel_delayed_work(&rdev->pm.idle_work); @@ -359,19 +257,6 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) { /*radeon_fence_wait_last(rdev);*/ - switch (rdev->pm.planned_action) { - case PM_ACTION_UPCLOCK: - rdev->pm.downclocked = false; - break; - case PM_ACTION_DOWNCLOCK: - rdev->pm.downclocked = true; - break; - case PM_ACTION_MINIMUM: - break; - case PM_ACTION_NONE: - DRM_ERROR("%s: PM_ACTION_NONE\n", __func__); - break; - } radeon_set_power_state(rdev); rdev->pm.planned_action = PM_ACTION_NONE; @@ -437,7 +322,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) { rdev->pm.planned_action = PM_ACTION_NONE; } else if (rdev->pm.planned_action == PM_ACTION_NONE && - rdev->pm.downclocked) { + rdev->pm.can_upclock) { rdev->pm.planned_action = PM_ACTION_UPCLOCK; rdev->pm.action_timeout = jiffies + @@ -447,7 +332,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) { rdev->pm.planned_action = PM_ACTION_NONE; } else if (rdev->pm.planned_action == PM_ACTION_NONE && - !rdev->pm.downclocked) { + rdev->pm.can_downclock) { rdev->pm.planned_action = PM_ACTION_DOWNCLOCK; rdev->pm.action_timeout = jiffies + -- cgit v1.2.3-70-g09d2 From 79daedc942813c0417ff5e277da6f7f35705cde5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 14:25:19 -0400 Subject: drm/radeon/kms: minor pm cleanups - remove non_clock_info struct - track power state misc flags Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 13 +++---------- drivers/gpu/drm/radeon/radeon_atombios.c | 22 ++++++++++++++-------- drivers/gpu/drm/radeon/radeon_combios.c | 15 ++++----------- drivers/gpu/drm/radeon/radeon_pm.c | 2 +- 6 files changed, 24 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index a6b2aca36b4..f10b747024f 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -137,7 +137,7 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].mclk, rdev->pm.power_state[rdev->pm.requested_power_state_index]. - non_clock_info.pcie_lanes); + pcie_lanes); } void r100_set_power_state(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index cc2797949ee..35a5d4856f4 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -234,7 +234,7 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].mclk, rdev->pm.power_state[rdev->pm.requested_power_state_index]. - non_clock_info.pcie_lanes); + pcie_lanes); } void r600_set_power_state(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b5eccc4094e..b9ad976cfb9 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -654,13 +654,6 @@ struct radeon_voltage { u32 voltage; }; -struct radeon_pm_non_clock_info { - /* pcie lanes */ - int pcie_lanes; - /* standardized non-clock flags */ - u32 flags; -}; - struct radeon_pm_clock_info { /* memory clock */ u32 mclk; @@ -682,11 +675,11 @@ struct radeon_power_state { /* number of valid clock modes in this power state */ int num_clock_modes; struct radeon_pm_clock_info *default_clock_mode; - /* non clock info about this state */ - struct radeon_pm_non_clock_info non_clock_info; - bool voltage_drop_active; /* standardized state flags */ u32 flags; + u32 misc; /* vbios specific flags */ + u32 misc2; /* vbios specific flags */ + int pcie_lanes; /* pcie lanes */ }; /* diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index a0a99b66af8..c29ac74a1d2 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1528,7 +1528,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].pcie_lanes = power_info->info.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { @@ -1550,6 +1550,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; } rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = misc; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1590,7 +1591,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].pcie_lanes = power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); @@ -1613,6 +1614,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; } rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1659,7 +1662,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].pcie_lanes = power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); @@ -1688,6 +1691,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1730,6 +1735,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) &rdev->pm.power_state[state_index - 1].clock_info[0]; rdev->pm.power_state[state_index].flags &= ~RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = 0; + rdev->pm.power_state[state_index].misc2 = 0; } } else { /* add the i2c bus for thermal/fan chip */ @@ -1852,7 +1859,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (mode_index) { misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); misc2 = le16_to_cpu(non_clock_info->usClassification); - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; + rdev->pm.power_state[state_index].pcie_lanes = ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { @@ -1902,10 +1911,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - if (rdev->asic->get_pcie_lanes) - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); - else - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; + rdev->pm.power_state[state_index].pcie_lanes = 16; rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].flags = 0; state_index++; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 6a9ec851126..c22344b7fc5 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2382,17 +2382,13 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) goto default_mode; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[0].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - goto default_mode; rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BATTERY; misc = RBIOS16(offset + 0x5 + 0x0); if (rev > 4) misc2 = RBIOS16(offset + 0x5 + 0xe); + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; if (misc & 0x4) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; if (misc & 0x8) @@ -2439,7 +2435,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) } else rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; if (rev > 6) - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].pcie_lanes = RBIOS8(offset + 0x5 + 0x10); rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; state_index++; @@ -2459,10 +2455,7 @@ default_mode: rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - if (rdev->asic->get_pcie_lanes) - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); - else - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; + rdev->pm.power_state[state_index].pcie_lanes = 16; rdev->pm.power_state[state_index].flags = 0; rdev->pm.default_power_state_index = state_index; rdev->pm.num_power_states = state_index + 1; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 1febb62bdd9..87814eb8a1b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -64,7 +64,7 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) pm_state_types[rdev->pm.power_state[i].type], is_default ? "(default)" : ""); if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) - DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes); + DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes); if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) DRM_INFO("\tSingle display only\n"); DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); -- cgit v1.2.3-70-g09d2 From 58e21dff53b9063563e7bb5f5a795ab2d8f61dda Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Mar 2010 13:31:08 -0400 Subject: drm/radeon/kms/pm: restore default power state on exit Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 4 ++++ drivers/gpu/drm/radeon/r600.c | 10 ++++++++++ drivers/gpu/drm/radeon/radeon.h | 3 ++- drivers/gpu/drm/radeon/radeon_pm.c | 9 +++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index f10b747024f..6443d9ea6c1 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -123,6 +123,10 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.current_power_state_index + 1; } break; + case PM_ACTION_DEFAULT: + rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.can_upclock = false; + break; case PM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 35a5d4856f4..4f7f318b543 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -161,6 +161,11 @@ void r600_get_power_state(struct radeon_device *rdev, } rdev->pm.requested_clock_mode_index = 0; break; + case PM_ACTION_DEFAULT: + rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_upclock = false; + break; case PM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); @@ -221,6 +226,11 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.can_upclock = false; } break; + case PM_ACTION_DEFAULT: + rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_upclock = false; + break; case PM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b9ad976cfb9..5ffb29597af 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -615,7 +615,8 @@ enum radeon_pm_action { PM_ACTION_NONE, PM_ACTION_MINIMUM, PM_ACTION_DOWNCLOCK, - PM_ACTION_UPCLOCK + PM_ACTION_UPCLOCK, + PM_ACTION_DEFAULT }; enum radeon_voltage_type { diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 87814eb8a1b..23b79ebce6c 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -125,6 +125,15 @@ int radeon_pm_init(struct radeon_device *rdev) void radeon_pm_fini(struct radeon_device *rdev) { + if (rdev->pm.state != PM_STATE_DISABLED) { + /* cancel work */ + cancel_delayed_work_sync(&rdev->pm.idle_work); + /* reset default clocks */ + rdev->pm.state = PM_STATE_DISABLED; + rdev->pm.planned_action = PM_ACTION_DEFAULT; + radeon_pm_set_clocks(rdev); + } + if (rdev->pm.i2c_bus) radeon_i2c_destroy(rdev->pm.i2c_bus); } -- cgit v1.2.3-70-g09d2 From 49e02b7306cb7e01965fe5f41ba0f80085142f6e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 23 Apr 2010 17:57:27 -0400 Subject: drm/radeon/kms/pm: add additional asic callbacks - pm_misc() - handles voltage, pcie lanes, and other non clock related power mode settings. Currently disabled. Needs further debugging - pm_prepare() - disables crtc mem requests right now. All memory clients need to be disabled when changing memory clocks. This function can be expanded to include disabling fb access as well. - pm_finish() - enable active memory clients. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 41 ++++++++++ drivers/gpu/drm/radeon/evergreen_reg.h | 1 + drivers/gpu/drm/radeon/r100.c | 142 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r100d.h | 36 +++++++++ drivers/gpu/drm/radeon/r500_reg.h | 1 + drivers/gpu/drm/radeon/r600.c | 5 ++ drivers/gpu/drm/radeon/radeon.h | 3 + drivers/gpu/drm/radeon/radeon_asic.c | 42 ++++++++++ drivers/gpu/drm/radeon/radeon_asic.h | 11 +++ drivers/gpu/drm/radeon/rs600.c | 123 ++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/rs600d.h | 32 ++++++++ drivers/gpu/drm/radeon/rv770.c | 4 + 12 files changed, 441 insertions(+) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 0137a4cd90f..8d86d0568d9 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -39,6 +39,47 @@ static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); +void evergreen_pm_misc(struct radeon_device *rdev) +{ + +} + +void evergreen_pm_prepare(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* disable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset); + tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); + } + } +} + +void evergreen_pm_finish(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* enable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset); + tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); + } + } +} + bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { bool connected = false; diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 9dba6d97d9b..93aab2ebd9d 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -166,6 +166,7 @@ /* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */ #define EVERGREEN_CRTC_CONTROL 0x6e70 # define EVERGREEN_CRTC_MASTER_EN (1 << 0) +# define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) #define EVERGREEN_CRTC_STATUS 0x6e8c #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 6443d9ea6c1..2106ac66eb3 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -37,6 +37,7 @@ #include "rs100d.h" #include "rv200d.h" #include "rv250d.h" +#include "atom.h" #include #include @@ -200,6 +201,147 @@ void r100_set_power_state(struct radeon_device *rdev) DRM_INFO("GUI not idle!!!\n"); } +void r100_pm_misc(struct radeon_device *rdev) +{ +#if 0 + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + u32 tmp, sclk_cntl, sclk_cntl2, sclk_more_cntl; + + if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { + if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + tmp = RREG32(voltage->gpio.reg); + if (voltage->active_high) + tmp |= voltage->gpio.mask; + else + tmp &= ~(voltage->gpio.mask); + WREG32(voltage->gpio.reg, tmp); + if (voltage->delay) + udelay(voltage->delay); + } else { + tmp = RREG32(voltage->gpio.reg); + if (voltage->active_high) + tmp &= ~voltage->gpio.mask; + else + tmp |= voltage->gpio.mask; + WREG32(voltage->gpio.reg, tmp); + if (voltage->delay) + udelay(voltage->delay); + } + } + + sclk_cntl = RREG32_PLL(SCLK_CNTL); + sclk_cntl2 = RREG32_PLL(SCLK_CNTL2); + sclk_cntl2 &= ~REDUCED_SPEED_SCLK_SEL(3); + sclk_more_cntl = RREG32_PLL(SCLK_MORE_CNTL); + sclk_more_cntl &= ~VOLTAGE_DELAY_SEL(3); + if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) { + sclk_more_cntl |= REDUCED_SPEED_SCLK_EN; + if (ps->misc & ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE) + sclk_cntl2 |= REDUCED_SPEED_SCLK_MODE; + else + sclk_cntl2 &= ~REDUCED_SPEED_SCLK_MODE; + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) + sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(0); + else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) + sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(2); + } else + sclk_more_cntl &= ~REDUCED_SPEED_SCLK_EN; + + if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) { + sclk_more_cntl |= IO_CG_VOLTAGE_DROP; + if (voltage->delay) { + sclk_more_cntl |= VOLTAGE_DROP_SYNC; + switch (voltage->delay) { + case 33: + sclk_more_cntl |= VOLTAGE_DELAY_SEL(0); + break; + case 66: + sclk_more_cntl |= VOLTAGE_DELAY_SEL(1); + break; + case 99: + sclk_more_cntl |= VOLTAGE_DELAY_SEL(2); + break; + case 132: + sclk_more_cntl |= VOLTAGE_DELAY_SEL(3); + break; + } + } else + sclk_more_cntl &= ~VOLTAGE_DROP_SYNC; + } else + sclk_more_cntl &= ~IO_CG_VOLTAGE_DROP; + + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN) + sclk_cntl &= ~FORCE_HDP; + else + sclk_cntl |= FORCE_HDP; + + WREG32_PLL(SCLK_CNTL, sclk_cntl); + WREG32_PLL(SCLK_CNTL2, sclk_cntl2); + WREG32_PLL(SCLK_MORE_CNTL, sclk_more_cntl); + + /* set pcie lanes */ + if ((rdev->flags & RADEON_IS_PCIE) && + !(rdev->flags & RADEON_IS_IGP) && + rdev->asic->set_pcie_lanes && + (ps->pcie_lanes != + rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { + radeon_set_pcie_lanes(rdev, + ps->pcie_lanes); + DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); + } +#endif +} + +void r100_pm_prepare(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* disable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + if (radeon_crtc->crtc_id) { + tmp = RREG32(RADEON_CRTC2_GEN_CNTL); + tmp |= RADEON_CRTC2_DISP_REQ_EN_B; + WREG32(RADEON_CRTC2_GEN_CNTL, tmp); + } else { + tmp = RREG32(RADEON_CRTC_GEN_CNTL); + tmp |= RADEON_CRTC_DISP_REQ_EN_B; + WREG32(RADEON_CRTC_GEN_CNTL, tmp); + } + } + } +} + +void r100_pm_finish(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* enable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + if (radeon_crtc->crtc_id) { + tmp = RREG32(RADEON_CRTC2_GEN_CNTL); + tmp &= ~RADEON_CRTC2_DISP_REQ_EN_B; + WREG32(RADEON_CRTC2_GEN_CNTL, tmp); + } else { + tmp = RREG32(RADEON_CRTC_GEN_CNTL); + tmp &= ~RADEON_CRTC_DISP_REQ_EN_B; + WREG32(RADEON_CRTC_GEN_CNTL, tmp); + } + } + } +} + bool r100_gui_idle(struct radeon_device *rdev) { if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h index de8abd104ab..d016b16fa11 100644 --- a/drivers/gpu/drm/radeon/r100d.h +++ b/drivers/gpu/drm/radeon/r100d.h @@ -838,5 +838,41 @@ #define G_00000D_FORCE_RB(x) (((x) >> 28) & 0x1) #define C_00000D_FORCE_RB 0xEFFFFFFF +/* PLL regs */ +#define SCLK_CNTL 0xd +#define FORCE_HDP (1 << 17) +#define CLK_PWRMGT_CNTL 0x14 +#define GLOBAL_PMAN_EN (1 << 10) +#define DISP_PM (1 << 20) +#define PLL_PWRMGT_CNTL 0x15 +#define MPLL_TURNOFF (1 << 0) +#define SPLL_TURNOFF (1 << 1) +#define PPLL_TURNOFF (1 << 2) +#define P2PLL_TURNOFF (1 << 3) +#define TVPLL_TURNOFF (1 << 4) +#define MOBILE_SU (1 << 16) +#define SU_SCLK_USE_BCLK (1 << 17) +#define SCLK_CNTL2 0x1e +#define REDUCED_SPEED_SCLK_MODE (1 << 16) +#define REDUCED_SPEED_SCLK_SEL(x) ((x) << 17) +#define MCLK_MISC 0x1f +#define EN_MCLK_TRISTATE_IN_SUSPEND (1 << 18) +#define SCLK_MORE_CNTL 0x35 +#define REDUCED_SPEED_SCLK_EN (1 << 16) +#define IO_CG_VOLTAGE_DROP (1 << 17) +#define VOLTAGE_DELAY_SEL(x) ((x) << 20) +#define VOLTAGE_DROP_SYNC (1 << 19) + +/* mmreg */ +#define DISP_PWR_MAN 0xd08 +#define DISP_D3_GRPH_RST (1 << 18) +#define DISP_D3_SUBPIC_RST (1 << 19) +#define DISP_D3_OV0_RST (1 << 20) +#define DISP_D1D2_GRPH_RST (1 << 21) +#define DISP_D1D2_SUBPIC_RST (1 << 22) +#define DISP_D1D2_OV0_RST (1 << 23) +#define DISP_DVO_ENABLE_RST (1 << 24) +#define TV_ENABLE_RST (1 << 25) +#define AUTO_PWRUP_EN (1 << 26) #endif diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 0cf2ad2a558..f5adf42a9d1 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -347,6 +347,7 @@ #define AVIVO_D1CRTC_CONTROL 0x6080 # define AVIVO_CRTC_EN (1 << 0) +# define AVIVO_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) #define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 #define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 #define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4f7f318b543..38f75f54019 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -304,6 +304,11 @@ void r600_set_power_state(struct radeon_device *rdev) DRM_INFO("GUI not idle!!!\n"); } +void r600_pm_misc(struct radeon_device *rdev) +{ + +} + bool r600_gui_idle(struct radeon_device *rdev) { if (RREG32(GRBM_STATUS) & GUI_ACTIVE) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5ffb29597af..16f0ea78ea9 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -815,6 +815,9 @@ struct radeon_asic { bool (*gui_idle)(struct radeon_device *rdev); void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); void (*set_power_state)(struct radeon_device *rdev); + void (*pm_misc)(struct radeon_device *rdev); + void (*pm_prepare)(struct radeon_device *rdev); + void (*pm_finish)(struct radeon_device *rdev); }; /* diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 1053115ba65..1e6f17bf54f 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -168,6 +168,9 @@ static struct radeon_asic r100_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic r200_asic = { @@ -209,6 +212,9 @@ static struct radeon_asic r200_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic r300_asic = { @@ -251,6 +257,9 @@ static struct radeon_asic r300_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic r300_asic_pcie = { @@ -292,6 +301,9 @@ static struct radeon_asic r300_asic_pcie = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic r420_asic = { @@ -334,6 +346,9 @@ static struct radeon_asic r420_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic rs400_asic = { @@ -376,6 +391,9 @@ static struct radeon_asic rs400_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic rs600_asic = { @@ -418,6 +436,9 @@ static struct radeon_asic rs600_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &rs600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic rs690_asic = { @@ -460,6 +481,9 @@ static struct radeon_asic rs690_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &rs600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic rv515_asic = { @@ -502,6 +526,9 @@ static struct radeon_asic rv515_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &rs600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic r520_asic = { @@ -544,6 +571,9 @@ static struct radeon_asic r520_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &rs600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic r600_asic = { @@ -585,6 +615,9 @@ static struct radeon_asic r600_asic = { .gui_idle = &r600_gui_idle, .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, + .pm_misc = &r600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic rs780_asic = { @@ -626,6 +659,9 @@ static struct radeon_asic rs780_asic = { .gui_idle = &r600_gui_idle, .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, + .pm_misc = &r600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic rv770_asic = { @@ -667,6 +703,9 @@ static struct radeon_asic rv770_asic = { .gui_idle = &r600_gui_idle, .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, + .pm_misc = &rv770_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic evergreen_asic = { @@ -706,6 +745,9 @@ static struct radeon_asic evergreen_asic = { .gui_idle = &r600_gui_idle, .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, + .pm_misc = &evergreen_pm_misc, + .pm_prepare = &evergreen_pm_prepare, + .pm_finish = &evergreen_pm_finish, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 71b21bb4e5f..378db67ba2d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -130,6 +130,9 @@ extern bool r100_gui_idle(struct radeon_device *rdev); extern void r100_set_power_state(struct radeon_device *rdev); extern void r100_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action); +extern void r100_pm_misc(struct radeon_device *rdev); +extern void r100_pm_prepare(struct radeon_device *rdev); +extern void r100_pm_finish(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 @@ -201,6 +204,9 @@ void rs600_hpd_fini(struct radeon_device *rdev); bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void rs600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); +extern void rs600_pm_misc(struct radeon_device *rdev); +extern void rs600_pm_prepare(struct radeon_device *rdev); +extern void rs600_pm_finish(struct radeon_device *rdev); /* * rs690,rs740 @@ -278,6 +284,7 @@ extern bool r600_gui_idle(struct radeon_device *rdev); extern void r600_set_power_state(struct radeon_device *rdev); extern void r600_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action); +extern void r600_pm_misc(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 @@ -286,6 +293,7 @@ int rv770_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); int rv770_suspend(struct radeon_device *rdev); int rv770_resume(struct radeon_device *rdev); +extern void rv770_pm_misc(struct radeon_device *rdev); /* * evergreen @@ -306,5 +314,8 @@ void evergreen_hpd_set_polarity(struct radeon_device *rdev, u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc); int evergreen_irq_set(struct radeon_device *rdev); int evergreen_irq_process(struct radeon_device *rdev); +extern void evergreen_pm_misc(struct radeon_device *rdev); +extern void evergreen_pm_prepare(struct radeon_device *rdev); +extern void evergreen_pm_finish(struct radeon_device *rdev); #endif diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index b312b72d76c..c3890b76a1c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -46,6 +46,129 @@ void rs600_gpu_init(struct radeon_device *rdev); int rs600_mc_wait_for_idle(struct radeon_device *rdev); +void rs600_pm_misc(struct radeon_device *rdev) +{ +#if 0 + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + u32 tmp, dyn_pwrmgt_sclk_length, dyn_sclk_vol_cntl; + u32 hdp_dyn_cntl, mc_host_dyn_cntl; + + if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { + if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + tmp = RREG32(voltage->gpio.reg); + if (voltage->active_high) + tmp |= voltage->gpio.mask; + else + tmp &= ~(voltage->gpio.mask); + WREG32(voltage->gpio.reg, tmp); + if (voltage->delay) + udelay(voltage->delay); + } else { + tmp = RREG32(voltage->gpio.reg); + if (voltage->active_high) + tmp &= ~voltage->gpio.mask; + else + tmp |= voltage->gpio.mask; + WREG32(voltage->gpio.reg, tmp); + if (voltage->delay) + udelay(voltage->delay); + } + } + + dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH); + dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf); + dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_LOLEN(0xf); + if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) { + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) { + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(2); + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(2); + } else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) { + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(4); + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(4); + } + } else { + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(1); + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(1); + } + WREG32_PLL(DYN_PWRMGT_SCLK_LENGTH, dyn_pwrmgt_sclk_length); + + dyn_sclk_vol_cntl = RREG32_PLL(DYN_SCLK_VOL_CNTL); + if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) { + dyn_sclk_vol_cntl |= IO_CG_VOLTAGE_DROP; + if (voltage->delay) { + dyn_sclk_vol_cntl |= VOLTAGE_DROP_SYNC; + dyn_sclk_vol_cntl |= VOLTAGE_DELAY_SEL(voltage->delay); + } else + dyn_sclk_vol_cntl &= ~VOLTAGE_DROP_SYNC; + } else + dyn_sclk_vol_cntl &= ~IO_CG_VOLTAGE_DROP; + WREG32_PLL(DYN_SCLK_VOL_CNTL, dyn_sclk_vol_cntl); + + hdp_dyn_cntl = RREG32_PLL(HDP_DYN_CNTL); + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN) + hdp_dyn_cntl &= ~HDP_FORCEON; + else + hdp_dyn_cntl |= HDP_FORCEON; + WREG32_PLL(HDP_DYN_CNTL, hdp_dyn_cntl); + + mc_host_dyn_cntl = RREG32_PLL(MC_HOST_DYN_CNTL); + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN) + mc_host_dyn_cntl &= ~MC_HOST_FORCEON; + else + mc_host_dyn_cntl |= MC_HOST_FORCEON; + WREG32_PLL(MC_HOST_DYN_CNTL, mc_host_dyn_cntl); + + /* set pcie lanes */ + if ((rdev->flags & RADEON_IS_PCIE) && + !(rdev->flags & RADEON_IS_IGP) && + rdev->asic->set_pcie_lanes && + (ps->pcie_lanes != + rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { + radeon_set_pcie_lanes(rdev, + ps->pcie_lanes); + DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); + } +#endif +} + +void rs600_pm_prepare(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* disable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + tmp = RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset); + tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); + } + } +} + +void rs600_pm_finish(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* enable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + tmp = RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset); + tmp &= ~AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); + } + } +} + /* hpd for digital panel detect/disconnect */ bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h index 08c4bebd301..8f624342927 100644 --- a/drivers/gpu/drm/radeon/rs600d.h +++ b/drivers/gpu/drm/radeon/rs600d.h @@ -634,4 +634,36 @@ #define G_006D4C_D2MODE_PRIORITY_B_FORCE_MASK(x) (((x) >> 24) & 0x1) #define C_006D4C_D2MODE_PRIORITY_B_FORCE_MASK 0xFEFFFFFF +/* PLL regs */ +#define GENERAL_PWRMGT 0x8 +#define GLOBAL_PWRMGT_EN (1 << 0) +#define MOBILE_SU (1 << 2) +#define DYN_PWRMGT_SCLK_LENGTH 0xc +#define NORMAL_POWER_SCLK_HILEN(x) ((x) << 0) +#define NORMAL_POWER_SCLK_LOLEN(x) ((x) << 4) +#define REDUCED_POWER_SCLK_HILEN(x) ((x) << 8) +#define REDUCED_POWER_SCLK_LOLEN(x) ((x) << 12) +#define POWER_D1_SCLK_HILEN(x) ((x) << 16) +#define POWER_D1_SCLK_LOLEN(x) ((x) << 20) +#define STATIC_SCREEN_HILEN(x) ((x) << 24) +#define STATIC_SCREEN_LOLEN(x) ((x) << 28) +#define DYN_SCLK_VOL_CNTL 0xe +#define IO_CG_VOLTAGE_DROP (1 << 0) +#define VOLTAGE_DROP_SYNC (1 << 2) +#define VOLTAGE_DELAY_SEL(x) ((x) << 3) +#define HDP_DYN_CNTL 0x10 +#define HDP_FORCEON (1 << 0) +#define MC_HOST_DYN_CNTL 0x1e +#define MC_HOST_FORCEON (1 << 0) + +/* mmreg */ +#define DOUT_POWER_MANAGEMENT_CNTL 0x7ee0 +#define PWRDN_WAIT_BUSY_OFF (1 << 0) +#define PWRDN_WAIT_PWRSEQ_OFF (1 << 4) +#define PWRDN_WAIT_PPLL_OFF (1 << 8) +#define PWRUP_WAIT_PPLL_ON (1 << 12) +#define PWRUP_WAIT_MEM_INIT_DONE (1 << 16) +#define PM_ASSERT_RESET (1 << 20) +#define PM_PWRDN_PPLL (1 << 24) + #endif diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index a74683e1861..7c55182a9dd 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -42,6 +42,10 @@ static void rv770_gpu_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); +void rv770_pm_misc(struct radeon_device *rdev) +{ + +} /* * GART -- cgit v1.2.3-70-g09d2 From a424816fb37f894a37585cf86dfdd6b8b1dc681f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 24 Apr 2010 14:50:23 -0400 Subject: drm/radeon/kms/pm: rework power management Add two new sysfs attributes: - dynpm - power_state Echoing 0/1 to dynpm disables/enables dynamic power management. The driver scales the sclk dynamically based on the number of queued fences. dynpm only scales sclk dynamically in single head mode. Echoing x.y to power_state selects a static power state (x) and clock mode (y). This allows you to statically select a power state and clock mode. Selecting a static clock mode will disable dynpm. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 66 +++++++++++------ drivers/gpu/drm/radeon/r600.c | 69 ++++++++++------- drivers/gpu/drm/radeon/radeon.h | 7 +- drivers/gpu/drm/radeon/radeon_asic.h | 4 +- drivers/gpu/drm/radeon/radeon_pm.c | 139 ++++++++++++++++++++++++++++++++++- 5 files changed, 229 insertions(+), 56 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 2106ac66eb3..7675827c3a8 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -145,7 +145,7 @@ void r100_get_power_state(struct radeon_device *rdev, pcie_lanes); } -void r100_set_power_state(struct radeon_device *rdev) +void r100_set_power_state(struct radeon_device *rdev, bool static_switch) { u32 sclk, mclk; @@ -167,33 +167,51 @@ void r100_set_power_state(struct radeon_device *rdev) if (rdev->pm.active_crtc_count > 1) mclk = rdev->clock.default_mclk; - /* set pcie lanes */ - /* TODO */ + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); - /* set voltage */ - /* TODO */ - - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } + if (static_switch) { + radeon_pm_prepare(rdev); + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_set_engine_clock(rdev, sclk); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } +#if 0 + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_set_memory_clock(rdev, mclk); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } +#endif + radeon_pm_finish(rdev); + } else { + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } #if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_pm_prepare(rdev); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_finish(rdev); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } #endif + } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 38f75f54019..46913099406 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -247,7 +247,7 @@ void r600_get_power_state(struct radeon_device *rdev, pcie_lanes); } -void r600_set_power_state(struct radeon_device *rdev) +void r600_set_power_state(struct radeon_device *rdev, bool static_switch) { u32 sclk, mclk; @@ -266,37 +266,52 @@ void r600_set_power_state(struct radeon_device *rdev) clock_info[rdev->pm.requested_clock_mode_index].mclk; if (mclk > rdev->clock.default_mclk) mclk = rdev->clock.default_mclk; - /* don't change the mclk with multiple crtcs */ - if (rdev->pm.active_crtc_count > 1) - mclk = rdev->clock.default_mclk; - - /* set pcie lanes */ - /* TODO */ - /* set voltage */ - /* TODO */ + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } + if (static_switch) { + radeon_pm_prepare(rdev); + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_set_engine_clock(rdev, sclk); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } +#if 0 + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_set_memory_clock(rdev, mclk); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } +#endif + radeon_pm_finish(rdev); + } else { + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } #if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_pm_prepare(rdev); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_finish(rdev); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } #endif + } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 16f0ea78ea9..cdcf5eaf671 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -814,7 +814,7 @@ struct radeon_asic { void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); bool (*gui_idle)(struct radeon_device *rdev); void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); - void (*set_power_state)(struct radeon_device *rdev); + void (*set_power_state)(struct radeon_device *rdev, bool static_switch); void (*pm_misc)(struct radeon_device *rdev); void (*pm_prepare)(struct radeon_device *rdev); void (*pm_finish)(struct radeon_device *rdev); @@ -1226,7 +1226,10 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) #define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a)) -#define radeon_set_power_state(rdev) (rdev)->asic->set_power_state((rdev)) +#define radeon_set_power_state(rdev, s) (rdev)->asic->set_power_state((rdev), (s)) +#define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev)) +#define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev)) +#define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 378db67ba2d..8a127862999 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -127,7 +127,7 @@ void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); extern bool r100_gui_idle(struct radeon_device *rdev); -extern void r100_set_power_state(struct radeon_device *rdev); +extern void r100_set_power_state(struct radeon_device *rdev, bool static_switch); extern void r100_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action); extern void r100_pm_misc(struct radeon_device *rdev); @@ -281,7 +281,7 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); extern bool r600_gui_idle(struct radeon_device *rdev); -extern void r600_set_power_state(struct radeon_device *rdev); +extern void r600_set_power_state(struct radeon_device *rdev, bool static_switch); extern void r600_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action); extern void r600_pm_misc(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 23b79ebce6c..c703ae326bc 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -34,6 +34,128 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev); static void radeon_pm_idle_work_handler(struct work_struct *work); static int radeon_debugfs_pm_init(struct radeon_device *rdev); +static void radeon_pm_set_power_mode_static_locked(struct radeon_device *rdev) +{ + mutex_lock(&rdev->cp.mutex); + + /* wait for GPU idle */ + rdev->pm.gui_idle = false; + rdev->irq.gui_idle = true; + radeon_irq_set(rdev); + wait_event_interruptible_timeout( + rdev->irq.idle_queue, rdev->pm.gui_idle, + msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); + rdev->irq.gui_idle = false; + radeon_irq_set(rdev); + + radeon_set_power_state(rdev, true); + + /* update display watermarks based on new power state */ + radeon_update_bandwidth_info(rdev); + if (rdev->pm.active_crtc_count) + radeon_bandwidth_update(rdev); + + mutex_unlock(&rdev->cp.mutex); +} + +static ssize_t radeon_get_power_state_static(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + + return snprintf(buf, PAGE_SIZE, "%d.%d\n", rdev->pm.current_power_state_index, + rdev->pm.current_clock_mode_index); +} + +static ssize_t radeon_set_power_state_static(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + int ps, cm; + + if (sscanf(buf, "%u.%u", &ps, &cm) != 2) { + DRM_ERROR("Invalid power state!\n"); + return count; + } + + mutex_lock(&rdev->pm.mutex); + if ((ps >= 0) && (ps < rdev->pm.num_power_states) && + (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { + if ((rdev->pm.active_crtc_count > 1) && + (rdev->pm.power_state[ps].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)) { + DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm); + } else { + /* disable dynpm */ + rdev->pm.state = PM_STATE_DISABLED; + rdev->pm.planned_action = PM_ACTION_NONE; + rdev->pm.requested_power_state_index = ps; + rdev->pm.requested_clock_mode_index = cm; + radeon_pm_set_power_mode_static_locked(rdev); + } + } else + DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm); + mutex_unlock(&rdev->pm.mutex); + + return count; +} + +static ssize_t radeon_get_dynpm(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + + return snprintf(buf, PAGE_SIZE, "%s\n", + (rdev->pm.state == PM_STATE_DISABLED) ? "disabled" : "enabled"); +} + +static ssize_t radeon_set_dynpm(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + int tmp = simple_strtoul(buf, NULL, 10); + + if (tmp == 0) { + /* update power mode info */ + radeon_pm_compute_clocks(rdev); + /* disable dynpm */ + mutex_lock(&rdev->pm.mutex); + rdev->pm.state = PM_STATE_DISABLED; + rdev->pm.planned_action = PM_ACTION_NONE; + mutex_unlock(&rdev->pm.mutex); + DRM_INFO("radeon: dynamic power management disabled\n"); + } else if (tmp == 1) { + if (rdev->pm.num_power_states > 1) { + /* enable dynpm */ + mutex_lock(&rdev->pm.mutex); + rdev->pm.state = PM_STATE_PAUSED; + rdev->pm.planned_action = PM_ACTION_DEFAULT; + radeon_get_power_state(rdev, rdev->pm.planned_action); + mutex_unlock(&rdev->pm.mutex); + /* update power mode info */ + radeon_pm_compute_clocks(rdev); + DRM_INFO("radeon: dynamic power management enabled\n"); + } else + DRM_ERROR("dynpm not valid on this system\n"); + } else + DRM_ERROR("Invalid setting: %d\n", tmp); + + return count; +} + +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, radeon_get_power_state_static, radeon_set_power_state_static); +static DEVICE_ATTR(dynpm, S_IRUGO | S_IWUSR, radeon_get_dynpm, radeon_set_dynpm); + + static const char *pm_state_names[4] = { "PM_STATE_DISABLED", "PM_STATE_MINIMUM", @@ -111,6 +233,10 @@ int radeon_pm_init(struct radeon_device *rdev) DRM_ERROR("Failed to register debugfs file for PM!\n"); } + /* where's the best place to put this? */ + device_create_file(rdev->dev, &dev_attr_power_state); + device_create_file(rdev->dev, &dev_attr_dynpm); + INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) { @@ -132,8 +258,19 @@ void radeon_pm_fini(struct radeon_device *rdev) rdev->pm.state = PM_STATE_DISABLED; rdev->pm.planned_action = PM_ACTION_DEFAULT; radeon_pm_set_clocks(rdev); + } else if ((rdev->pm.current_power_state_index != + rdev->pm.default_power_state_index) || + (rdev->pm.current_clock_mode_index != 0)) { + rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.requested_clock_mode_index = 0; + mutex_lock(&rdev->pm.mutex); + radeon_pm_set_power_mode_static_locked(rdev); + mutex_unlock(&rdev->pm.mutex); } + device_remove_file(rdev->dev, &dev_attr_power_state); + device_remove_file(rdev->dev, &dev_attr_dynpm); + if (rdev->pm.i2c_bus) radeon_i2c_destroy(rdev->pm.i2c_bus); } @@ -267,7 +404,7 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) { /*radeon_fence_wait_last(rdev);*/ - radeon_set_power_state(rdev); + radeon_set_power_state(rdev, false); rdev->pm.planned_action = PM_ACTION_NONE; } -- cgit v1.2.3-70-g09d2 From 956ac86d9277b7142f0ad3f24f7fbd4beed0777d Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 26 Apr 2010 17:01:16 -0400 Subject: radeon: Enable memory reclockong on r600 With luck, dynamic memory reclocking on r600 should be stable with the previous patches. Enable it. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 46913099406..1696cc277d8 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -271,26 +271,27 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) radeon_pm_misc(rdev); if (static_switch) { - radeon_pm_prepare(rdev); + /* set engine clock */ if (sclk != rdev->pm.current_sclk) { radeon_set_engine_clock(rdev, sclk); rdev->pm.current_sclk = sclk; DRM_INFO("Setting: e: %d\n", sclk); } -#if 0 + /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); + radeon_pm_finish(rdev); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } -#endif - radeon_pm_finish(rdev); + } else { - /* set engine clock */ + radeon_sync_with_vblank(rdev); + if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, sclk); radeon_pm_debug_check_in_vbl(rdev, true); @@ -298,10 +299,8 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) DRM_INFO("Setting: e: %d\n", sclk); } -#if 0 /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); radeon_pm_debug_check_in_vbl(rdev, false); radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); @@ -310,7 +309,6 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } -#endif } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; -- cgit v1.2.3-70-g09d2 From f81f202402640c27b38e1452dcb4d3e447043f48 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 28 Apr 2010 12:13:06 -0400 Subject: radeon: Try harder to ensure we reclock in vblank The vblank interrupt on r600 doesn't seem to be especially reliable, so perform some sanity checks before the actual reclock. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r500_reg.h | 2 ++ drivers/gpu/drm/radeon/r600.c | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 11 ++++++++++- 4 files changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index f5adf42a9d1..93c9a2bbccf 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -351,6 +351,7 @@ #define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 #define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 #define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c +#define AVIVO_D1CRTC_STATUS_POSITION 0x60a0 #define AVIVO_D1CRTC_FRAME_COUNT 0x60a4 #define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 @@ -489,6 +490,7 @@ #define AVIVO_D2CRTC_BLANK_CONTROL 0x6884 #define AVIVO_D2CRTC_INTERLACE_CONTROL 0x6888 #define AVIVO_D2CRTC_INTERLACE_STATUS 0x688c +#define AVIVO_D2CRTC_STATUS_POSITION 0x68a0 #define AVIVO_D2CRTC_FRAME_COUNT 0x68a4 #define AVIVO_D2CRTC_STEREO_CONTROL 0x68c4 diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1696cc277d8..d3a79e0a912 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -289,8 +289,34 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) } } else { + u32 position; + u32 vbl; + radeon_sync_with_vblank(rdev); + if (!radeon_pm_in_vbl(rdev)) + return; + + if (rdev->pm.active_crtcs & (1 << 0)) { + vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); + position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); + position &= 0xfff; + vbl &= 0xfff; + + if (position < vbl && position > 1) + return; + } + + if (rdev->pm.active_crtcs & (1 << 1)) { + vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); + position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); + position &= 0xfff; + vbl &= 0xfff; + + if (position < vbl && position > 1) + return; + } + if (sclk != rdev->pm.current_sclk) { radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, sclk); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bed84b316bb..93ac88eb6b3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -175,6 +175,7 @@ void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); +bool radeon_pm_in_vbl(struct radeon_device *rdev); bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); void radeon_sync_with_vblank(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 134b19537d1..88163e043fc 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -387,7 +387,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_unlock(&rdev->pm.mutex); } -bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +bool radeon_pm_in_vbl(struct radeon_device *rdev) { u32 stat_crtc = 0; bool in_vbl = true; @@ -446,6 +446,15 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) in_vbl = false; } } + + return in_vbl; +} + +bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +{ + u32 stat_crtc = 0; + bool in_vbl = radeon_pm_in_vbl(rdev); + if (in_vbl == false) DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc, finish ? "exit" : "entry"); -- cgit v1.2.3-70-g09d2 From 539d24181753e40174746d576d415bfb56131975 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 29 Apr 2010 00:22:43 -0400 Subject: drm/radeon/kms: more pm fixes - disable gui idle interrupt use Seems to hang some r5xx chips - move vbl range check into existing vbl check function in radeon_pm.c - disable crtc mc acccess for the whole reclocking process Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_reg.h | 2 ++ drivers/gpu/drm/radeon/r100.c | 6 ++-- drivers/gpu/drm/radeon/r600.c | 35 +++--------------- drivers/gpu/drm/radeon/radeon_pm.c | 65 +++++++++++++++++++--------------- 4 files changed, 45 insertions(+), 63 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 93aab2ebd9d..af86af836f1 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -164,10 +164,12 @@ #define EVERGREEN_CRTC5_REGISTER_OFFSET (0x129f0 - 0x6df0) /* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */ +#define EVERGREEN_CRTC_V_BLANK_START_END 0x6e34 #define EVERGREEN_CRTC_CONTROL 0x6e70 # define EVERGREEN_CRTC_MASTER_EN (1 << 0) # define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) #define EVERGREEN_CRTC_STATUS 0x6e8c +#define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index a5f11c300f6..493b9b48da3 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -178,14 +178,12 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) rdev->pm.current_sclk = sclk; DRM_INFO("Setting: e: %d\n", sclk); } -#if 0 /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { radeon_set_memory_clock(rdev, mclk); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } -#endif radeon_pm_finish(rdev); } else { radeon_sync_with_vblank(rdev); @@ -193,6 +191,7 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) if (!radeon_pm_in_vbl(rdev)) return; + radeon_pm_prepare(rdev); /* set engine clock */ if (sclk != rdev->pm.current_sclk) { radeon_pm_debug_check_in_vbl(rdev, false); @@ -205,13 +204,12 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { radeon_pm_debug_check_in_vbl(rdev, false); - radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); - radeon_pm_finish(rdev); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } + radeon_pm_finish(rdev); } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d3a79e0a912..75c825cb879 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -256,7 +256,6 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) return; if (radeon_gui_idle(rdev)) { - sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].sclk; if (sclk > rdev->clock.default_sclk) @@ -271,52 +270,27 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) radeon_pm_misc(rdev); if (static_switch) { - + radeon_pm_prepare(rdev); /* set engine clock */ if (sclk != rdev->pm.current_sclk) { radeon_set_engine_clock(rdev, sclk); rdev->pm.current_sclk = sclk; DRM_INFO("Setting: e: %d\n", sclk); } - /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); - radeon_pm_finish(rdev); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } - + radeon_pm_finish(rdev); } else { - u32 position; - u32 vbl; - radeon_sync_with_vblank(rdev); if (!radeon_pm_in_vbl(rdev)) return; - if (rdev->pm.active_crtcs & (1 << 0)) { - vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); - position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); - position &= 0xfff; - vbl &= 0xfff; - - if (position < vbl && position > 1) - return; - } - - if (rdev->pm.active_crtcs & (1 << 1)) { - vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); - position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); - position &= 0xfff; - vbl &= 0xfff; - - if (position < vbl && position > 1) - return; - } - + radeon_pm_prepare(rdev); if (sclk != rdev->pm.current_sclk) { radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, sclk); @@ -328,13 +302,12 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { radeon_pm_debug_check_in_vbl(rdev, false); - radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); - radeon_pm_finish(rdev); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } + radeon_pm_finish(rdev); } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 88163e043fc..2eb675e7844 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -64,7 +64,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->vram_mutex); mutex_lock(&rdev->cp.mutex); - +#if 0 /* wait for GPU idle */ rdev->pm.gui_idle = false; rdev->irq.gui_idle = true; @@ -74,7 +74,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); rdev->irq.gui_idle = false; radeon_irq_set(rdev); - +#endif radeon_unmap_vram_bos(rdev); if (!static_switch) { @@ -85,7 +85,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) } } } - + radeon_set_power_state(rdev, static_switch); if (!static_switch) { @@ -389,51 +389,57 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) bool radeon_pm_in_vbl(struct radeon_device *rdev) { - u32 stat_crtc = 0; + u32 stat_crtc = 0, vbl = 0, position = 0; bool in_vbl = true; if (ASIC_IS_DCE4(rdev)) { if (rdev->pm.active_crtcs & (1 << 0)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 1)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 2)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 3)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 4)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 5)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff; } } else if (ASIC_IS_AVIVO(rdev)) { if (rdev->pm.active_crtcs & (1 << 0)) { - stat_crtc = RREG32(D1CRTC_STATUS); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END) & 0xfff; + position = RREG32(AVIVO_D1CRTC_STATUS_POSITION) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 1)) { - stat_crtc = RREG32(D2CRTC_STATUS); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END) & 0xfff; + position = RREG32(AVIVO_D2CRTC_STATUS_POSITION) & 0xfff; } + if (position < vbl && position > 1) + in_vbl = false; } else { if (rdev->pm.active_crtcs & (1 << 0)) { stat_crtc = RREG32(RADEON_CRTC_STATUS); @@ -447,6 +453,9 @@ bool radeon_pm_in_vbl(struct radeon_device *rdev) } } + if (position < vbl && position > 1) + in_vbl = false; + return in_vbl; } -- cgit v1.2.3-70-g09d2 From d7311171c4cc8d6231427f7ac5056b939a184b80 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 3 May 2010 01:13:14 -0400 Subject: drm/radeon/kms/pm: add support for no display power states The lowest power states often cause display problems, so only enable them when all displays are off. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 9 ++++--- drivers/gpu/drm/radeon/r100.c | 12 ++++++--- drivers/gpu/drm/radeon/r600.c | 20 ++++++++++++--- drivers/gpu/drm/radeon/radeon.h | 7 ++++-- drivers/gpu/drm/radeon/radeon_atombios.c | 37 +++++++++++++++++++--------- drivers/gpu/drm/radeon/radeon_combios.c | 2 +- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 9 ++++--- drivers/gpu/drm/radeon/radeon_pm.c | 38 ++++++++++++++++++++--------- 8 files changed, 94 insertions(+), 40 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 4151ad8affe..03dd6c41dc1 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -245,13 +245,15 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) switch (mode) { case DRM_MODE_DPMS_ON: + radeon_crtc->enabled = true; + /* adjust pm to dpms changes BEFORE enabling crtcs */ + radeon_pm_compute_clocks(rdev); atombios_enable_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); atombios_blank_crtc(crtc, ATOM_DISABLE); drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); - radeon_crtc->enabled = true; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -262,11 +264,10 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); radeon_crtc->enabled = false; + /* adjust pm to dpms changes AFTER disabling crtcs */ + radeon_pm_compute_clocks(rdev); break; } - - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } static void diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 14b7541df38..4161a35dd3d 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -87,7 +87,7 @@ void r100_get_power_state(struct radeon_device *rdev, } else { if (rdev->pm.active_crtc_count > 1) { for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if (i >= rdev->pm.current_power_state_index) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; @@ -101,6 +101,12 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index - 1; } + /* don't use the power state if crtcs are active and no display flag is set */ + if ((rdev->pm.active_crtc_count > 0) && + (rdev->pm.power_state[rdev->pm.requested_power_state_index].clock_info[0].flags & + RADEON_PM_MODE_NO_DISPLAY)) { + rdev->pm.requested_power_state_index++; + } break; case PM_ACTION_UPCLOCK: if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { @@ -109,7 +115,7 @@ void r100_get_power_state(struct radeon_device *rdev, } else { if (rdev->pm.active_crtc_count > 1) { for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if (i <= rdev->pm.current_power_state_index) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; @@ -215,7 +221,7 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; } else - DRM_INFO("GUI not idle!!!\n"); + DRM_INFO("pm: GUI not idle!!!\n"); } void r100_pm_misc(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 75c825cb879..08a328c4165 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -120,7 +120,7 @@ void r600_get_power_state(struct radeon_device *rdev, } else { if (rdev->pm.active_crtc_count > 1) { for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if (i >= rdev->pm.current_power_state_index) { rdev->pm.requested_power_state_index = @@ -136,6 +136,13 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.current_power_state_index - 1; } rdev->pm.requested_clock_mode_index = 0; + /* don't use the power state if crtcs are active and no display flag is set */ + if ((rdev->pm.active_crtc_count > 0) && + (rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].flags & + RADEON_PM_MODE_NO_DISPLAY)) { + rdev->pm.requested_power_state_index++; + } break; case PM_ACTION_UPCLOCK: if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { @@ -144,7 +151,7 @@ void r600_get_power_state(struct radeon_device *rdev, } else { if (rdev->pm.active_crtc_count > 1) { for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if (i <= rdev->pm.current_power_state_index) { rdev->pm.requested_power_state_index = @@ -179,7 +186,7 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state_index = -1; /* start at 1 as we don't want the default mode */ for (i = 1; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) || (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) { @@ -210,6 +217,13 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.requested_clock_mode_index = 0; rdev->pm.can_downclock = false; } + /* don't use the power state if crtcs are active and no display flag is set */ + if ((rdev->pm.active_crtc_count > 0) && + (rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].flags & + RADEON_PM_MODE_NO_DISPLAY)) { + rdev->pm.requested_clock_mode_index++; + } break; case PM_ACTION_UPCLOCK: if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e39e2b4ec97..480a83ff54d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -658,6 +658,9 @@ struct radeon_voltage { u32 voltage; }; +/* clock mode flags */ +#define RADEON_PM_MODE_NO_DISPLAY (1 << 0) + struct radeon_pm_clock_info { /* memory clock */ u32 mclk; @@ -665,12 +668,12 @@ struct radeon_pm_clock_info { u32 sclk; /* voltage info */ struct radeon_voltage voltage; - /* standardized clock flags - not sure we'll need these */ + /* standardized clock flags */ u32 flags; }; /* state flags */ -#define RADEON_PM_SINGLE_DISPLAY_ONLY (1 << 0) +#define RADEON_PM_STATE_SINGLE_DISPLAY_ONLY (1 << 0) struct radeon_power_state { enum radeon_pm_state_type type; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index c29ac74a1d2..9149e4a3af0 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1549,7 +1549,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; } - rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].misc = misc; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) @@ -1568,7 +1568,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; } if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = @@ -1577,7 +1577,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + } else if (state_index == 0) { + rdev->pm.power_state[state_index].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; } state_index++; break; @@ -1613,7 +1616,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; } - rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].misc2 = misc2; /* order matters! */ @@ -1633,14 +1636,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; } if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT) rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; @@ -1648,7 +1651,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + } else if (state_index == 0) { + rdev->pm.power_state[state_index].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; } state_index++; break; @@ -1690,7 +1696,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; } } - rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].misc2 = misc2; /* order matters! */ @@ -1710,7 +1716,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; } if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) rdev->pm.power_state[state_index].type = @@ -1721,6 +1727,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; + } else if (state_index == 0) { + rdev->pm.power_state[state_index].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; } state_index++; break; @@ -1734,7 +1743,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index - 1].default_clock_mode = &rdev->pm.power_state[state_index - 1].clock_info[0]; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].misc = 0; rdev->pm.power_state[state_index].misc2 = 0; } @@ -1881,7 +1890,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].flags = 0; if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) rdev->pm.power_state[state_index].flags |= - RADEON_PM_SINGLE_DISPLAY_ONLY; + RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; @@ -1892,6 +1901,12 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) state_index++; } } + /* if multiple clock modes, mark the lowest as no display */ + for (i = 0; i < state_index; i++) { + if (rdev->pm.power_state[i].num_clock_modes > 1) + rdev->pm.power_state[i].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; + } /* first mode is usually default */ if (rdev->pm.default_power_state_index == -1) { rdev->pm.power_state[0].type = diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index c22344b7fc5..93f18bbf744 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2437,7 +2437,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) if (rev > 6) rdev->pm.power_state[state_index].pcie_lanes = RBIOS8(offset + 0x5 + 0x10); - rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; state_index++; } else { /* XXX figure out some good default low power mode for mobility cards w/out power tables */ diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 7701d42c480..e1e5255396a 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -314,6 +314,9 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) switch (mode) { case DRM_MODE_DPMS_ON: + radeon_crtc->enabled = true; + /* adjust pm to dpms changes BEFORE enabling crtcs */ + radeon_pm_compute_clocks(rdev); if (radeon_crtc->crtc_id) WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask)); else { @@ -323,7 +326,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); - radeon_crtc->enabled = true; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -337,11 +339,10 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); } radeon_crtc->enabled = false; + /* adjust pm to dpms changes AFTER disabling crtcs */ + radeon_pm_compute_clocks(rdev); break; } - - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 1ee7fc9918a..0dfa508fe5f 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -58,7 +58,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) { int i; - if (!static_switch) + if (rdev->pm.state != PM_STATE_DISABLED) radeon_get_power_state(rdev, rdev->pm.planned_action); mutex_lock(&rdev->ddev->struct_mutex); @@ -147,8 +147,11 @@ static ssize_t radeon_set_power_state_static(struct device *dev, mutex_lock(&rdev->pm.mutex); if ((ps >= 0) && (ps < rdev->pm.num_power_states) && (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { - if ((rdev->pm.active_crtc_count > 1) && - (rdev->pm.power_state[ps].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)) { + if ((rdev->pm.active_crtc_count > 0) && + (rdev->pm.power_state[ps].clock_info[cm].flags & RADEON_PM_MODE_NO_DISPLAY)) { + DRM_ERROR("Invalid power state for display: %d.%d\n", ps, cm); + } else if ((rdev->pm.active_crtc_count > 1) && + (rdev->pm.power_state[ps].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)) { DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm); } else { /* disable dynpm */ @@ -248,7 +251,7 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) is_default ? "(default)" : ""); if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes); - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) DRM_INFO("\tSingle display only\n"); DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { @@ -261,6 +264,8 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) j, rdev->pm.power_state[i].clock_info[j].sclk * 10, rdev->pm.power_state[i].clock_info[j].mclk * 10); + if (rdev->pm.power_state[i].clock_info[j].flags & RADEON_PM_MODE_NO_DISPLAY) + DRM_INFO("\t\tNo display only\n"); } } } @@ -318,7 +323,7 @@ void radeon_pm_fini(struct radeon_device *rdev) /* reset default clocks */ rdev->pm.state = PM_STATE_DISABLED; rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_pm_set_clocks(rdev, false); + radeon_pm_set_clocks(rdev, true); } else if ((rdev->pm.current_power_state_index != rdev->pm.default_power_state_index) || (rdev->pm.current_clock_mode_index != 0)) { @@ -342,9 +347,6 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; - if (rdev->pm.state == PM_STATE_DISABLED) - return; - mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; @@ -358,13 +360,22 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) } } + if (rdev->pm.state == PM_STATE_DISABLED) { + mutex_unlock(&rdev->pm.mutex); + return; + } + + /* Note, radeon_pm_set_clocks is called with static_switch set + * to true since we always want to statically set the clocks, + * not wait for vbl. + */ if (rdev->pm.active_crtc_count > 1) { if (rdev->pm.state == PM_STATE_ACTIVE) { cancel_delayed_work(&rdev->pm.idle_work); rdev->pm.state = PM_STATE_PAUSED; - rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_pm_set_clocks(rdev, false); + rdev->pm.planned_action = PM_ACTION_DEFAULT; + radeon_pm_set_clocks(rdev, true); DRM_DEBUG("radeon: dynamic power management deactivated\n"); } @@ -374,7 +385,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (rdev->pm.state == PM_STATE_MINIMUM) { rdev->pm.state = PM_STATE_ACTIVE; rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_pm_set_clocks(rdev, false); + radeon_pm_set_clocks(rdev, true); queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); @@ -390,7 +401,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) rdev->pm.state = PM_STATE_MINIMUM; rdev->pm.planned_action = PM_ACTION_MINIMUM; - radeon_pm_set_clocks(rdev, false); + radeon_pm_set_clocks(rdev, true); } } @@ -526,6 +537,9 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) } } + /* Note, radeon_pm_set_clocks is called with static_switch set + * to false since we want to wait for vbl to avoid flicker. + */ if (rdev->pm.planned_action != PM_ACTION_NONE && jiffies > rdev->pm.action_timeout) { radeon_pm_set_clocks(rdev, false); -- cgit v1.2.3-70-g09d2 From ce8f53709bf440100cb9d31b1303291551cf517f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 May 2010 15:10:16 -0400 Subject: drm/radeon/kms/pm: rework power management - Separate dynpm and profile based power management methods. You can select the pm method by echoing the selected method ("dynpm" or "profile") to power_method in sysfs. - Expose basic 4 profile in profile method "default" - default clocks "auto" - select between low and high based on ac/dc state "low" - DC, low power mode "high" - AC, performance mode The current base profile is "default", but it should switched to "auto" once we've tested on more systems. Switching the state is a matter of echoing the requested profile to power_profile in sysfs. The lowest power states are selected automatically when dpms turns the monitors off in all states but default. - Remove dynamic fence-based reclocking for the moment. We can revisit this later once we have basic pm in. - Move pm init/fini to modesetting path. pm is tightly coupled with display state. Make sure display side is initialized before pm. - Add pm suspend/resume functions to make sure pm state is properly reinitialized on resume. - Remove dynpm module option. It's now selectable via sysfs. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Kconfig | 1 + drivers/gpu/drm/radeon/evergreen.c | 3 - drivers/gpu/drm/radeon/r100.c | 128 ++----- drivers/gpu/drm/radeon/r300.c | 3 - drivers/gpu/drm/radeon/r420.c | 32 +- drivers/gpu/drm/radeon/r520.c | 2 - drivers/gpu/drm/radeon/r600.c | 332 ++++++++++++----- drivers/gpu/drm/radeon/radeon.h | 87 +++-- drivers/gpu/drm/radeon/radeon_asic.c | 56 +-- drivers/gpu/drm/radeon/radeon_asic.h | 12 +- drivers/gpu/drm/radeon/radeon_device.c | 2 + drivers/gpu/drm/radeon/radeon_display.c | 4 + drivers/gpu/drm/radeon/radeon_drv.c | 4 - drivers/gpu/drm/radeon/radeon_pm.c | 628 +++++++++++++++++++------------- drivers/gpu/drm/radeon/rs400.c | 3 - drivers/gpu/drm/radeon/rs600.c | 3 - drivers/gpu/drm/radeon/rs690.c | 3 - drivers/gpu/drm/radeon/rv515.c | 3 - drivers/gpu/drm/radeon/rv770.c | 3 - 19 files changed, 790 insertions(+), 519 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index 1c02d23f6fc..80c5b3ea28b 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -1,6 +1,7 @@ config DRM_RADEON_KMS bool "Enable modesetting on radeon by default - NEW DRIVER" depends on DRM_RADEON + depends on POWER_SUPPLY help Choose this option if you want kernel modesetting enabled by default. diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 8d86d0568d9..8c8e4d3cbaa 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2115,8 +2115,6 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_clocks_init(rdev); if (r) return r; - /* Initialize power management */ - radeon_pm_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -2178,7 +2176,6 @@ int evergreen_init(struct radeon_device *rdev) void evergreen_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); /*r600_blit_fini(rdev);*/ r700_cp_fini(rdev); r600_wb_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 4161a35dd3d..4c5d21bfa2c 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -68,22 +68,21 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ -void r100_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action) +void r100_pm_get_dynpm_state(struct radeon_device *rdev) { int i; - rdev->pm.can_upclock = true; - rdev->pm.can_downclock = true; + rdev->pm.dynpm_can_upclock = true; + rdev->pm.dynpm_can_downclock = true; - switch (action) { - case PM_ACTION_MINIMUM: + switch (rdev->pm.dynpm_planned_action) { + case DYNPM_ACTION_MINIMUM: rdev->pm.requested_power_state_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; break; - case PM_ACTION_DOWNCLOCK: + case DYNPM_ACTION_DOWNCLOCK: if (rdev->pm.current_power_state_index == 0) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; } else { if (rdev->pm.active_crtc_count > 1) { for (i = 0; i < rdev->pm.num_power_states; i++) { @@ -108,10 +107,10 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state_index++; } break; - case PM_ACTION_UPCLOCK: + case DYNPM_ACTION_UPCLOCK: if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; } else { if (rdev->pm.active_crtc_count > 1) { for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { @@ -130,11 +129,11 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.current_power_state_index + 1; } break; - case PM_ACTION_DEFAULT: + case DYNPM_ACTION_DEFAULT: rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; break; - case PM_ACTION_NONE: + case DYNPM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); return; @@ -151,77 +150,33 @@ void r100_get_power_state(struct radeon_device *rdev, pcie_lanes); } -void r100_set_power_state(struct radeon_device *rdev, bool static_switch) -{ - u32 sclk, mclk; - - if (rdev->pm.current_power_state_index == rdev->pm.requested_power_state_index) - return; - - if (radeon_gui_idle(rdev)) { - - sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].sclk; - if (sclk > rdev->clock.default_sclk) - sclk = rdev->clock.default_sclk; - - mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk; - if (mclk > rdev->clock.default_mclk) - mclk = rdev->clock.default_mclk; - /* don't change the mclk with multiple crtcs */ - if (rdev->pm.active_crtc_count > 1) - mclk = rdev->clock.default_mclk; - - /* voltage, pcie lanes, etc.*/ - radeon_pm_misc(rdev); - - if (static_switch) { - radeon_pm_prepare(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_set_engine_clock(rdev, sclk); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_set_memory_clock(rdev, mclk); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); - } else { - radeon_sync_with_vblank(rdev); - - if (!radeon_pm_in_vbl(rdev)) - return; - - radeon_pm_prepare(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } - - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); - } - - rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; - rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; - } else - DRM_INFO("pm: GUI not idle!!!\n"); +void r100_pm_init_profile(struct radeon_device *rdev) +{ + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; } void r100_pm_misc(struct radeon_device *rdev) @@ -3815,7 +3770,6 @@ int r100_suspend(struct radeon_device *rdev) void r100_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -3871,8 +3825,6 @@ int r100_init(struct radeon_device *rdev) r100_errata(rdev); /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 5d622cb39b3..5c54db51de8 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1345,7 +1345,6 @@ int r300_suspend(struct radeon_device *rdev) void r300_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -1401,8 +1400,6 @@ int r300_init(struct radeon_device *rdev) r300_errata(rdev); /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 3759d838429..87c0e384003 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -36,6 +36,35 @@ #include "r420d.h" #include "r420_reg_safe.h" +void r420_pm_init_profile(struct radeon_device *rdev) +{ + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; +} + static void r420_set_reg_safe(struct radeon_device *rdev) { rdev->config.r300.reg_safe_bm = r420_reg_safe_bm; @@ -268,7 +297,6 @@ int r420_suspend(struct radeon_device *rdev) void r420_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -328,8 +356,6 @@ int r420_init(struct radeon_device *rdev) /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 870111e26bd..34330df2848 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -261,8 +261,6 @@ int r520_init(struct radeon_device *rdev) } /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 08a328c4165..618d76d366a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,13 +92,12 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); -void r600_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action) +void r600_pm_get_dynpm_state(struct radeon_device *rdev) { int i; - rdev->pm.can_upclock = true; - rdev->pm.can_downclock = true; + rdev->pm.dynpm_can_upclock = true; + rdev->pm.dynpm_can_downclock = true; /* power state array is low to high, default is first */ if ((rdev->flags & RADEON_IS_IGP) || (rdev->family == CHIP_R600)) { @@ -107,16 +106,16 @@ void r600_get_power_state(struct radeon_device *rdev, if (rdev->pm.num_power_states > 2) min_power_state_index = 1; - switch (action) { - case PM_ACTION_MINIMUM: + switch (rdev->pm.dynpm_planned_action) { + case DYNPM_ACTION_MINIMUM: rdev->pm.requested_power_state_index = min_power_state_index; rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; break; - case PM_ACTION_DOWNCLOCK: + case DYNPM_ACTION_DOWNCLOCK: if (rdev->pm.current_power_state_index == min_power_state_index) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; } else { if (rdev->pm.active_crtc_count > 1) { for (i = 0; i < rdev->pm.num_power_states; i++) { @@ -144,10 +143,10 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state_index++; } break; - case PM_ACTION_UPCLOCK: + case DYNPM_ACTION_UPCLOCK: if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; } else { if (rdev->pm.active_crtc_count > 1) { for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { @@ -168,12 +167,12 @@ void r600_get_power_state(struct radeon_device *rdev, } rdev->pm.requested_clock_mode_index = 0; break; - case PM_ACTION_DEFAULT: + case DYNPM_ACTION_DEFAULT: rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; break; - case PM_ACTION_NONE: + case DYNPM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); return; @@ -200,22 +199,22 @@ void r600_get_power_state(struct radeon_device *rdev, } else rdev->pm.requested_power_state_index = 1; - switch (action) { - case PM_ACTION_MINIMUM: + switch (rdev->pm.dynpm_planned_action) { + case DYNPM_ACTION_MINIMUM: rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; break; - case PM_ACTION_DOWNCLOCK: + case DYNPM_ACTION_DOWNCLOCK: if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { if (rdev->pm.current_clock_mode_index == 0) { rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; } else rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index - 1; } else { rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; } /* don't use the power state if crtcs are active and no display flag is set */ if ((rdev->pm.active_crtc_count > 0) && @@ -225,27 +224,27 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.requested_clock_mode_index++; } break; - case PM_ACTION_UPCLOCK: + case DYNPM_ACTION_UPCLOCK: if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { if (rdev->pm.current_clock_mode_index == (rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1)) { rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; } else rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index + 1; } else { rdev->pm.requested_clock_mode_index = rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; } break; - case PM_ACTION_DEFAULT: + case DYNPM_ACTION_DEFAULT: rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; break; - case PM_ACTION_NONE: + case DYNPM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); return; @@ -261,73 +260,225 @@ void r600_get_power_state(struct radeon_device *rdev, pcie_lanes); } -void r600_set_power_state(struct radeon_device *rdev, bool static_switch) +static int r600_pm_get_type_index(struct radeon_device *rdev, + enum radeon_pm_state_type ps_type, + int instance) { - u32 sclk, mclk; - - if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && - (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) - return; - - if (radeon_gui_idle(rdev)) { - sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].sclk; - if (sclk > rdev->clock.default_sclk) - sclk = rdev->clock.default_sclk; - - mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk; - if (mclk > rdev->clock.default_mclk) - mclk = rdev->clock.default_mclk; - - /* voltage, pcie lanes, etc.*/ - radeon_pm_misc(rdev); + int i; + int found_instance = -1; - if (static_switch) { - radeon_pm_prepare(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_set_engine_clock(rdev, sclk); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_set_memory_clock(rdev, mclk); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == ps_type) { + found_instance++; + if (found_instance == instance) + return i; + } + } + /* return default if no match */ + return rdev->pm.default_power_state_index; +} + +void rs780_pm_init_profile(struct radeon_device *rdev) +{ + if (rdev->pm.num_power_states == 2) { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; + } else if (rdev->pm.num_power_states == 3) { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; + } else { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; + } +} + +void r600_pm_init_profile(struct radeon_device *rdev) +{ + if (rdev->family == CHIP_R600) { + /* XXX */ + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; + } else if (rdev->flags & RADEON_IS_MOBILITY) { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; + } else { + if (rdev->pm.num_power_states < 4) { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } else { - radeon_sync_with_vblank(rdev); - - if (!radeon_pm_in_vbl(rdev)) - return; - - radeon_pm_prepare(rdev); - if (sclk != rdev->pm.current_sclk) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } - - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } - - rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; - rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; - } else - DRM_INFO("GUI not idle!!!\n"); + } } void r600_pm_misc(struct radeon_device *rdev) @@ -2320,8 +2471,6 @@ int r600_init(struct radeon_device *rdev) r = radeon_clocks_init(rdev); if (r) return r; - /* Initialize power management */ - radeon_pm_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -2386,7 +2535,6 @@ int r600_init(struct radeon_device *rdev) void r600_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r600_audio_fini(rdev); r600_blit_fini(rdev); r600_cp_fini(rdev); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 480a83ff54d..5c9ce2beaca 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -89,7 +89,6 @@ extern int radeon_testing; extern int radeon_connector_table; extern int radeon_tv; extern int radeon_new_pll; -extern int radeon_dynpm; extern int radeon_audio; extern int radeon_disp_priority; extern int radeon_hw_i2c; @@ -173,11 +172,10 @@ struct radeon_clock { int radeon_pm_init(struct radeon_device *rdev); void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); +void radeon_pm_suspend(struct radeon_device *rdev); +void radeon_pm_resume(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); -bool radeon_pm_in_vbl(struct radeon_device *rdev); -bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); -void radeon_sync_with_vblank(struct radeon_device *rdev); /* * Fences. @@ -608,18 +606,24 @@ struct radeon_wb { * Equation between gpu/memory clock and available bandwidth is hw dependent * (type of memory, bus size, efficiency, ...) */ -enum radeon_pm_state { - PM_STATE_DISABLED, - PM_STATE_MINIMUM, - PM_STATE_PAUSED, - PM_STATE_ACTIVE + +enum radeon_pm_method { + PM_METHOD_PROFILE, + PM_METHOD_DYNPM, +}; + +enum radeon_dynpm_state { + DYNPM_STATE_DISABLED, + DYNPM_STATE_MINIMUM, + DYNPM_STATE_PAUSED, + DYNPM_STATE_ACTIVE }; -enum radeon_pm_action { - PM_ACTION_NONE, - PM_ACTION_MINIMUM, - PM_ACTION_DOWNCLOCK, - PM_ACTION_UPCLOCK, - PM_ACTION_DEFAULT +enum radeon_dynpm_action { + DYNPM_ACTION_NONE, + DYNPM_ACTION_MINIMUM, + DYNPM_ACTION_DOWNCLOCK, + DYNPM_ACTION_UPCLOCK, + DYNPM_ACTION_DEFAULT }; enum radeon_voltage_type { @@ -637,11 +641,25 @@ enum radeon_pm_state_type { POWER_STATE_TYPE_PERFORMANCE, }; -enum radeon_pm_clock_mode_type { - POWER_MODE_TYPE_DEFAULT, - POWER_MODE_TYPE_LOW, - POWER_MODE_TYPE_MID, - POWER_MODE_TYPE_HIGH, +enum radeon_pm_profile_type { + PM_PROFILE_DEFAULT, + PM_PROFILE_AUTO, + PM_PROFILE_LOW, + PM_PROFILE_HIGH, +}; + +#define PM_PROFILE_DEFAULT_IDX 0 +#define PM_PROFILE_LOW_SH_IDX 1 +#define PM_PROFILE_HIGH_SH_IDX 2 +#define PM_PROFILE_LOW_MH_IDX 3 +#define PM_PROFILE_HIGH_MH_IDX 4 +#define PM_PROFILE_MAX 5 + +struct radeon_pm_profile { + int dpms_off_ps_idx; + int dpms_on_ps_idx; + int dpms_off_cm_idx; + int dpms_on_cm_idx; }; struct radeon_voltage { @@ -696,12 +714,6 @@ struct radeon_power_state { struct radeon_pm { struct mutex mutex; - struct delayed_work idle_work; - enum radeon_pm_state state; - enum radeon_pm_action planned_action; - unsigned long action_timeout; - bool can_upclock; - bool can_downclock; u32 active_crtcs; int active_crtc_count; int req_vblank; @@ -731,6 +743,19 @@ struct radeon_pm { u32 current_sclk; u32 current_mclk; struct radeon_i2c_chan *i2c_bus; + /* selected pm method */ + enum radeon_pm_method pm_method; + /* dynpm power management */ + struct delayed_work dynpm_idle_work; + enum radeon_dynpm_state dynpm_state; + enum radeon_dynpm_action dynpm_planned_action; + unsigned long dynpm_action_timeout; + bool dynpm_can_upclock; + bool dynpm_can_downclock; + /* profile-based power management */ + enum radeon_pm_profile_type profile; + int profile_index; + struct radeon_pm_profile profiles[PM_PROFILE_MAX]; }; @@ -819,11 +844,12 @@ struct radeon_asic { */ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); bool (*gui_idle)(struct radeon_device *rdev); - void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); - void (*set_power_state)(struct radeon_device *rdev, bool static_switch); + /* power management */ void (*pm_misc)(struct radeon_device *rdev); void (*pm_prepare)(struct radeon_device *rdev); void (*pm_finish)(struct radeon_device *rdev); + void (*pm_init_profile)(struct radeon_device *rdev); + void (*pm_get_dynpm_state)(struct radeon_device *rdev); }; /* @@ -1041,6 +1067,7 @@ struct radeon_device { uint8_t audio_category_code; bool powered_down; + struct notifier_block acpi_nb; }; int radeon_device_init(struct radeon_device *rdev, @@ -1232,11 +1259,11 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) -#define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a)) -#define radeon_set_power_state(rdev, s) (rdev)->asic->set_power_state((rdev), (s)) #define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev)) #define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev)) #define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev)) +#define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev)) +#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 1e6f17bf54f..e57df08d4ae 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -166,11 +166,11 @@ static struct radeon_asic r100_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r200_asic = { @@ -210,11 +210,11 @@ static struct radeon_asic r200_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r300_asic = { @@ -255,11 +255,11 @@ static struct radeon_asic r300_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r300_asic_pcie = { @@ -299,11 +299,11 @@ static struct radeon_asic r300_asic_pcie = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r420_asic = { @@ -344,11 +344,11 @@ static struct radeon_asic r420_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic rs400_asic = { @@ -389,11 +389,11 @@ static struct radeon_asic rs400_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic rs600_asic = { @@ -434,11 +434,11 @@ static struct radeon_asic rs600_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &rs600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic rs690_asic = { @@ -479,11 +479,11 @@ static struct radeon_asic rs690_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &rs600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic rv515_asic = { @@ -524,11 +524,11 @@ static struct radeon_asic rv515_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &rs600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r520_asic = { @@ -569,11 +569,11 @@ static struct radeon_asic r520_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &rs600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r600_asic = { @@ -613,11 +613,11 @@ static struct radeon_asic r600_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, - .get_power_state = &r600_get_power_state, - .set_power_state = &r600_set_power_state, .pm_misc = &r600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r600_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; static struct radeon_asic rs780_asic = { @@ -657,11 +657,11 @@ static struct radeon_asic rs780_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, - .get_power_state = &r600_get_power_state, - .set_power_state = &r600_set_power_state, .pm_misc = &r600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &rs780_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; static struct radeon_asic rv770_asic = { @@ -701,11 +701,11 @@ static struct radeon_asic rv770_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, - .get_power_state = &r600_get_power_state, - .set_power_state = &r600_set_power_state, .pm_misc = &rv770_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r600_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; static struct radeon_asic evergreen_asic = { @@ -743,11 +743,11 @@ static struct radeon_asic evergreen_asic = { .hpd_sense = &evergreen_hpd_sense, .hpd_set_polarity = &evergreen_hpd_set_polarity, .gui_idle = &r600_gui_idle, - .get_power_state = &r600_get_power_state, - .set_power_state = &r600_set_power_state, .pm_misc = &evergreen_pm_misc, .pm_prepare = &evergreen_pm_prepare, .pm_finish = &evergreen_pm_finish, + .pm_init_profile = &r600_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 8a127862999..5c40a3dfaca 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -127,12 +127,11 @@ void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); extern bool r100_gui_idle(struct radeon_device *rdev); -extern void r100_set_power_state(struct radeon_device *rdev, bool static_switch); -extern void r100_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action); extern void r100_pm_misc(struct radeon_device *rdev); extern void r100_pm_prepare(struct radeon_device *rdev); extern void r100_pm_finish(struct radeon_device *rdev); +extern void r100_pm_init_profile(struct radeon_device *rdev); +extern void r100_pm_get_dynpm_state(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 @@ -170,6 +169,7 @@ extern int r420_init(struct radeon_device *rdev); extern void r420_fini(struct radeon_device *rdev); extern int r420_suspend(struct radeon_device *rdev); extern int r420_resume(struct radeon_device *rdev); +extern void r420_pm_init_profile(struct radeon_device *rdev); /* * rs400,rs480 @@ -281,10 +281,10 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); extern bool r600_gui_idle(struct radeon_device *rdev); -extern void r600_set_power_state(struct radeon_device *rdev, bool static_switch); -extern void r600_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action); extern void r600_pm_misc(struct radeon_device *rdev); +extern void r600_pm_init_profile(struct radeon_device *rdev); +extern void rs780_pm_init_profile(struct radeon_device *rdev); +extern void r600_pm_get_dynpm_state(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index e249da81dbf..a20b612ffe7 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -748,6 +748,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) radeon_save_bios_scratch_regs(rdev); + radeon_pm_suspend(rdev); radeon_suspend(rdev); radeon_hpd_fini(rdev); /* evict remaining vram memory */ @@ -783,6 +784,7 @@ int radeon_resume_kms(struct drm_device *dev) /* resume AGP if in use */ radeon_agp_resume(rdev); radeon_resume(rdev); + radeon_pm_resume(rdev); radeon_restore_bios_scratch_regs(rdev); radeon_fbdev_set_suspend(rdev, 0); release_console_sem(); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 10d70540fc5..f48f42454fb 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1037,6 +1037,9 @@ int radeon_modeset_init(struct radeon_device *rdev) /* initialize hpd */ radeon_hpd_init(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + radeon_fbdev_init(rdev); drm_kms_helper_poll_init(rdev->ddev); @@ -1047,6 +1050,7 @@ void radeon_modeset_fini(struct radeon_device *rdev) { radeon_fbdev_fini(rdev); kfree(rdev->mode_info.bios_hardcoded_edid); + radeon_pm_fini(rdev); if (rdev->mode_info.mode_config_initialized) { drm_kms_helper_poll_fini(rdev->ddev); diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 6e22815f7f0..4afba1eca2a 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -92,7 +92,6 @@ int radeon_testing = 0; int radeon_connector_table = 0; int radeon_tv = 1; int radeon_new_pll = -1; -int radeon_dynpm = -1; int radeon_audio = 1; int radeon_disp_priority = 0; int radeon_hw_i2c = 0; @@ -133,9 +132,6 @@ module_param_named(tv, radeon_tv, int, 0444); MODULE_PARM_DESC(new_pll, "Select new PLL code"); module_param_named(new_pll, radeon_new_pll, int, 0444); -MODULE_PARM_DESC(dynpm, "Disable/Enable dynamic power management (1 = enable)"); -module_param_named(dynpm, radeon_dynpm, int, 0444); - MODULE_PARM_DESC(audio, "Audio enable (0 = disable)"); module_param_named(audio, radeon_audio, int, 0444); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 0dfa508fe5f..1827317704a 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -23,14 +23,98 @@ #include "drmP.h" #include "radeon.h" #include "avivod.h" +#ifdef CONFIG_ACPI +#include +#endif +#include #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 #define RADEON_WAIT_VBLANK_TIMEOUT 200 #define RADEON_WAIT_IDLE_TIMEOUT 200 -static void radeon_pm_idle_work_handler(struct work_struct *work); +static void radeon_dynpm_idle_work_handler(struct work_struct *work); static int radeon_debugfs_pm_init(struct radeon_device *rdev); +static bool radeon_pm_in_vbl(struct radeon_device *rdev); +static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); +static void radeon_pm_update_profile(struct radeon_device *rdev); +static void radeon_pm_set_clocks(struct radeon_device *rdev); + +#define ACPI_AC_CLASS "ac_adapter" + +#ifdef CONFIG_ACPI +static int radeon_acpi_event(struct notifier_block *nb, + unsigned long val, + void *data) +{ + struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); + struct acpi_bus_event *entry = (struct acpi_bus_event *)data; + + if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { + if (power_supply_is_system_supplied() > 0) + DRM_INFO("pm: AC\n"); + else + DRM_INFO("pm: DC\n"); + + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + if (rdev->pm.profile == PM_PROFILE_AUTO) { + mutex_lock(&rdev->pm.mutex); + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + mutex_unlock(&rdev->pm.mutex); + } + } + } + + return NOTIFY_OK; +} +#endif + +static void radeon_pm_update_profile(struct radeon_device *rdev) +{ + switch (rdev->pm.profile) { + case PM_PROFILE_DEFAULT: + rdev->pm.profile_index = PM_PROFILE_DEFAULT_IDX; + break; + case PM_PROFILE_AUTO: + if (power_supply_is_system_supplied() > 0) { + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX; + } else { + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX; + } + break; + case PM_PROFILE_LOW: + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX; + break; + case PM_PROFILE_HIGH: + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX; + break; + } + + if (rdev->pm.active_crtc_count == 0) { + rdev->pm.requested_power_state_index = + rdev->pm.profiles[rdev->pm.profile_index].dpms_off_ps_idx; + rdev->pm.requested_clock_mode_index = + rdev->pm.profiles[rdev->pm.profile_index].dpms_off_cm_idx; + } else { + rdev->pm.requested_power_state_index = + rdev->pm.profiles[rdev->pm.profile_index].dpms_on_ps_idx; + rdev->pm.requested_clock_mode_index = + rdev->pm.profiles[rdev->pm.profile_index].dpms_on_cm_idx; + } +} static void radeon_unmap_vram_bos(struct radeon_device *rdev) { @@ -54,12 +138,93 @@ static void radeon_unmap_vram_bos(struct radeon_device *rdev) ttm_bo_unmap_virtual(&rdev->r600_blit.shader_obj->tbo); } -static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) +static void radeon_sync_with_vblank(struct radeon_device *rdev) { - int i; + if (rdev->pm.active_crtcs) { + rdev->pm.vblank_sync = false; + wait_event_timeout( + rdev->irq.vblank_queue, rdev->pm.vblank_sync, + msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); + } +} + +static void radeon_set_power_state(struct radeon_device *rdev) +{ + u32 sclk, mclk; + + if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && + (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) + return; + + if (radeon_gui_idle(rdev)) { + sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk; + if (sclk > rdev->clock.default_sclk) + sclk = rdev->clock.default_sclk; + + mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk; + if (mclk > rdev->clock.default_mclk) + mclk = rdev->clock.default_mclk; + + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); + + if (rdev->pm.pm_method == PM_METHOD_DYNPM) { + radeon_sync_with_vblank(rdev); + + if (!radeon_pm_in_vbl(rdev)) + return; + + radeon_pm_prepare(rdev); + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } + + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } + radeon_pm_finish(rdev); + } else { + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_prepare(rdev); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_finish(rdev); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_prepare(rdev); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_finish(rdev); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } + } - if (rdev->pm.state != PM_STATE_DISABLED) - radeon_get_power_state(rdev, rdev->pm.planned_action); + rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; + rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; + } else + DRM_INFO("pm: GUI not idle!!!\n"); +} + +static void radeon_pm_set_clocks(struct radeon_device *rdev) +{ + int i; mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->vram_mutex); @@ -67,27 +232,31 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) /* gui idle int has issues on older chips it seems */ if (rdev->family >= CHIP_R600) { - /* wait for GPU idle */ - rdev->pm.gui_idle = false; - rdev->irq.gui_idle = true; - radeon_irq_set(rdev); - wait_event_interruptible_timeout( - rdev->irq.idle_queue, rdev->pm.gui_idle, - msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); - rdev->irq.gui_idle = false; - radeon_irq_set(rdev); + if (rdev->irq.installed) { + /* wait for GPU idle */ + rdev->pm.gui_idle = false; + rdev->irq.gui_idle = true; + radeon_irq_set(rdev); + wait_event_interruptible_timeout( + rdev->irq.idle_queue, rdev->pm.gui_idle, + msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); + rdev->irq.gui_idle = false; + radeon_irq_set(rdev); + } } else { - struct radeon_fence *fence; - radeon_ring_alloc(rdev, 64); - radeon_fence_create(rdev, &fence); - radeon_fence_emit(rdev, fence); - radeon_ring_commit(rdev); - radeon_fence_wait(fence, false); - radeon_fence_unref(&fence); + if (rdev->cp.ready) { + struct radeon_fence *fence; + radeon_ring_alloc(rdev, 64); + radeon_fence_create(rdev, &fence); + radeon_fence_emit(rdev, fence); + radeon_ring_commit(rdev); + radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); + } } radeon_unmap_vram_bos(rdev); - if (!static_switch) { + if (rdev->irq.installed) { for (i = 0; i < rdev->num_crtc; i++) { if (rdev->pm.active_crtcs & (1 << i)) { rdev->pm.req_vblank |= (1 << i); @@ -96,9 +265,9 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) } } - radeon_set_power_state(rdev, static_switch); + radeon_set_power_state(rdev); - if (!static_switch) { + if (rdev->irq.installed) { for (i = 0; i < rdev->num_crtc; i++) { if (rdev->pm.req_vblank & (1 << i)) { rdev->pm.req_vblank &= ~(1 << i); @@ -112,230 +281,195 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) if (rdev->pm.active_crtc_count) radeon_bandwidth_update(rdev); - rdev->pm.planned_action = PM_ACTION_NONE; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; mutex_unlock(&rdev->cp.mutex); mutex_unlock(&rdev->vram_mutex); mutex_unlock(&rdev->ddev->struct_mutex); } -static ssize_t radeon_get_power_state_static(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t radeon_get_pm_profile(struct device *dev, + struct device_attribute *attr, + char *buf) { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; + int cp = rdev->pm.profile; - return snprintf(buf, PAGE_SIZE, "%d.%d\n", rdev->pm.current_power_state_index, - rdev->pm.current_clock_mode_index); + return snprintf(buf, PAGE_SIZE, "%s\n", + (cp == PM_PROFILE_AUTO) ? "auto" : + (cp == PM_PROFILE_LOW) ? "low" : + (cp == PM_PROFILE_HIGH) ? "high" : "default"); } -static ssize_t radeon_set_power_state_static(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +static ssize_t radeon_set_pm_profile(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; - int ps, cm; - - if (sscanf(buf, "%u.%u", &ps, &cm) != 2) { - DRM_ERROR("Invalid power state!\n"); - return count; - } mutex_lock(&rdev->pm.mutex); - if ((ps >= 0) && (ps < rdev->pm.num_power_states) && - (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { - if ((rdev->pm.active_crtc_count > 0) && - (rdev->pm.power_state[ps].clock_info[cm].flags & RADEON_PM_MODE_NO_DISPLAY)) { - DRM_ERROR("Invalid power state for display: %d.%d\n", ps, cm); - } else if ((rdev->pm.active_crtc_count > 1) && - (rdev->pm.power_state[ps].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)) { - DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm); - } else { - /* disable dynpm */ - rdev->pm.state = PM_STATE_DISABLED; - rdev->pm.planned_action = PM_ACTION_NONE; - rdev->pm.requested_power_state_index = ps; - rdev->pm.requested_clock_mode_index = cm; - radeon_pm_set_clocks(rdev, true); + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + if (strncmp("default", buf, strlen("default")) == 0) + rdev->pm.profile = PM_PROFILE_DEFAULT; + else if (strncmp("auto", buf, strlen("auto")) == 0) + rdev->pm.profile = PM_PROFILE_AUTO; + else if (strncmp("low", buf, strlen("low")) == 0) + rdev->pm.profile = PM_PROFILE_LOW; + else if (strncmp("high", buf, strlen("high")) == 0) + rdev->pm.profile = PM_PROFILE_HIGH; + else { + DRM_ERROR("invalid power profile!\n"); + goto fail; } - } else - DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm); + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + } +fail: mutex_unlock(&rdev->pm.mutex); return count; } -static ssize_t radeon_get_dynpm(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t radeon_get_pm_method(struct device *dev, + struct device_attribute *attr, + char *buf) { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; + int pm = rdev->pm.pm_method; return snprintf(buf, PAGE_SIZE, "%s\n", - (rdev->pm.state == PM_STATE_DISABLED) ? "disabled" : "enabled"); + (pm == PM_METHOD_DYNPM) ? "dynpm" : "profile"); } -static ssize_t radeon_set_dynpm(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +static ssize_t radeon_set_pm_method(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; - int tmp = simple_strtoul(buf, NULL, 10); - if (tmp == 0) { - /* update power mode info */ - radeon_pm_compute_clocks(rdev); - /* disable dynpm */ + + if (strncmp("dynpm", buf, strlen("dynpm")) == 0) { mutex_lock(&rdev->pm.mutex); - rdev->pm.state = PM_STATE_DISABLED; - rdev->pm.planned_action = PM_ACTION_NONE; + rdev->pm.pm_method = PM_METHOD_DYNPM; + rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; mutex_unlock(&rdev->pm.mutex); - DRM_INFO("radeon: dynamic power management disabled\n"); - } else if (tmp == 1) { - if (rdev->pm.num_power_states > 1) { - /* enable dynpm */ - mutex_lock(&rdev->pm.mutex); - rdev->pm.state = PM_STATE_PAUSED; - rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_get_power_state(rdev, rdev->pm.planned_action); - mutex_unlock(&rdev->pm.mutex); - /* update power mode info */ - radeon_pm_compute_clocks(rdev); - DRM_INFO("radeon: dynamic power management enabled\n"); - } else - DRM_ERROR("dynpm not valid on this system\n"); - } else - DRM_ERROR("Invalid setting: %d\n", tmp); - + } else if (strncmp("profile", buf, strlen("profile")) == 0) { + mutex_lock(&rdev->pm.mutex); + rdev->pm.pm_method = PM_METHOD_PROFILE; + /* disable dynpm */ + rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; + cancel_delayed_work(&rdev->pm.dynpm_idle_work); + mutex_unlock(&rdev->pm.mutex); + } else { + DRM_ERROR("invalid power method!\n"); + goto fail; + } + radeon_pm_compute_clocks(rdev); +fail: return count; } -static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, radeon_get_power_state_static, radeon_set_power_state_static); -static DEVICE_ATTR(dynpm, S_IRUGO | S_IWUSR, radeon_get_dynpm, radeon_set_dynpm); - +static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); +static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); -static const char *pm_state_names[4] = { - "PM_STATE_DISABLED", - "PM_STATE_MINIMUM", - "PM_STATE_PAUSED", - "PM_STATE_ACTIVE" -}; - -static const char *pm_state_types[5] = { - "", - "Powersave", - "Battery", - "Balanced", - "Performance", -}; - -static void radeon_print_power_mode_info(struct radeon_device *rdev) +void radeon_pm_suspend(struct radeon_device *rdev) { - int i, j; - bool is_default; - - DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states); - for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.default_power_state_index == i) - is_default = true; - else - is_default = false; - DRM_INFO("State %d %s %s\n", i, - pm_state_types[rdev->pm.power_state[i].type], - is_default ? "(default)" : ""); - if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) - DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes); - if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) - DRM_INFO("\tSingle display only\n"); - DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); - for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { - if (rdev->flags & RADEON_IS_IGP) - DRM_INFO("\t\t%d engine: %d\n", - j, - rdev->pm.power_state[i].clock_info[j].sclk * 10); - else - DRM_INFO("\t\t%d engine/memory: %d/%d\n", - j, - rdev->pm.power_state[i].clock_info[j].sclk * 10, - rdev->pm.power_state[i].clock_info[j].mclk * 10); - if (rdev->pm.power_state[i].clock_info[j].flags & RADEON_PM_MODE_NO_DISPLAY) - DRM_INFO("\t\tNo display only\n"); - } - } + mutex_lock(&rdev->pm.mutex); + cancel_delayed_work(&rdev->pm.dynpm_idle_work); + rdev->pm.current_power_state_index = -1; + rdev->pm.current_clock_mode_index = -1; + rdev->pm.current_sclk = 0; + rdev->pm.current_mclk = 0; + mutex_unlock(&rdev->pm.mutex); } -void radeon_sync_with_vblank(struct radeon_device *rdev) +void radeon_pm_resume(struct radeon_device *rdev) { - if (rdev->pm.active_crtcs) { - rdev->pm.vblank_sync = false; - wait_event_timeout( - rdev->irq.vblank_queue, rdev->pm.vblank_sync, - msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); - } + radeon_pm_compute_clocks(rdev); } int radeon_pm_init(struct radeon_device *rdev) { - rdev->pm.state = PM_STATE_DISABLED; - rdev->pm.planned_action = PM_ACTION_NONE; - rdev->pm.can_upclock = true; - rdev->pm.can_downclock = true; + /* default to profile method */ + rdev->pm.pm_method = PM_METHOD_PROFILE; + rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; + rdev->pm.dynpm_can_upclock = true; + rdev->pm.dynpm_can_downclock = true; + rdev->pm.current_sclk = 0; + rdev->pm.current_mclk = 0; if (rdev->bios) { if (rdev->is_atom_bios) radeon_atombios_get_power_modes(rdev); else radeon_combios_get_power_modes(rdev); - radeon_print_power_mode_info(rdev); + radeon_pm_init_profile(rdev); + rdev->pm.current_power_state_index = -1; + rdev->pm.current_clock_mode_index = -1; } - if (radeon_debugfs_pm_init(rdev)) { - DRM_ERROR("Failed to register debugfs file for PM!\n"); - } + if (rdev->pm.num_power_states > 1) { + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + mutex_lock(&rdev->pm.mutex); + rdev->pm.profile = PM_PROFILE_DEFAULT; + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + mutex_unlock(&rdev->pm.mutex); + } - /* where's the best place to put this? */ - device_create_file(rdev->dev, &dev_attr_power_state); - device_create_file(rdev->dev, &dev_attr_dynpm); + /* where's the best place to put these? */ + device_create_file(rdev->dev, &dev_attr_power_profile); + device_create_file(rdev->dev, &dev_attr_power_method); - INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); +#ifdef CONFIG_ACPI + rdev->acpi_nb.notifier_call = radeon_acpi_event; + register_acpi_notifier(&rdev->acpi_nb); +#endif + INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); - if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) { - rdev->pm.state = PM_STATE_PAUSED; - DRM_INFO("radeon: dynamic power management enabled\n"); - } + if (radeon_debugfs_pm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for PM!\n"); + } - DRM_INFO("radeon: power management initialized\n"); + DRM_INFO("radeon: power management initialized\n"); + } return 0; } void radeon_pm_fini(struct radeon_device *rdev) { - if (rdev->pm.state != PM_STATE_DISABLED) { - /* cancel work */ - cancel_delayed_work_sync(&rdev->pm.idle_work); - /* reset default clocks */ - rdev->pm.state = PM_STATE_DISABLED; - rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_pm_set_clocks(rdev, true); - } else if ((rdev->pm.current_power_state_index != - rdev->pm.default_power_state_index) || - (rdev->pm.current_clock_mode_index != 0)) { - rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; - rdev->pm.requested_clock_mode_index = 0; + if (rdev->pm.num_power_states > 1) { mutex_lock(&rdev->pm.mutex); - radeon_pm_set_clocks(rdev, true); + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + rdev->pm.profile = PM_PROFILE_DEFAULT; + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { + /* cancel work */ + cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); + /* reset default clocks */ + rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; + radeon_pm_set_clocks(rdev); + } mutex_unlock(&rdev->pm.mutex); - } - device_remove_file(rdev->dev, &dev_attr_power_state); - device_remove_file(rdev->dev, &dev_attr_dynpm); + device_remove_file(rdev->dev, &dev_attr_power_profile); + device_remove_file(rdev->dev, &dev_attr_power_method); +#ifdef CONFIG_ACPI + unregister_acpi_notifier(&rdev->acpi_nb); +#endif + } if (rdev->pm.i2c_bus) radeon_i2c_destroy(rdev->pm.i2c_bus); @@ -347,6 +481,9 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; + if (rdev->pm.num_power_states < 2) + return; + mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; @@ -360,55 +497,56 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) } } - if (rdev->pm.state == PM_STATE_DISABLED) { - mutex_unlock(&rdev->pm.mutex); - return; - } - - /* Note, radeon_pm_set_clocks is called with static_switch set - * to true since we always want to statically set the clocks, - * not wait for vbl. - */ - if (rdev->pm.active_crtc_count > 1) { - if (rdev->pm.state == PM_STATE_ACTIVE) { - cancel_delayed_work(&rdev->pm.idle_work); - - rdev->pm.state = PM_STATE_PAUSED; - rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_pm_set_clocks(rdev, true); - - DRM_DEBUG("radeon: dynamic power management deactivated\n"); - } - } else if (rdev->pm.active_crtc_count == 1) { - /* TODO: Increase clocks if needed for current mode */ - - if (rdev->pm.state == PM_STATE_MINIMUM) { - rdev->pm.state = PM_STATE_ACTIVE; - rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_pm_set_clocks(rdev, true); - - queue_delayed_work(rdev->wq, &rdev->pm.idle_work, - msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); - } else if (rdev->pm.state == PM_STATE_PAUSED) { - rdev->pm.state = PM_STATE_ACTIVE; - queue_delayed_work(rdev->wq, &rdev->pm.idle_work, - msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); - DRM_DEBUG("radeon: dynamic power management activated\n"); - } - } else { /* count == 0 */ - if (rdev->pm.state != PM_STATE_MINIMUM) { - cancel_delayed_work(&rdev->pm.idle_work); - - rdev->pm.state = PM_STATE_MINIMUM; - rdev->pm.planned_action = PM_ACTION_MINIMUM; - radeon_pm_set_clocks(rdev, true); + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { + if (rdev->pm.dynpm_state != DYNPM_STATE_DISABLED) { + if (rdev->pm.active_crtc_count > 1) { + if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { + cancel_delayed_work(&rdev->pm.dynpm_idle_work); + + rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; + radeon_pm_get_dynpm_state(rdev); + radeon_pm_set_clocks(rdev); + + DRM_DEBUG("radeon: dynamic power management deactivated\n"); + } + } else if (rdev->pm.active_crtc_count == 1) { + /* TODO: Increase clocks if needed for current mode */ + + if (rdev->pm.dynpm_state == DYNPM_STATE_MINIMUM) { + rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_UPCLOCK; + radeon_pm_get_dynpm_state(rdev); + radeon_pm_set_clocks(rdev); + + queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) { + rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; + queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + DRM_DEBUG("radeon: dynamic power management activated\n"); + } + } else { /* count == 0 */ + if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) { + cancel_delayed_work(&rdev->pm.dynpm_idle_work); + + rdev->pm.dynpm_state = DYNPM_STATE_MINIMUM; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_MINIMUM; + radeon_pm_get_dynpm_state(rdev); + radeon_pm_set_clocks(rdev); + } + } } } mutex_unlock(&rdev->pm.mutex); } -bool radeon_pm_in_vbl(struct radeon_device *rdev) +static bool radeon_pm_in_vbl(struct radeon_device *rdev) { u32 stat_crtc = 0, vbl = 0, position = 0; bool in_vbl = true; @@ -480,7 +618,7 @@ bool radeon_pm_in_vbl(struct radeon_device *rdev) return in_vbl; } -bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) { u32 stat_crtc = 0; bool in_vbl = radeon_pm_in_vbl(rdev); @@ -491,16 +629,16 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) return in_vbl; } -static void radeon_pm_idle_work_handler(struct work_struct *work) +static void radeon_dynpm_idle_work_handler(struct work_struct *work) { struct radeon_device *rdev; int resched; rdev = container_of(work, struct radeon_device, - pm.idle_work.work); + pm.dynpm_idle_work.work); resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); mutex_lock(&rdev->pm.mutex); - if (rdev->pm.state == PM_STATE_ACTIVE) { + if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { unsigned long irq_flags; int not_processed = 0; @@ -516,23 +654,23 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) read_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); if (not_processed >= 3) { /* should upclock */ - if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) { - rdev->pm.planned_action = PM_ACTION_NONE; - } else if (rdev->pm.planned_action == PM_ACTION_NONE && - rdev->pm.can_upclock) { - rdev->pm.planned_action = - PM_ACTION_UPCLOCK; - rdev->pm.action_timeout = jiffies + + if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_DOWNCLOCK) { + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; + } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE && + rdev->pm.dynpm_can_upclock) { + rdev->pm.dynpm_planned_action = + DYNPM_ACTION_UPCLOCK; + rdev->pm.dynpm_action_timeout = jiffies + msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); } } else if (not_processed == 0) { /* should downclock */ - if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) { - rdev->pm.planned_action = PM_ACTION_NONE; - } else if (rdev->pm.planned_action == PM_ACTION_NONE && - rdev->pm.can_downclock) { - rdev->pm.planned_action = - PM_ACTION_DOWNCLOCK; - rdev->pm.action_timeout = jiffies + + if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_UPCLOCK) { + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; + } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE && + rdev->pm.dynpm_can_downclock) { + rdev->pm.dynpm_planned_action = + DYNPM_ACTION_DOWNCLOCK; + rdev->pm.dynpm_action_timeout = jiffies + msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); } } @@ -540,15 +678,16 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) /* Note, radeon_pm_set_clocks is called with static_switch set * to false since we want to wait for vbl to avoid flicker. */ - if (rdev->pm.planned_action != PM_ACTION_NONE && - jiffies > rdev->pm.action_timeout) { - radeon_pm_set_clocks(rdev, false); + if (rdev->pm.dynpm_planned_action != DYNPM_ACTION_NONE && + jiffies > rdev->pm.dynpm_action_timeout) { + radeon_pm_get_dynpm_state(rdev); + radeon_pm_set_clocks(rdev); } } mutex_unlock(&rdev->pm.mutex); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); - queue_delayed_work(rdev->wq, &rdev->pm.idle_work, + queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); } @@ -563,7 +702,6 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct radeon_device *rdev = dev->dev_private; - seq_printf(m, "state: %s\n", pm_state_names[rdev->pm.state]); seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk); seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index dc76fe76eb2..9e4240b3bf0 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -456,7 +456,6 @@ int rs400_suspend(struct radeon_device *rdev) void rs400_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -507,8 +506,6 @@ int rs400_init(struct radeon_device *rdev) /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize memory controller */ rs400_mc_init(rdev); /* Fence driver */ diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 8e0c46060b3..e8c68e9c0a1 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -846,7 +846,6 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -896,8 +895,6 @@ int rs600_init(struct radeon_device *rdev) /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize memory controller */ rs600_mc_init(rdev); rs600_debugfs(rdev); diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index e8edfe61728..bcc33195ebc 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -676,7 +676,6 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -727,8 +726,6 @@ int rs690_init(struct radeon_device *rdev) /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize memory controller */ rs690_mc_init(rdev); rv515_debugfs(rdev); diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 2009f4b20c2..7d9a7b0a180 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -445,7 +445,6 @@ void rv515_set_safe_registers(struct radeon_device *rdev) void rv515_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -494,8 +493,6 @@ int rv515_init(struct radeon_device *rdev) return -EINVAL; /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 7c55182a9dd..253f24aec03 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1091,8 +1091,6 @@ int rv770_init(struct radeon_device *rdev) r = radeon_clocks_init(rdev); if (r) return r; - /* Initialize power management */ - radeon_pm_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -1161,7 +1159,6 @@ int rv770_init(struct radeon_device *rdev) void rv770_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r600_blit_fini(rdev); r700_cp_fini(rdev); r600_wb_fini(rdev); -- cgit v1.2.3-70-g09d2 From ce8a3eb20c4cb7d9e0c33e7560070688cd9066fc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 May 2010 16:58:27 -0400 Subject: drm/radeon/kms/pm: make pm spam debug only Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 16 ++++++++-------- drivers/gpu/drm/radeon/r600.c | 14 +++++++------- drivers/gpu/drm/radeon/radeon_pm.c | 16 ++++++++-------- drivers/gpu/drm/radeon/rs600.c | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 4c5d21bfa2c..9a59ba46f07 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -141,13 +141,13 @@ void r100_pm_get_dynpm_state(struct radeon_device *rdev) /* only one clock mode per power state */ rdev->pm.requested_clock_mode_index = 0; - DRM_INFO("Requested: e: %d m: %d p: %d\n", - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].sclk, - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk, - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - pcie_lanes); + DRM_DEBUG("Requested: e: %d m: %d p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + pcie_lanes); } void r100_pm_init_profile(struct radeon_device *rdev) @@ -266,7 +266,7 @@ void r100_pm_misc(struct radeon_device *rdev) rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { radeon_set_pcie_lanes(rdev, ps->pcie_lanes); - DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); + DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes); } } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 618d76d366a..0fef3351660 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -251,13 +251,13 @@ void r600_pm_get_dynpm_state(struct radeon_device *rdev) } } - DRM_INFO("Requested: e: %d m: %d p: %d\n", - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].sclk, - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk, - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - pcie_lanes); + DRM_DEBUG("Requested: e: %d m: %d p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + pcie_lanes); } static int r600_pm_get_type_index(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 1827317704a..c88edae33de 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -52,9 +52,9 @@ static int radeon_acpi_event(struct notifier_block *nb, if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { if (power_supply_is_system_supplied() > 0) - DRM_INFO("pm: AC\n"); + DRM_DEBUG("pm: AC\n"); else - DRM_INFO("pm: DC\n"); + DRM_DEBUG("pm: DC\n"); if (rdev->pm.pm_method == PM_METHOD_PROFILE) { if (rdev->pm.profile == PM_PROFILE_AUTO) { @@ -183,7 +183,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_engine_clock(rdev, sclk); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); + DRM_DEBUG("Setting: e: %d\n", sclk); } /* set memory clock */ @@ -192,7 +192,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_memory_clock(rdev, mclk); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); + DRM_DEBUG("Setting: m: %d\n", mclk); } radeon_pm_finish(rdev); } else { @@ -203,7 +203,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_engine_clock(rdev, sclk); radeon_pm_finish(rdev); rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); + DRM_DEBUG("Setting: e: %d\n", sclk); } /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { @@ -212,14 +212,14 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_memory_clock(rdev, mclk); radeon_pm_finish(rdev); rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); + DRM_DEBUG("Setting: m: %d\n", mclk); } } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; } else - DRM_INFO("pm: GUI not idle!!!\n"); + DRM_DEBUG("pm: GUI not idle!!!\n"); } static void radeon_pm_set_clocks(struct radeon_device *rdev) @@ -624,7 +624,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish bool in_vbl = radeon_pm_in_vbl(rdev); if (in_vbl == false) - DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc, + DRM_DEBUG("not in vbl for pm change %08x at %s\n", stat_crtc, finish ? "exit" : "entry"); return in_vbl; } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index e8c68e9c0a1..79887cac5b5 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -135,7 +135,7 @@ void rs600_pm_misc(struct radeon_device *rdev) rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { radeon_set_pcie_lanes(rdev, ps->pcie_lanes); - DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); + DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes); } } -- cgit v1.2.3-70-g09d2 From 4bff51711ca8709c5f18640ad6e8ae6b9e8f8047 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 17 May 2010 19:41:26 -0400 Subject: drm/radeon/kms/pm: fix r6xx+ profile setup This patch is a combination of the previous two profile patches, but without the index bugs. It cleans up and fixes some issues with pm profile setup on r6xx chips. Some tables have different orderings for the power states, also, r600 only has 1 clock mode per power state. On desktop cards there are no battery modes, so the low and high power states are the same. For the low profile case, choose the lower clock mode. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 114 ++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 61 deletions(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 0fef3351660..7ffc3892c65 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -369,61 +369,27 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; /* low sh */ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; /* low mh */ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; - } else if (rdev->flags & RADEON_IS_MOBILITY) { - /* default */ - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; - /* low sh */ - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; - /* high sh */ - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; - /* low mh */ - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; - /* high mh */ - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; } else { if (rdev->pm.num_power_states < 4) { /* default */ @@ -432,23 +398,23 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; /* low sh */ - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; /* high sh */ - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; /* low mh */ - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 1; /* high mh */ - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } else { @@ -458,23 +424,49 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; /* low sh */ - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + if (rdev->flags & RADEON_IS_MOBILITY) { + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + } else { + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; + } /* high sh */ - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; /* low mh */ - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 3; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 3; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + if (rdev->flags & RADEON_IS_MOBILITY) { + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + } else { + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 1; + } /* high mh */ - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 3; - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } -- cgit v1.2.3-70-g09d2 From b486787ee4797d6e42a9bd3a6f079385ad0f4472 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 20 May 2010 18:44:49 -0400 Subject: drm/radeon/kms/pm/r600: select the mid clock mode for single head low profile This saves some more power at the expense of performance. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/r600.c') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 7ffc3892c65..44e96a2ae25 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -430,7 +430,7 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; } else { rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); -- cgit v1.2.3-70-g09d2