Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f122c610 authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie
Browse files

drm/radeon/kms: fix up audio interrupt handling



- add support for rs6xx
- add support for DCE4/5
- fixup 6xx/7xx

Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 3a2a67aa
Loading
Loading
Loading
Loading
+128 −0
Original line number Original line Diff line number Diff line
@@ -2594,6 +2594,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
	u32 grbm_int_cntl = 0;
	u32 grbm_int_cntl = 0;
	u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
	u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
	u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;


	if (!rdev->irq.installed) {
	if (!rdev->irq.installed) {
		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -2614,6 +2615,13 @@ int evergreen_irq_set(struct radeon_device *rdev)
	hpd5 = RREG32(DC_HPD5_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;
	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;


	afmt1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
	afmt2 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
	afmt3 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
	afmt4 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
	afmt5 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
	afmt6 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;

	if (rdev->family >= CHIP_CAYMAN) {
	if (rdev->family >= CHIP_CAYMAN) {
		/* enable CP interrupts on all rings */
		/* enable CP interrupts on all rings */
		if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
		if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
@@ -2690,6 +2698,30 @@ int evergreen_irq_set(struct radeon_device *rdev)
		DRM_DEBUG("evergreen_irq_set: hpd 6\n");
		DRM_DEBUG("evergreen_irq_set: hpd 6\n");
		hpd6 |= DC_HPDx_INT_EN;
		hpd6 |= DC_HPDx_INT_EN;
	}
	}
	if (rdev->irq.afmt[0]) {
		DRM_DEBUG("evergreen_irq_set: hdmi 0\n");
		afmt1 |= AFMT_AZ_FORMAT_WTRIG_MASK;
	}
	if (rdev->irq.afmt[1]) {
		DRM_DEBUG("evergreen_irq_set: hdmi 1\n");
		afmt2 |= AFMT_AZ_FORMAT_WTRIG_MASK;
	}
	if (rdev->irq.afmt[2]) {
		DRM_DEBUG("evergreen_irq_set: hdmi 2\n");
		afmt3 |= AFMT_AZ_FORMAT_WTRIG_MASK;
	}
	if (rdev->irq.afmt[3]) {
		DRM_DEBUG("evergreen_irq_set: hdmi 3\n");
		afmt4 |= AFMT_AZ_FORMAT_WTRIG_MASK;
	}
	if (rdev->irq.afmt[4]) {
		DRM_DEBUG("evergreen_irq_set: hdmi 4\n");
		afmt5 |= AFMT_AZ_FORMAT_WTRIG_MASK;
	}
	if (rdev->irq.afmt[5]) {
		DRM_DEBUG("evergreen_irq_set: hdmi 5\n");
		afmt6 |= AFMT_AZ_FORMAT_WTRIG_MASK;
	}
	if (rdev->irq.gui_idle) {
	if (rdev->irq.gui_idle) {
		DRM_DEBUG("gui idle\n");
		DRM_DEBUG("gui idle\n");
		grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
		grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
@@ -2732,6 +2764,13 @@ int evergreen_irq_set(struct radeon_device *rdev)
	WREG32(DC_HPD5_INT_CONTROL, hpd5);
	WREG32(DC_HPD5_INT_CONTROL, hpd5);
	WREG32(DC_HPD6_INT_CONTROL, hpd6);
	WREG32(DC_HPD6_INT_CONTROL, hpd6);


	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, afmt1);
	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, afmt2);
	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, afmt3);
	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, afmt4);
	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, afmt5);
	WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, afmt6);

	return 0;
	return 0;
}
}


@@ -2756,6 +2795,13 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
		rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
		rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
	}
	}


	rdev->irq.stat_regs.evergreen.afmt_status1 = RREG32(AFMT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET);
	rdev->irq.stat_regs.evergreen.afmt_status2 = RREG32(AFMT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET);
	rdev->irq.stat_regs.evergreen.afmt_status3 = RREG32(AFMT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET);
	rdev->irq.stat_regs.evergreen.afmt_status4 = RREG32(AFMT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET);
	rdev->irq.stat_regs.evergreen.afmt_status5 = RREG32(AFMT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET);
	rdev->irq.stat_regs.evergreen.afmt_status6 = RREG32(AFMT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);

	if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED)
	if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED)
		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
	if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
	if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
