diff options
| author | Alex Deucher <alexander.deucher@amd.com> | 2012-03-20 17:18:22 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2012-03-21 02:55:54 -0400 |
| commit | 25a857fbe973bdcc7df0df2e0c8f9c6e1ab0e475 (patch) | |
| tree | 48299c76543e234ef10ad746dc9d4e0904f472ad | |
| parent | 347e7592beb0abd56a11ec16ca8aba9f60681f13 (diff) | |
drm/radeon/kms: add support for interrupts on SI
This is mostly identical to evergreen/ni, however
there are some additional fields in the IV vector
for RINGID and VMID.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
| -rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/si.c | 721 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/sid.h | 158 |
3 files changed, 881 insertions, 2 deletions
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 5eb23829353f..924b68718b82 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
| @@ -2778,7 +2778,7 @@ void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size) | |||
| 2778 | rdev->ih.rptr = 0; | 2778 | rdev->ih.rptr = 0; |
| 2779 | } | 2779 | } |
| 2780 | 2780 | ||
| 2781 | static int r600_ih_ring_alloc(struct radeon_device *rdev) | 2781 | int r600_ih_ring_alloc(struct radeon_device *rdev) |
| 2782 | { | 2782 | { |
| 2783 | int r; | 2783 | int r; |
| 2784 | 2784 | ||
| @@ -2814,7 +2814,7 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev) | |||
| 2814 | return 0; | 2814 | return 0; |
| 2815 | } | 2815 | } |
| 2816 | 2816 | ||
| 2817 | static void r600_ih_ring_fini(struct radeon_device *rdev) | 2817 | void r600_ih_ring_fini(struct radeon_device *rdev) |
| 2818 | { | 2818 | { |
| 2819 | int r; | 2819 | int r; |
| 2820 | if (rdev->ih.ring_obj) { | 2820 | if (rdev->ih.ring_obj) { |
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 4252cd0ab64b..6aecbf54cd5d 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c | |||
| @@ -55,6 +55,8 @@ MODULE_FIRMWARE("radeon/VERDE_ce.bin"); | |||
| 55 | MODULE_FIRMWARE("radeon/VERDE_mc.bin"); | 55 | MODULE_FIRMWARE("radeon/VERDE_mc.bin"); |
| 56 | MODULE_FIRMWARE("radeon/VERDE_rlc.bin"); | 56 | MODULE_FIRMWARE("radeon/VERDE_rlc.bin"); |
| 57 | 57 | ||
| 58 | extern int r600_ih_ring_alloc(struct radeon_device *rdev); | ||
| 59 | extern void r600_ih_ring_fini(struct radeon_device *rdev); | ||
| 58 | extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev); | 60 | extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev); |
| 59 | extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save); | 61 | extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save); |
| 60 | extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save); | 62 | extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save); |
| @@ -3072,3 +3074,722 @@ static int si_rlc_resume(struct radeon_device *rdev) | |||
| 3072 | return 0; | 3074 | return 0; |
| 3073 | } | 3075 | } |
| 3074 | 3076 | ||
| 3077 | static void si_enable_interrupts(struct radeon_device *rdev) | ||
| 3078 | { | ||
| 3079 | u32 ih_cntl = RREG32(IH_CNTL); | ||
| 3080 | u32 ih_rb_cntl = RREG32(IH_RB_CNTL); | ||
| 3081 | |||
| 3082 | ih_cntl |= ENABLE_INTR; | ||
| 3083 | ih_rb_cntl |= IH_RB_ENABLE; | ||
| 3084 | WREG32(IH_CNTL, ih_cntl); | ||
| 3085 | WREG32(IH_RB_CNTL, ih_rb_cntl); | ||
| 3086 | rdev->ih.enabled = true; | ||
| 3087 | } | ||
| 3088 | |||
| 3089 | static void si_disable_interrupts(struct radeon_device *rdev) | ||
| 3090 | { | ||
| 3091 | u32 ih_rb_cntl = RREG32(IH_RB_CNTL); | ||
| 3092 | u32 ih_cntl = RREG32(IH_CNTL); | ||
| 3093 | |||
| 3094 | ih_rb_cntl &= ~IH_RB_ENABLE; | ||
| 3095 | ih_cntl &= ~ENABLE_INTR; | ||
| 3096 | WREG32(IH_RB_CNTL, ih_rb_cntl); | ||
| 3097 | WREG32(IH_CNTL, ih_cntl); | ||
| 3098 | /* set rptr, wptr to 0 */ | ||
| 3099 | WREG32(IH_RB_RPTR, 0); | ||
| 3100 | WREG32(IH_RB_WPTR, 0); | ||
| 3101 | rdev->ih.enabled = false; | ||
| 3102 | rdev->ih.wptr = 0; | ||
| 3103 | rdev->ih.rptr = 0; | ||
| 3104 | } | ||
| 3105 | |||
| 3106 | static void si_disable_interrupt_state(struct radeon_device *rdev) | ||
| 3107 | { | ||
| 3108 | u32 tmp; | ||
| 3109 | |||
| 3110 | WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); | ||
| 3111 | WREG32(CP_INT_CNTL_RING1, 0); | ||
| 3112 | WREG32(CP_INT_CNTL_RING2, 0); | ||
| 3113 | WREG32(GRBM_INT_CNTL, 0); | ||
| 3114 | WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); | ||
| 3115 | WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); | ||
| 3116 | if (rdev->num_crtc >= 4) { | ||
| 3117 | WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); | ||
| 3118 | WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); | ||
| 3119 | } | ||
| 3120 | if (rdev->num_crtc >= 6) { | ||
| 3121 | WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); | ||
| 3122 | WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); | ||
| 3123 | } | ||
| 3124 | |||
| 3125 | WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); | ||
| 3126 | WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); | ||
| 3127 | if (rdev->num_crtc >= 4) { | ||
| 3128 | WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); | ||
| 3129 | WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); | ||
| 3130 | } | ||
| 3131 | if (rdev->num_crtc >= 6) { | ||
| 3132 | WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); | ||
| 3133 | WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); | ||
| 3134 | } | ||
| 3135 | |||
| 3136 | WREG32(DACA_AUTODETECT_INT_CONTROL, 0); | ||
| 3137 | |||
| 3138 | tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY; | ||
| 3139 | WREG32(DC_HPD1_INT_CONTROL, tmp); | ||
| 3140 | tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY; | ||
| 3141 | WREG32(DC_HPD2_INT_CONTROL, tmp); | ||
| 3142 | tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY; | ||
| 3143 | WREG32(DC_HPD3_INT_CONTROL, tmp); | ||
| 3144 | tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY; | ||
| 3145 | WREG32(DC_HPD4_INT_CONTROL, tmp); | ||
| 3146 | tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY; | ||
| 3147 | WREG32(DC_HPD5_INT_CONTROL, tmp); | ||
| 3148 | tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY; | ||
| 3149 | WREG32(DC_HPD6_INT_CONTROL, tmp); | ||
| 3150 | |||
| 3151 | } | ||
| 3152 | |||
| 3153 | static int si_irq_init(struct radeon_device *rdev) | ||
| 3154 | { | ||
| 3155 | int ret = 0; | ||
| 3156 | int rb_bufsz; | ||
| 3157 | u32 interrupt_cntl, ih_cntl, ih_rb_cntl; | ||
| 3158 | |||
| 3159 | /* allocate ring */ | ||
| 3160 | ret = r600_ih_ring_alloc(rdev); | ||
| 3161 | if (ret) | ||
| 3162 | return ret; | ||
| 3163 | |||
| 3164 | /* disable irqs */ | ||
| 3165 | si_disable_interrupts(rdev); | ||
| 3166 | |||
| 3167 | /* init rlc */ | ||
| 3168 | ret = si_rlc_resume(rdev); | ||
| 3169 | if (ret) { | ||
| 3170 | r600_ih_ring_fini(rdev); | ||
| 3171 | return ret; | ||
| 3172 | } | ||
| 3173 | |||
| 3174 | /* setup interrupt control */ | ||
| 3175 | /* set dummy read address to ring address */ | ||
| 3176 | WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8); | ||
| 3177 | interrupt_cntl = RREG32(INTERRUPT_CNTL); | ||
| 3178 | /* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi | ||
| 3179 | * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN | ||
| 3180 | */ | ||
| 3181 | interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE; | ||
| 3182 | /* IH_REQ_NONSNOOP_EN=1 if ring is in non-cacheable memory, e.g., vram */ | ||
| 3183 | interrupt_cntl &= ~IH_REQ_NONSNOOP_EN; | ||
| 3184 | WREG32(INTERRUPT_CNTL, interrupt_cntl); | ||
| 3185 | |||
| 3186 | WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8); | ||
| 3187 | rb_bufsz = drm_order(rdev->ih.ring_size / 4); | ||
| 3188 | |||
| 3189 | ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE | | ||
| 3190 | IH_WPTR_OVERFLOW_CLEAR | | ||
| 3191 | (rb_bufsz << 1)); | ||
| 3192 | |||
| 3193 | if (rdev->wb.enabled) | ||
| 3194 | ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE; | ||
| 3195 | |||
| 3196 | /* set the writeback address whether it's enabled or not */ | ||
| 3197 | WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC); | ||
| 3198 | WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF); | ||
| 3199 | |||
| 3200 | WREG32(IH_RB_CNTL, ih_rb_cntl); | ||
| 3201 | |||
| 3202 | /* set rptr, wptr to 0 */ | ||
| 3203 | WREG32(IH_RB_RPTR, 0); | ||
| 3204 | WREG32(IH_RB_WPTR, 0); | ||
| 3205 | |||
| 3206 | /* Default settings for IH_CNTL (disabled at first) */ | ||
| 3207 | ih_cntl = MC_WRREQ_CREDIT(0x10) | MC_WR_CLEAN_CNT(0x10) | MC_VMID(0); | ||
| 3208 | /* RPTR_REARM only works if msi's are enabled */ | ||
| 3209 | if (rdev->msi_enabled) | ||
| 3210 | ih_cntl |= RPTR_REARM; | ||
| 3211 | WREG32(IH_CNTL, ih_cntl); | ||
| 3212 | |||
| 3213 | /* force the active interrupt state to all disabled */ | ||
| 3214 | si_disable_interrupt_state(rdev); | ||
| 3215 | |||
| 3216 | /* enable irqs */ | ||
| 3217 | si_enable_interrupts(rdev); | ||
| 3218 | |||
| 3219 | return ret; | ||
| 3220 | } | ||
| 3221 | |||
| 3222 | int si_irq_set(struct radeon_device *rdev) | ||
| 3223 | { | ||
| 3224 | u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; | ||
| 3225 | u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0; | ||
