diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/dce_v6_0.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 193 |
1 files changed, 144 insertions, 49 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index eb7de9122d99..255c70959343 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -40,18 +40,25 @@ #include "amdgpu_connectors.h" #include "amdgpu_display.h" +#include "dce_v6_0.h" +#include "sid.h" + #include "bif/bif_3_0_d.h" #include "bif/bif_3_0_sh_mask.h" + #include "oss/oss_1_0_d.h" #include "oss/oss_1_0_sh_mask.h" + #include "gca/gfx_6_0_d.h" #include "gca/gfx_6_0_sh_mask.h" +#include "gca/gfx_7_2_enum.h" + #include "gmc/gmc_6_0_d.h" #include "gmc/gmc_6_0_sh_mask.h" + #include "dce/dce_6_0_d.h" #include "dce/dce_6_0_sh_mask.h" -#include "gca/gfx_7_2_enum.h" -#include "dce_v6_0.h" + #include "si_enums.h" static void dce_v6_0_set_display_funcs(struct amdgpu_device *adev); @@ -59,31 +66,31 @@ static void dce_v6_0_set_irq_funcs(struct amdgpu_device *adev); static const u32 crtc_offsets[6] = { - SI_CRTC0_REGISTER_OFFSET, - SI_CRTC1_REGISTER_OFFSET, - SI_CRTC2_REGISTER_OFFSET, - SI_CRTC3_REGISTER_OFFSET, - SI_CRTC4_REGISTER_OFFSET, - SI_CRTC5_REGISTER_OFFSET + CRTC0_REGISTER_OFFSET, + CRTC1_REGISTER_OFFSET, + CRTC2_REGISTER_OFFSET, + CRTC3_REGISTER_OFFSET, + CRTC4_REGISTER_OFFSET, + CRTC5_REGISTER_OFFSET }; static const u32 hpd_offsets[] = { - mmDC_HPD1_INT_STATUS - mmDC_HPD1_INT_STATUS, - mmDC_HPD2_INT_STATUS - mmDC_HPD1_INT_STATUS, - mmDC_HPD3_INT_STATUS - mmDC_HPD1_INT_STATUS, - mmDC_HPD4_INT_STATUS - mmDC_HPD1_INT_STATUS, - mmDC_HPD5_INT_STATUS - mmDC_HPD1_INT_STATUS, - mmDC_HPD6_INT_STATUS - mmDC_HPD1_INT_STATUS, + HPD0_REGISTER_OFFSET, + HPD1_REGISTER_OFFSET, + HPD2_REGISTER_OFFSET, + HPD3_REGISTER_OFFSET, + HPD4_REGISTER_OFFSET, + HPD5_REGISTER_OFFSET }; static const uint32_t dig_offsets[] = { - SI_CRTC0_REGISTER_OFFSET, - SI_CRTC1_REGISTER_OFFSET, - SI_CRTC2_REGISTER_OFFSET, - SI_CRTC3_REGISTER_OFFSET, - SI_CRTC4_REGISTER_OFFSET, - SI_CRTC5_REGISTER_OFFSET, + CRTC0_REGISTER_OFFSET, + CRTC1_REGISTER_OFFSET, + CRTC2_REGISTER_OFFSET, + CRTC3_REGISTER_OFFSET, + CRTC4_REGISTER_OFFSET, + CRTC5_REGISTER_OFFSET, (0x13830 - 0x7030) >> 2, }; @@ -206,9 +213,9 @@ static void dce_v6_0_page_flip(struct amdgpu_device *adev, /* update the scanout addresses */ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, upper_32_bits(crtc_base)); + /* writing to the low address triggers the update */ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset, (u32)crtc_base); - /* post the write */ RREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset); } @@ -218,11 +225,11 @@ static int dce_v6_0_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, { if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc)) return -EINVAL; + *vbl = RREG32(mmCRTC_V_BLANK_START_END + crtc_offsets[crtc]); *position = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); return 0; - } /** @@ -242,7 +249,8 @@ static bool dce_v6_0_hpd_sense(struct amdgpu_device *adev, if (hpd >= adev->mode_info.num_hpd) return connected; - if (RREG32(mmDC_HPD1_INT_STATUS + hpd_offsets[hpd]) & DC_HPD1_INT_STATUS__DC_HPD1_SENSE_MASK) + if (RREG32(mmDC_HPD1_INT_STATUS + hpd_offsets[hpd]) & + DC_HPD1_INT_STATUS__DC_HPD1_SENSE_MASK) connected = true; return connected; @@ -370,13 +378,41 @@ static u32 dce_v6_0_hpd_get_gpio_reg(struct amdgpu_device *adev) return mmDC_GPIO_HPD_A; } +static bool dce_v6_0_is_display_hung(struct amdgpu_device *adev) +{ + u32 crtc_hung = 0; + u32 crtc_status[6]; + u32 i, j, tmp; + + for (i = 0; i < adev->mode_info.num_crtc; i++) { + if (RREG32(mmCRTC_CONTROL + crtc_offsets[i]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK) { + crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]); + crtc_hung |= (1 << i); + } + } + + for (j = 0; j < 10; j++) { + for (i = 0; i < adev->mode_info.num_crtc; i++) { + if (crtc_hung & (1 << i)) { + tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]); + if (tmp != crtc_status[i]) + crtc_hung &= ~(1 << i); + } + } + if (crtc_hung == 0) + return false; + udelay(100); + } + + return true; +} + static void dce_v6_0_set_vga_render_state(struct amdgpu_device *adev, bool render) { if (!render) WREG32(mmVGA_RENDER_CONTROL, RREG32(mmVGA_RENDER_CONTROL) & VGA_VSTATUS_CNTL); - } static int dce_v6_0_get_num_crtc(struct amdgpu_device *adev) @@ -419,7 +455,6 @@ void dce_v6_0_disable_dce(struct amdgpu_device *adev) static void dce_v6_0_program_fmt(struct drm_encoder *encoder) { - struct drm_device *dev = encoder->dev; struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); @@ -895,8 +930,8 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev, wm_high.dram_channels = dram_channels; wm_high.num_heads = num_heads; - if (adev->pm.dpm_enabled) { /* watermark for low clocks */ + if (adev->pm.dpm_enabled) { wm_low.yclk = amdgpu_dpm_get_mclk(adev, true) * 10; wm_low.sclk = @@ -1006,6 +1041,20 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev, } /* watermark setup */ +/** + * dce_v6_0_line_buffer_adjust - Set up the line buffer + * + * @adev: amdgpu_device pointer + * @amdgpu_crtc: the selected display controller + * @mode: the current display mode on the selected display + * controller + * @other_mode: the display mode of another display controller + * that may be sharing the line buffer + * + * Setup up the line buffer allocation for + * the selected display controller (CIK). + * Returns the line buffer size in pixels. + */ static u32 dce_v6_0_line_buffer_adjust(struct amdgpu_device *adev, struct amdgpu_crtc *amdgpu_crtc, struct drm_display_mode *mode, @@ -1347,13 +1396,13 @@ static void dce_v6_0_audio_enable(struct amdgpu_device *adev, static const u32 pin_offsets[7] = { - (0x1780 - 0x1780), - (0x1786 - 0x1780), - (0x178c - 0x1780), - (0x1792 - 0x1780), - (0x1798 - 0x1780), - (0x179d - 0x1780), - (0x17a4 - 0x1780), + AUD0_REGISTER_OFFSET, + AUD1_REGISTER_OFFSET, + AUD2_REGISTER_OFFSET, + AUD3_REGISTER_OFFSET, + AUD4_REGISTER_OFFSET, + AUD5_REGISTER_OFFSET, + AUD6_REGISTER_OFFSET, }; static int dce_v6_0_audio_init(struct amdgpu_device *adev) @@ -1386,6 +1435,8 @@ static int dce_v6_0_audio_init(struct amdgpu_device *adev) adev->mode_info.audio.pin[i].connected = false; adev->mode_info.audio.pin[i].offset = pin_offsets[i]; adev->mode_info.audio.pin[i].id = i; + /* disable audio. it will be set up later */ + /* XXX remove once we switch to ip funcs */ dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false); } @@ -2602,6 +2653,32 @@ static const struct drm_crtc_helper_funcs dce_v6_0_crtc_helper_funcs = { .get_scanout_position = amdgpu_crtc_get_scanout_position, }; +static void dce_v6_0_panic_flush(struct drm_plane *plane) +{ + struct drm_framebuffer *fb; + struct amdgpu_crtc *amdgpu_crtc; + struct amdgpu_device *adev; + uint32_t fb_format; + + if (!plane->fb) + return; + + fb = plane->fb; + amdgpu_crtc = to_amdgpu_crtc(plane->crtc); + adev = drm_to_adev(fb->dev); + + /* Disable DC tiling */ + fb_format = RREG32(mmGRPH_CONTROL + amdgpu_crtc->crtc_offset); + fb_format &= ~GRPH_ARRAY_MODE(0x7); + WREG32(mmGRPH_CONTROL + amdgpu_crtc->crtc_offset, fb_format); + +} + +static const struct drm_plane_helper_funcs dce_v6_0_drm_primary_plane_helper_funcs = { + .get_scanout_buffer = amdgpu_display_get_scanout_buffer, + .panic_flush = dce_v6_0_panic_flush, +}; + static int dce_v6_0_crtc_init(struct amdgpu_device *adev, int index) { struct amdgpu_crtc *amdgpu_crtc; @@ -2629,6 +2706,7 @@ static int dce_v6_0_crtc_init(struct amdgpu_device *adev, int index) amdgpu_crtc->encoder = NULL; amdgpu_crtc->connector = NULL; drm_crtc_helper_add(&amdgpu_crtc->base, &dce_v6_0_crtc_helper_funcs); + drm_plane_helper_add(amdgpu_crtc->base.primary, &dce_v6_0_drm_primary_plane_helper_funcs); return 0; } @@ -2838,14 +2916,35 @@ static int dce_v6_0_resume(struct amdgpu_ip_block *ip_block) return amdgpu_display_resume_helper(adev); } -static bool dce_v6_0_is_idle(void *handle) +static bool dce_v6_0_is_idle(struct amdgpu_ip_block *ip_block) { return true; } static int dce_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) { - DRM_INFO("xxxx: dce_v6_0_soft_reset --- no impl!!\n"); + u32 srbm_soft_reset = 0, tmp; + struct amdgpu_device *adev = ip_block->adev; + + if (dce_v6_0_is_display_hung(adev)) + srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; + + if (srbm_soft_reset) { + tmp = RREG32(mmSRBM_SOFT_RESET); + tmp |= srbm_soft_reset; + dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); + WREG32(mmSRBM_SOFT_RESET, tmp); + tmp = RREG32(mmSRBM_SOFT_RESET); + + udelay(50); + + tmp &= ~srbm_soft_reset; + WREG32(mmSRBM_SOFT_RESET, tmp); + tmp = RREG32(mmSRBM_SOFT_RESET); + + /* Wait a little for things to settle down */ + udelay(50); + } return 0; } @@ -2862,22 +2961,22 @@ static void dce_v6_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, switch (crtc) { case 0: - reg_block = SI_CRTC0_REGISTER_OFFSET; + reg_block = CRTC0_REGISTER_OFFSET; break; case 1: - reg_block = SI_CRTC1_REGISTER_OFFSET; + reg_block = CRTC1_REGISTER_OFFSET; break; case 2: - reg_block = SI_CRTC2_REGISTER_OFFSET; + reg_block = CRTC2_REGISTER_OFFSET; break; case 3: - reg_block = SI_CRTC3_REGISTER_OFFSET; + reg_block = CRTC3_REGISTER_OFFSET; break; case 4: - reg_block = SI_CRTC4_REGISTER_OFFSET; + reg_block = CRTC4_REGISTER_OFFSET; break; case 5: - reg_block = SI_CRTC5_REGISTER_OFFSET; + reg_block = CRTC5_REGISTER_OFFSET; break; default: DRM_DEBUG("invalid crtc %d\n", crtc); @@ -3121,16 +3220,15 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev, } return 0; - } -static int dce_v6_0_set_clockgating_state(void *handle, +static int dce_v6_0_set_clockgating_state(struct amdgpu_ip_block *ip_block, enum amd_clockgating_state state) { return 0; } -static int dce_v6_0_set_powergating_state(void *handle, +static int dce_v6_0_set_powergating_state(struct amdgpu_ip_block *ip_block, enum amd_powergating_state state) { return 0; @@ -3254,8 +3352,7 @@ static void dce_v6_0_ext_commit(struct drm_encoder *encoder) } -static void -dce_v6_0_ext_mode_set(struct drm_encoder *encoder, +static void dce_v6_0_ext_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { @@ -3267,8 +3364,7 @@ static void dce_v6_0_ext_disable(struct drm_encoder *encoder) } -static void -dce_v6_0_ext_dpms(struct drm_encoder *encoder, int mode) +static void dce_v6_0_ext_dpms(struct drm_encoder *encoder, int mode) { } @@ -3339,7 +3435,6 @@ static void dce_v6_0_encoder_add(struct amdgpu_device *adev, amdgpu_encoder->devices |= supported_device; return; } - } /* add a new one */ |