@@ -2829,6 +2875,36 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
		tmp |= DC_HPDx_INT_ACK;
		tmp |= DC_HPDx_INT_ACK;
		WREG32(DC_HPD6_INT_CONTROL, tmp);
		WREG32(DC_HPD6_INT_CONTROL, tmp);
	}
	}
	if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
		tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
		tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
		WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, tmp);
	}
	if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) {
		tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
		tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
		WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, tmp);
	}
	if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) {
		tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
		tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
		WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, tmp);
	}
	if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) {
		tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
		tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
		WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, tmp);
	}
	if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) {
		tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
		tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
		WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, tmp);
	}
	if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) {
		tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
		tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
		WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, tmp);
	}
}
}


void evergreen_irq_disable(struct radeon_device *rdev)
void evergreen_irq_disable(struct radeon_device *rdev)
@@ -2878,6 +2954,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
	u32 ring_index;
	u32 ring_index;
	unsigned long flags;
	unsigned long flags;
	bool queue_hotplug = false;
	bool queue_hotplug = false;
	bool queue_hdmi = false;


	if (!rdev->ih.enabled || rdev->shutdown)
	if (!rdev->ih.enabled || rdev->shutdown)
		return IRQ_NONE;
		return IRQ_NONE;
@@ -3111,6 +3188,55 @@ int evergreen_irq_process(struct radeon_device *rdev)
				break;
				break;
			}
			}
			break;
			break;
		case 44: /* hdmi */
			switch (src_data) {
			case 0:
				if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
					rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG;
					queue_hdmi = true;
					DRM_DEBUG("IH: HDMI0\n");
				}
				break;
			case 1:
				if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) {
					rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG;
					queue_hdmi = true;
					DRM_DEBUG("IH: HDMI1\n");
				}
				break;
			case 2:
				if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) {
					rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG;
					queue_hdmi = true;
					DRM_DEBUG("IH: HDMI2\n");
				}
				break;
			case 3:
				if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) {
					rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG;
					queue_hdmi = true;
					DRM_DEBUG("IH: HDMI3\n");
				}
				break;
			case 4:
				if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) {
					rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG;
					queue_hdmi = true;
					DRM_DEBUG("IH: HDMI4\n");
				}
				break;
			case 5:
				if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) {
					rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG;
					queue_hdmi = true;
					DRM_DEBUG("IH: HDMI5\n");
				}
				break;
			default:
				DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
				break;
			}
			break;
		case 176: /* CP_INT in ring buffer */
		case 176: /* CP_INT in ring buffer */
		case 177: /* CP_INT in IB1 */
		case 177: /* CP_INT in IB1 */
		case 178: /* CP_INT in IB2 */
		case 178: /* CP_INT in IB2 */
@@ -3154,6 +3280,8 @@ int evergreen_irq_process(struct radeon_device *rdev)
		goto restart_ih;
		goto restart_ih;
	if (queue_hotplug)
	if (queue_hotplug)
		schedule_work(&rdev->hotplug_work);
		schedule_work(&rdev->hotplug_work);
	if (queue_hdmi)
		schedule_work(&rdev->audio_work);
	rdev->ih.rptr = rptr;
	rdev->ih.rptr = rptr;
	WREG32(IH_RB_RPTR, rdev->ih.rptr);
	WREG32(IH_RB_RPTR, rdev->ih.rptr);
	spin_unlock_irqrestore(&rdev->ih.lock, flags);
	spin_unlock_irqrestore(&rdev->ih.lock, flags);
