diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/rs600.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/rs600.c | 215 |
1 files changed, 152 insertions, 63 deletions
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 670b555d2ca2..88c8e91ea651 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -35,19 +35,26 @@ * close to the one of the R600 family (R600 likely being an evolution * of the RS600 GART block). */ -#include <drm/drmP.h> + +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/pci.h> + +#include <drm/drm_device.h> +#include <drm/drm_vblank.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> + +#include "atom.h" #include "radeon.h" #include "radeon_asic.h" -#include "atom.h" -#include "rs600d.h" - +#include "radeon_audio.h" #include "rs600_reg_safe.h" +#include "rs600d.h" static void rs600_gpu_init(struct radeon_device *rdev); int rs600_mc_wait_for_idle(struct radeon_device *rdev); -static const u32 crtc_offsets[2] = -{ +static const u32 crtc_offsets[2] = { 0, AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL }; @@ -109,21 +116,10 @@ void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc) } } -void rs600_pre_page_flip(struct radeon_device *rdev, int crtc) -{ - /* enable the pflip int */ - radeon_irq_kms_pflip_irq_get(rdev, crtc); -} - -void rs600_post_page_flip(struct radeon_device *rdev, int crtc) -{ - /* disable the pflip int */ - radeon_irq_kms_pflip_irq_put(rdev, crtc); -} - -u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, bool async) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; + struct drm_framebuffer *fb = radeon_crtc->base.primary->fb; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); int i; @@ -131,6 +127,12 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) tmp |= AVIVO_D1GRPH_UPDATE_LOCK; WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); + /* flip at hsync for async, default is vsync */ + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, + async ? AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0); + /* update pitch */ + WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, + fb->pitches[0] / fb->format->cpp[0]); /* update the scanout addresses */ WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, (u32)crtc_base); @@ -148,9 +150,79 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) /* Unlock the lock, so double-buffering can take place inside vblank */ tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK; WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); +} + +bool rs600_page_flip_pending(struct radeon_device *rdev, int crtc_id) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; /* Return current update_pending status: */ - return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING; + return !!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & + AVIVO_D1GRPH_SURFACE_UPDATE_PENDING); +} + +void avivo_program_fmt(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); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + int bpc = 0; + u32 tmp = 0; + enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + bpc = radeon_get_monitor_bpc(connector); + dither = radeon_connector->dither; + } + + /* LVDS FMT is set up by atom */ + if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT) + return; + + if (bpc == 0) + return; + + switch (bpc) { + case 6: + if (dither == RADEON_FMT_DITHER_ENABLE) + /* XXX sort out optimal dither settings */ + tmp |= AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; + else + tmp |= AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN; + break; + case 8: + if (dither == RADEON_FMT_DITHER_ENABLE) + /* XXX sort out optimal dither settings */ + tmp |= (AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN | + AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH); + else + tmp |= (AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN | + AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH); + break; + case 10: + default: + /* not needed */ + break; + } + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + WREG32(AVIVO_TMDSA_BIT_DEPTH_CONTROL, tmp); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, tmp); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + WREG32(AVIVO_DVOA_BIT_DEPTH_CONTROL, tmp); + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + WREG32(AVIVO_DDIA_BIT_DEPTH_CONTROL, tmp); + break; + default: + break; + } } void rs600_pm_misc(struct radeon_device *rdev) @@ -249,7 +321,7 @@ void rs600_pm_misc(struct radeon_device *rdev) void rs600_pm_prepare(struct radeon_device *rdev) { - struct drm_device *ddev = rdev->ddev; + struct drm_device *ddev = rdev_to_drm(rdev); struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; u32 tmp; @@ -267,7 +339,7 @@ void rs600_pm_prepare(struct radeon_device *rdev) void rs600_pm_finish(struct radeon_device *rdev) { - struct drm_device *ddev = rdev->ddev; + struct drm_device *ddev = rdev_to_drm(rdev); struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; u32 tmp; @@ -336,7 +408,7 @@ void rs600_hpd_set_polarity(struct radeon_device *rdev, void rs600_hpd_init(struct radeon_device *rdev) { - struct drm_device *dev = rdev->ddev; + struct drm_device *dev = rdev_to_drm(rdev); struct drm_connector *connector; unsigned enable = 0; @@ -354,7 +426,8 @@ void rs600_hpd_init(struct radeon_device *rdev) default: break; } - enable |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + enable |= 1 << radeon_connector->hpd.hpd; radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } radeon_irq_kms_enable_hpd(rdev, enable); @@ -362,7 +435,7 @@ void rs600_hpd_init(struct radeon_device *rdev) void rs600_hpd_fini(struct radeon_device *rdev) { - struct drm_device *dev = rdev->ddev; + struct drm_device *dev = rdev_to_drm(rdev); struct drm_connector *connector; unsigned disable = 0; @@ -380,12 +453,13 @@ void rs600_hpd_fini(struct radeon_device *rdev) default: break; } - disable |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + disable |= 1 << radeon_connector->hpd.hpd; } radeon_irq_kms_disable_hpd(rdev, disable); } -int rs600_asic_reset(struct radeon_device *rdev) +int rs600_asic_reset(struct radeon_device *rdev, bool hard) { struct rv515_mc_save save; u32 status, tmp; @@ -497,7 +571,6 @@ static int rs600_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* Enable bus master */ tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; WREG32(RADEON_BUS_CNTL, tmp); @@ -568,24 +641,26 @@ static void rs600_gart_fini(struct radeon_device *rdev) radeon_gart_table_vram_free(rdev); } -#define R600_PTE_VALID (1 << 0) -#define R600_PTE_SYSTEM (1 << 1) -#define R600_PTE_SNOOPED (1 << 2) -#define R600_PTE_READABLE (1 << 5) -#define R600_PTE_WRITEABLE (1 << 6) +uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags) +{ + addr = addr & 0xFFFFFFFFFFFFF000ULL; + addr |= R600_PTE_SYSTEM; + if (flags & RADEON_GART_PAGE_VALID) + addr |= R600_PTE_VALID; + if (flags & RADEON_GART_PAGE_READ) + addr |= R600_PTE_READABLE; + if (flags & RADEON_GART_PAGE_WRITE) + addr |= R600_PTE_WRITEABLE; + if (flags & RADEON_GART_PAGE_SNOOP) + addr |= R600_PTE_SNOOPED; + return addr; +} -int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) { void __iomem *ptr = (void *)rdev->gart.ptr; - - if (i < 0 || i > rdev->gart.num_gpu_pages) { - return -EINVAL; - } - addr = addr & 0xFFFFFFFFFFFFF000ULL; - addr |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED; - addr |= R600_PTE_READABLE | R600_PTE_WRITEABLE; - writeq(addr, ptr + (i * 8)); - return 0; + writeq(entry, ptr + (i * 8)); } int rs600_irq_set(struct radeon_device *rdev) @@ -634,6 +709,10 @@ int rs600_irq_set(struct radeon_device *rdev) WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2); if (ASIC_IS_DCE2(rdev)) WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0); + + /* posting read */ + RREG32(R_000040_GEN_INT_CNTL); + return 0; } @@ -718,21 +797,21 @@ int rs600_irq_process(struct radeon_device *rdev) /* Vertical blank interrupts */ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); + drm_handle_vblank(rdev_to_drm(rdev), 0); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_flip(rdev, 0); + radeon_crtc_handle_vblank(rdev, 0); } if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); + drm_handle_vblank(rdev_to_drm(rdev), 1); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_flip(rdev, 1); + radeon_crtc_handle_vblank(rdev, 1); } if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { queue_hotplug = true; @@ -749,7 +828,7 @@ int rs600_irq_process(struct radeon_device *rdev) status = rs600_irq_ack(rdev); } if (queue_hotplug) - schedule_work(&rdev->hotplug_work); + schedule_delayed_work(&rdev->hotplug_work, 0); if (queue_hdmi) schedule_work(&rdev->audio_work); if (rdev->msi_enabled) { @@ -824,6 +903,9 @@ void rs600_bandwidth_update(struct radeon_device *rdev) u32 d1mode_priority_a_cnt, d2mode_priority_a_cnt; /* FIXME: implement full support */ + if (!rdev->mode_info.mode_config_initialized) + return; + radeon_update_display_priority(rdev); if (rdev->mode_info.crtcs[0]->base.enabled) @@ -847,22 +929,26 @@ void rs600_bandwidth_update(struct radeon_device *rdev) uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg) { + unsigned long flags; + u32 r; + + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) | S_000070_MC_IND_CITF_ARB0(1)); - return RREG32(R_000074_MC_IND_DATA); + r = RREG32(R_000074_MC_IND_DATA); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); + return r; } void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { + unsigned long flags; + + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) | S_000070_MC_IND_CITF_ARB0(1) | S_000070_MC_IND_WR_EN(1)); WREG32(R_000074_MC_IND_DATA, v); -} - -static void rs600_debugfs(struct radeon_device *rdev) -{ - if (r100_debugfs_rbbm_init(rdev)) - DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); } void rs600_set_safe_registers(struct radeon_device *rdev) @@ -944,7 +1030,7 @@ static int rs600_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { dev_err(rdev->dev, "failed initializing audio\n"); return r; @@ -984,7 +1070,8 @@ int rs600_resume(struct radeon_device *rdev) int rs600_suspend(struct radeon_device *rdev) { - r600_audio_fini(rdev); + radeon_pm_suspend(rdev); + radeon_audio_fini(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); rs600_irq_disable(rdev); @@ -994,7 +1081,8 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { - r600_audio_fini(rdev); + radeon_pm_fini(rdev); + radeon_audio_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); @@ -1045,14 +1133,12 @@ int rs600_init(struct radeon_device *rdev) return -EINVAL; /* Initialize clocks */ - radeon_get_clock_info(rdev->ddev); + radeon_get_clock_info(rdev_to_drm(rdev)); /* initialize memory controller */ rs600_mc_init(rdev); - rs600_debugfs(rdev); + r100_debugfs_rbbm_init(rdev); /* Fence driver */ - r = radeon_fence_driver_init(rdev); - if (r) - return r; + radeon_fence_driver_init(rdev); /* Memory manager */ r = radeon_bo_init(rdev); if (r) @@ -1062,6 +1148,9 @@ int rs600_init(struct radeon_device *rdev) return r; rs600_set_safe_registers(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = rs600_startup(rdev); if (r) { |