+90 −25
Original line number Original line Diff line number Diff line
@@ -2968,6 +2968,15 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev)
			WREG32(DC_HPD5_INT_CONTROL, tmp);
			WREG32(DC_HPD5_INT_CONTROL, tmp);
			tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
			tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
			WREG32(DC_HPD6_INT_CONTROL, tmp);
			WREG32(DC_HPD6_INT_CONTROL, tmp);
			tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET0) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
			WREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET0, tmp);
			tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET1) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
			WREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET1, tmp);
		} else {
			tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
			WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
			tmp = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
			WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, tmp);
		}
		}
	} else {
	} else {
		WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
		WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
@@ -2978,6 +2987,10 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev)
		WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
		WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
		tmp = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY;
		tmp = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY;
		WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp);
		WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp);
		tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
		WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
		tmp = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
		WREG32(HDMI1_AUDIO_PACKET_CONTROL, tmp);
	}
	}
}
}


@@ -3074,7 +3087,7 @@ int r600_irq_set(struct radeon_device *rdev)
	u32 mode_int = 0;
	u32 mode_int = 0;
	u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;
	u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;
	u32 grbm_int_cntl = 0;
	u32 grbm_int_cntl = 0;
	u32 hdmi1, hdmi2;
	u32 hdmi0, hdmi1;
	u32 d1grph = 0, d2grph = 0;
	u32 d1grph = 0, d2grph = 0;


	if (!rdev->irq.installed) {
	if (!rdev->irq.installed) {
@@ -3089,9 +3102,7 @@ int r600_irq_set(struct radeon_device *rdev)
		return 0;
		return 0;
	}
	}


	hdmi1 = RREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN;
	if (ASIC_IS_DCE3(rdev)) {
	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;
		hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
		hpd2 = RREG32(DC_HPD2_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;
		hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
@@ -3099,12 +3110,18 @@ int r600_irq_set(struct radeon_device *rdev)
		if (ASIC_IS_DCE32(rdev)) {
		if (ASIC_IS_DCE32(rdev)) {
			hpd5 = RREG32(DC_HPD5_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;
			hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
			hdmi0 = RREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET0) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
			hdmi1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET1) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
		} else {
			hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
			hdmi1 = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
		}
		}
	} else {
	} 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;
		hpd1 = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL) & ~DC_HPDx_INT_EN;
		hpd2 = RREG32(DC_HOT_PLUG_DETECT2_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;
		hpd3 = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & ~DC_HPDx_INT_EN;
		hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
		hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
	}
	}


	if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
	if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
@@ -3146,13 +3163,13 @@ int r600_irq_set(struct radeon_device *rdev)
		DRM_DEBUG("r600_irq_set: hpd 6\n");
		DRM_DEBUG("r600_irq_set: hpd 6\n");
		hpd6 |= DC_HPDx_INT_EN;
		hpd6 |= DC_HPDx_INT_EN;
	}
	}
	if (rdev->irq.hdmi[0]) {
	if (rdev->irq.afmt[0]) {
		DRM_DEBUG("r600_irq_set: hdmi 1\n");
		DRM_DEBUG("r600_irq_set: hdmi 0\n");
		hdmi1 |= R600_HDMI_INT_EN;
		hdmi0 |= HDMI0_AZ_FORMAT_WTRIG_MASK;
	}
	}
	if (rdev->irq.hdmi[1]) {
	if (rdev->irq.afmt[1]) {
		DRM_DEBUG("r600_irq_set: hdmi 2\n");
		DRM_DEBUG("r600_irq_set: hdmi 0\n");
		hdmi2 |= R600_HDMI_INT_EN;
		hdmi1 |= HDMI0_AZ_FORMAT_WTRIG_MASK;
	}
	}
	if (rdev->irq.gui_idle) {
	if (rdev->irq.gui_idle) {
		DRM_DEBUG("gui idle\n");
		DRM_DEBUG("gui idle\n");
@@ -3164,9 +3181,7 @@ int r600_irq_set(struct radeon_device *rdev)
	WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph);
	WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph);
	WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph);
	WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph);
	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
	WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1);
	if (ASIC_IS_DCE3(rdev)) {
	if (ASIC_IS_DCE3(rdev)) {
		WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2);
		WREG32(DC_HPD1_INT_CONTROL, hpd1);
		WREG32(DC_HPD1_INT_CONTROL, hpd1);
		WREG32(DC_HPD2_INT_CONTROL, hpd2);
		WREG32(DC_HPD2_INT_CONTROL, hpd2);
		WREG32(DC_HPD3_INT_CONTROL, hpd3);
		WREG32(DC_HPD3_INT_CONTROL, hpd3);
@@ -3174,12 +3189,18 @@ int r600_irq_set(struct radeon_device *rdev)
		if (ASIC_IS_DCE32(rdev)) {
		if (ASIC_IS_DCE32(rdev)) {
			WREG32(DC_HPD5_INT_CONTROL, hpd5);
			WREG32(DC_HPD5_INT_CONTROL, hpd5);
			WREG32(DC_HPD6_INT_CONTROL, hpd6);
			WREG32(DC_HPD6_INT_CONTROL, hpd6);
			WREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET0, hdmi0);
			WREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET1, hdmi1);
		} else {
			WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
			WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
		}
		}
	} else {
	} else {
		WREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, hdmi2);
		WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
		WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
		WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
		WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
		WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, hpd3);
		WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, hpd3);
		WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
		WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
	}
	}


	return 0;
	return 0;
@@ -3193,10 +3214,19 @@ static void r600_irq_ack(struct radeon_device *rdev)
		rdev->irq.stat_regs.r600.disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
		rdev->irq.stat_regs.r600.disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
		rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE);
		rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE);
		rdev->irq.stat_regs.r600.disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2);
		rdev->irq.stat_regs.r600.disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2);
		if (ASIC_IS_DCE32(rdev)) {
			rdev->irq.stat_regs.r600.hdmi0_status = RREG32(AFMT_STATUS + HDMI_OFFSET0);
			rdev->irq.stat_regs.r600.hdmi1_status = RREG32(AFMT_STATUS + HDMI_OFFSET1);
		} else {
			rdev->irq.stat_regs.r600.hdmi0_status = RREG32(HDMI0_STATUS);
			rdev->irq.stat_regs.r600.hdmi1_status = RREG32(DCE3_HDMI1_STATUS);
		}
	} else {
	} else {
		rdev->irq.stat_regs.r600.disp_int = RREG32(DISP_INTERRUPT_STATUS);
		rdev->irq.stat_regs.r600.disp_int = RREG32(DISP_INTERRUPT_STATUS);
		rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
		rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
		rdev->irq.stat_regs.r600.disp_int_cont2 = 0;
		rdev->irq.stat_regs.r600.disp_int_cont2 = 0;
		rdev->irq.stat_regs.r600.hdmi0_status = RREG32(HDMI0_STATUS);
		rdev->irq.stat_regs.r600.hdmi1_status = RREG32(HDMI1_STATUS);
	}
	}
	rdev->irq.stat_regs.r600.d1grph_int = RREG32(D1GRPH_INTERRUPT_STATUS);
	rdev->irq.stat_regs.r600.d1grph_int = RREG32(D1GRPH_INTERRUPT_STATUS);
	rdev->irq.stat_regs.r600.d2grph_int = RREG32(D2GRPH_INTERRUPT_STATUS);
	rdev->irq.stat_regs.r600.d2grph_int = RREG32(D2GRPH_INTERRUPT_STATUS);
@@ -3262,17 +3292,32 @@ static void r600_irq_ack(struct radeon_device *rdev)
			tmp |= DC_HPDx_INT_ACK;
			tmp |= DC_HPDx_INT_ACK;
			WREG32(DC_HPD6_INT_CONTROL, tmp);
			WREG32(DC_HPD6_INT_CONTROL, tmp);
		}
		}
		if (rdev->irq.stat_regs.r600.hdmi0_status & AFMT_AZ_FORMAT_WTRIG) {
			tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET0);
			tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
			WREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET0, tmp);
		}
		}
	if (RREG32(R600_HDMI_BLOCK1 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
		if (rdev->irq.stat_regs.r600.hdmi1_status & AFMT_AZ_FORMAT_WTRIG) {
		WREG32_P(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
			tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET1);
			tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
			WREG32(AFMT_AUDIO_PACKET_CONTROL + HDMI_OFFSET1, tmp);
		}
		}
	if (ASIC_IS_DCE3(rdev)) {
	} else {
		if (RREG32(R600_HDMI_BLOCK3 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
		if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) {
			WREG32_P(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
			tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL);
			tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
			WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
		}
		}
		if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) {
			if (ASIC_IS_DCE3(rdev)) {
				tmp = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL);
				tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
				WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, tmp);
			} else {
			} else {
		if (RREG32(R600_HDMI_BLOCK2 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
				tmp = RREG32(HDMI1_AUDIO_PACKET_CONTROL);
			WREG32_P(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
				tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
				WREG32(HDMI1_AUDIO_PACKET_CONTROL, tmp);
			}
		}
		}
	}
	}
}
}
@@ -3348,6 +3393,7 @@ int r600_irq_process(struct radeon_device *rdev)
	u32 ring_index;
	u32 ring_index;
	unsigned long flags;
	unsigned long flags;
	bool queue_hotplug = false;
	bool queue_hotplug = false;
	bool queue_hdmi = false;


	if (!rdev->ih.enabled || rdev->shutdown)
	if (!rdev->ih.enabled || rdev->shutdown)
		return IRQ_NONE;
		return IRQ_NONE;
@@ -3483,9 +3529,26 @@ int r600_irq_process(struct radeon_device *rdev)
				break;
				break;
			}
			}
			break;
			break;
		case 21: /* HDMI */
		case 21: /* hdmi */
			DRM_DEBUG("IH: HDMI: 0x%x\n", src_data);
			switch (src_data) {
			r600_audio_schedule_polling(rdev);
			case 4:
				if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) {
					rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG;
					queue_hdmi = true;
					DRM_DEBUG("IH: HDMI0\n");
				}
				break;
			case 5:
				if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) {
					rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG;
					queue_hdmi = true;
					DRM_DEBUG("IH: HDMI1\n");
				}
				break;
			default:
				DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
				break;
			}
			break;
			break;
		case 176: /* CP_INT in ring buffer */
		case 176: /* CP_INT in ring buffer */
		case 177: /* CP_INT in IB1 */
		case 177: /* CP_INT in IB1 */
@@ -3517,6 +3580,8 @@ int r600_irq_process(struct radeon_device *rdev)
		goto restart_ih;
		goto restart_ih;
	if (queue_hotplug)
	if (queue_hotplug)
		schedule_work(&rdev->hotplug_work);
		schedule_work(&rdev->hotplug_work);
	if (queue_hdmi)
		schedule_work(&rdev->audio_work);
	rdev->ih.rptr = rptr;
	rdev->ih.rptr = rptr;
	WREG32(IH_RB_RPTR, rdev->ih.rptr);
	WREG32(IH_RB_RPTR, rdev->ih.rptr);
	spin_unlock_irqrestore(&rdev->ih.lock, flags);
	spin_unlock_irqrestore(&rdev->ih.lock, flags);
+5 −58
Original line number Original line Diff line number Diff line
@@ -29,8 +29,6 @@
#include "radeon_asic.h"
#include "radeon_asic.h"
#include "atom.h"
#include "atom.h"


#define AUDIO_TIMER_INTERVALL 100 /* 1/10 sekund should be enough */

/*
/*
 * check if the chipset is supported
 * check if the chipset is supported
 */
 */
@@ -105,21 +103,13 @@ uint8_t r600_audio_category_code(struct radeon_device *rdev)
	return (RREG32(R600_AUDIO_STATUS_BITS) >> 8) & 0xff;
	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
 * update all hdmi interfaces with current audio parameters
 */
 */
static void r600_audio_update_hdmi(unsigned long param)
void r600_audio_update_hdmi(struct work_struct *work)
{
{
	struct radeon_device *rdev = (struct radeon_device *)param;
	struct radeon_device *rdev = container_of(work, struct radeon_device,
						  audio_work);
	struct drm_device *dev = rdev->ddev;
	struct drm_device *dev = rdev->ddev;


	int channels = r600_audio_channels(rdev);
	int channels = r600_audio_channels(rdev);
@@ -127,9 +117,8 @@ static void r600_audio_update_hdmi(unsigned long param)
	int bps = r600_audio_bits_per_sample(rdev);
	int bps = r600_audio_bits_per_sample(rdev);
	uint8_t status_bits = r600_audio_status_bits(rdev);
	uint8_t status_bits = r600_audio_status_bits(rdev);
	uint8_t category_code = r600_audio_category_code(rdev);
	uint8_t category_code = r600_audio_category_code(rdev);

	struct drm_encoder *encoder;
	struct drm_encoder *encoder;
	int changes = 0, still_going = 0;
	int changes = 0;


	changes |= channels != rdev->audio_channels;
	changes |= channels != rdev->audio_channels;
	changes |= rate != rdev->audio_rate;
	changes |= rate != rdev->audio_rate;
@@ -146,14 +135,9 @@ static void r600_audio_update_hdmi(unsigned long param)
	}
	}


	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
		still_going |= radeon_encoder->audio_polling_active;
		if (changes || r600_hdmi_buffer_status_changed(encoder))
		if (changes || r600_hdmi_buffer_status_changed(encoder))
			r600_hdmi_update_audio_settings(encoder);
			r600_hdmi_update_audio_settings(encoder);
	}
	}

	if (still_going)
		r600_audio_schedule_polling(rdev);
}
}


/*
/*
@@ -177,7 +161,7 @@ static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
}
}


/*
/*
 * initialize the audio vars and register the update timer
 * initialize the audio vars
 */
 */
int r600_audio_init(struct radeon_device *rdev)
int r600_audio_init(struct radeon_device *rdev)
{
{
@@ -192,44 +176,9 @@ int r600_audio_init(struct radeon_device *rdev)
	rdev->audio_status_bits = 0;
	rdev->audio_status_bits = 0;
	rdev->audio_category_code = 0;
	rdev->audio_category_code = 0;


	setup_timer(
		&rdev->audio_timer,
		r600_audio_update_hdmi,
		(unsigned long)rdev);

	return 0;
	return 0;
}
}


/*
 * enable the polling timer, to check for status changes
 */
void r600_audio_enable_polling(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);

	DRM_DEBUG("r600_audio_enable_polling: %d\n",
		radeon_encoder->audio_polling_active);
	if (radeon_encoder->audio_polling_active)
		return;

	radeon_encoder->audio_polling_active = 1;
	if (rdev->audio_enabled)
		mod_timer(&rdev->audio_timer, jiffies + 1);
}

/*
 * disable the polling timer, so we get no more status updates
 */
void r600_audio_disable_polling(struct drm_encoder *encoder)
{
	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
	DRM_DEBUG("r600_audio_disable_polling: %d\n",
		radeon_encoder->audio_polling_active);
	radeon_encoder->audio_polling_active = 0;
}

/*
/*
 * atach the audio codec to the clock source of the encoder
 * atach the audio codec to the clock source of the encoder
 */
 */
@@ -297,7 +246,5 @@ void r600_audio_fini(struct radeon_device *rdev)
	if (!rdev->audio_enabled)
	if (!rdev->audio_enabled)
		return;
		return;


	del_timer(&rdev->audio_timer);

	r600_audio_engine_enable(rdev, false);
	r600_audio_engine_enable(rdev, false);
}
}
+3 −14
Original line number Original line Diff line number Diff line
@@ -548,19 +548,10 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
		}
		}
	}
	}


	if (rdev->irq.installed
	if (rdev->irq.installed) {
	    && rdev->family != CHIP_RS600
	    && rdev->family != CHIP_RS690
	    && rdev->family != CHIP_RS740
	    && !ASIC_IS_DCE4(rdev)) {
		/* if irq is available use it */
		/* if irq is available use it */
		rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true;
		rdev->irq.afmt[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true;
		radeon_irq_set(rdev);
		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",
	DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n",
@@ -590,11 +581,9 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
		offset, radeon_encoder->encoder_id);
		offset, radeon_encoder->encoder_id);


	/* disable irq */
	/* disable irq */
	rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = false;
	rdev->irq.afmt[offset == R600_HDMI_BLOCK1 ? 0 : 1] = false;
	radeon_irq_set(rdev);
	radeon_irq_set(rdev);


	/* disable polling */
	r600_audio_disable_polling(encoder);


	if (ASIC_IS_DCE5(rdev)) {
	if (ASIC_IS_DCE5(rdev)) {
		/* TODO */
		/* TODO */
+14 −3
Original line number Original line Diff line number Diff line
@@ -560,6 +560,7 @@ struct radeon_unpin_work {


struct r500_irq_stat_regs {
struct r500_irq_stat_regs {
	u32 disp_int;
	u32 disp_int;
	u32 hdmi0_status;
};
};


struct r600_irq_stat_regs {
struct r600_irq_stat_regs {
@@ -568,6 +569,8 @@ struct r600_irq_stat_regs {
	u32 disp_int_cont2;
	u32 disp_int_cont2;
	u32 d1grph_int;
	u32 d1grph_int;
	u32 d2grph_int;
	u32 d2grph_int;
	u32 hdmi0_status;
	u32 hdmi1_status;
};
};


struct evergreen_irq_stat_regs {
struct evergreen_irq_stat_regs {
@@ -583,6 +586,12 @@ struct evergreen_irq_stat_regs {
	u32 d4grph_int;
	u32 d4grph_int;
	u32 d5grph_int;
	u32 d5grph_int;
	u32 d6grph_int;
	u32 d6grph_int;
	u32 afmt_status1;
	u32 afmt_status2;
	u32 afmt_status3;
	u32 afmt_status4;
	u32 afmt_status5;
	u32 afmt_status6;
};
};


union radeon_irq_stat_regs {
union radeon_irq_stat_regs {
@@ -593,7 +602,7 @@ union radeon_irq_stat_regs {


#define RADEON_MAX_HPD_PINS 6
#define RADEON_MAX_HPD_PINS 6
#define RADEON_MAX_CRTCS 6
#define RADEON_MAX_CRTCS 6
#define RADEON_MAX_HDMI_BLOCKS 2
#define RADEON_MAX_AFMT_BLOCKS 6


struct radeon_irq {
struct radeon_irq {
	bool		installed;
	bool		installed;
@@ -605,7 +614,7 @@ struct radeon_irq {
	bool            gui_idle;
	bool            gui_idle;
	bool            gui_idle_acked;
	bool            gui_idle_acked;
	wait_queue_head_t	idle_queue;
	wait_queue_head_t	idle_queue;
	bool		hdmi[RADEON_MAX_HDMI_BLOCKS];
	bool		afmt[RADEON_MAX_AFMT_BLOCKS];
	spinlock_t sw_lock;
	spinlock_t sw_lock;
	int sw_refcount[RADEON_NUM_RINGS];
	int sw_refcount[RADEON_NUM_RINGS];
	union radeon_irq_stat_regs stat_regs;
	union radeon_irq_stat_regs stat_regs;
@@ -1546,13 +1555,13 @@ struct radeon_device {
	struct r600_ih ih; /* r6/700 interrupt ring */
	struct r600_ih ih; /* r6/700 interrupt ring */
	struct si_rlc rlc;
	struct si_rlc rlc;
	struct work_struct hotplug_work;
	struct work_struct hotplug_work;
	struct work_struct audio_work;
	int num_crtc; /* number of crtcs */
	int num_crtc; /* number of crtcs */
	struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
	struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
	struct mutex vram_mutex;
	struct mutex vram_mutex;


	/* audio stuff */
	/* audio stuff */
	bool			audio_enabled;
	bool			audio_enabled;
	struct timer_list	audio_timer;
	int			audio_channels;
	int			audio_channels;
	int			audio_rate;
	int			audio_rate;
	int			audio_bits_per_sample;
	int			audio_bits_per_sample;
@@ -1828,6 +1837,8 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
		     struct radeon_vm *vm,
		     struct radeon_vm *vm,
		     struct radeon_bo *bo);
		     struct radeon_bo *bo);


/* audio */
void r600_audio_update_hdmi(struct work_struct *work);


/*
/*
 * R600 vram scratch functions
 * R600 vram scratch functions
Loading