diff options
Diffstat (limited to 'drivers/gpu/drm/radeon')
68 files changed, 2582 insertions, 1364 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 12bc21219a0..4605633e253 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -2,7 +2,7 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -ccflags-y := -Iinclude/drm +ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include hostprogs-y := mkregtable clean-files := rn50_reg_safe.h r100_reg_safe.h r200_reg_safe.h rv515_reg_safe.h r300_reg_safe.h r420_reg_safe.h rs600_reg_safe.h r600_reg_safe.h evergreen_reg_safe.h cayman_reg_safe.h @@ -80,8 +80,10 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \ rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \ trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \ - ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o \ - radeon_sync.o + ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o \ + radeon_sync.o radeon_audio.o + +radeon-$(CONFIG_MMU_NOTIFIER) += radeon_mn.o # add async DMA block radeon-y += \ diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index d59ec491dbb..ed644a4f6f5 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1851,10 +1851,9 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) return pll; } /* otherwise, pick one of the plls */ - if ((rdev->family == CHIP_KAVERI) || - (rdev->family == CHIP_KABINI) || + if ((rdev->family == CHIP_KABINI) || (rdev->family == CHIP_MULLINS)) { - /* KB/KV/ML has PPLL1 and PPLL2 */ + /* KB/ML has PPLL1 and PPLL2 */ pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2; @@ -1863,7 +1862,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; } else { - /* CI has PPLL0, PPLL1, and PPLL2 */ + /* CI/KV has PPLL0, PPLL1, and PPLL2 */ pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2; @@ -2155,6 +2154,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) case ATOM_PPLL0: /* disable the ppll */ if ((rdev->family == CHIP_ARUBA) || + (rdev->family == CHIP_KAVERI) || (rdev->family == CHIP_BONAIRE) || (rdev->family == CHIP_HAWAII)) atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 11ba9d21b89..5bf825dfaa0 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -492,6 +492,10 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector, struct radeon_connector_atom_dig *dig_connector; int dp_clock; + if ((mode->clock > 340000) && + (!radeon_connector_is_dp12_capable(connector))) + return MODE_CLOCK_HIGH; + if (!radeon_connector->con_priv) return MODE_CLOCK_HIGH; dig_connector = radeon_connector->con_priv; @@ -619,10 +623,8 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) drm_dp_dpcd_writeb(dp_info->aux, DP_DOWNSPREAD_CTRL, 0); - if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) && - (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { + if (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE) drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1); - } /* set the lane count on the sink */ tmp = dp_info->dp_lane_count; diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index b8cd7975f79..7c9df1eac06 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -27,6 +27,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/radeon_drm.h> #include "radeon.h" +#include "radeon_audio.h" #include "atom.h" #include <linux/backlight.h> @@ -664,6 +665,8 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) int atombios_get_encoder_mode(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; struct radeon_connector *radeon_connector; @@ -728,6 +731,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) dig_connector = radeon_connector->con_priv; if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { + if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) + return ATOM_ENCODER_MODE_DP_AUDIO; return ATOM_ENCODER_MODE_DP; } else if (radeon_audio != 0) { if (radeon_connector->audio == RADEON_AUDIO_ENABLE) @@ -742,6 +747,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) } break; case DRM_MODE_CONNECTOR_eDP: + if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) + return ATOM_ENCODER_MODE_DP_AUDIO; return ATOM_ENCODER_MODE_DP; case DRM_MODE_CONNECTOR_DVIA: case DRM_MODE_CONNECTOR_VGA: @@ -1615,6 +1622,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) struct radeon_connector *radeon_connector = NULL; struct radeon_connector_atom_dig *radeon_dig_connector = NULL; bool travis_quirk = false; + int encoder_mode; if (connector) { radeon_connector = to_radeon_connector(connector); @@ -1710,6 +1718,11 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) } break; } + + encoder_mode = atombios_get_encoder_mode(encoder); + if (radeon_audio != 0 && + (encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode))) + radeon_audio_dpms(encoder, mode); } static void @@ -2123,6 +2136,7 @@ radeon_atom_encoder_mode_set(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); + int encoder_mode; radeon_encoder->pixel_clock = adjusted_mode->clock; @@ -2149,6 +2163,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: /* handled in dpms */ + encoder_mode = atombios_get_encoder_mode(encoder); + if (radeon_audio != 0 && + (encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode))) + radeon_audio_mode_set(encoder, adjusted_mode); break; case ENCODER_OBJECT_ID_INTERNAL_DDI: case ENCODER_OBJECT_ID_INTERNAL_DVO1: @@ -2170,13 +2188,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } atombios_apply_encoder_quirks(encoder, adjusted_mode); - - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { - if (rdev->asic->display.hdmi_enable) - radeon_hdmi_enable(rdev, encoder, true); - if (rdev->asic->display.hdmi_setmode) - radeon_hdmi_setmode(rdev, encoder, adjusted_mode); - } } static bool @@ -2442,10 +2453,6 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) disable_done: if (radeon_encoder_is_digital(encoder)) { - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { - if (rdev->asic->display.hdmi_enable) - radeon_hdmi_enable(rdev, encoder, false); - } dig = radeon_encoder->enc_priv; dig->dig_encoder = -1; } diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index 0b2929de9f4..db08f17be76 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -2277,6 +2277,7 @@ static void btc_update_requested_ps(struct radeon_device *rdev, eg_pi->requested_rps.ps_priv = &eg_pi->requested_ps; } +#if 0 void btc_dpm_reset_asic(struct radeon_device *rdev) { rv770_restrict_performance_levels_before_switch(rdev); @@ -2284,6 +2285,7 @@ void btc_dpm_reset_asic(struct radeon_device *rdev) btc_set_boot_state_timing(rdev); rv770_set_boot_state(rdev); } +#endif int btc_dpm_pre_set_power_state(struct radeon_device *rdev) { diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index f373a81ba3d..bcd2f1fe803 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -187,6 +187,9 @@ static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate); static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev, PPSMC_Msg msg, u32 parameter); +static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev); +static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev); + static struct ci_power_info *ci_get_pi(struct radeon_device *rdev) { struct ci_power_info *pi = rdev->pm.dpm.priv; @@ -1043,22 +1046,24 @@ static int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev) return -EINVAL; } + pi->fan_is_controlled_by_smc = true; return 0; } -#if 0 static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev) { PPSMC_Result ret; + struct ci_power_info *pi = ci_get_pi(rdev); ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl); - if (ret == PPSMC_Result_OK) + if (ret == PPSMC_Result_OK) { + pi->fan_is_controlled_by_smc = false; return 0; - else + } else return -EINVAL; } -static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, +int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, u32 *speed) { u32 duty, duty100; @@ -1083,21 +1088,22 @@ static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, return 0; } -static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, +int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, u32 speed) { u32 tmp; u32 duty, duty100; u64 tmp64; + struct ci_power_info *pi = ci_get_pi(rdev); if (rdev->pm.no_fan) return -ENOENT; - if (speed > 100) + if (pi->fan_is_controlled_by_smc) return -EINVAL; - if (rdev->pm.dpm.fan.ucode_fan_control) - ci_fan_ctrl_stop_smc_fan_control(rdev); + if (speed > 100) + return -EINVAL; duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; @@ -1112,11 +1118,38 @@ static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, tmp |= FDO_STATIC_DUTY(duty); WREG32_SMC(CG_FDO_CTRL0, tmp); - ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC); - return 0; } +void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode) +{ + if (mode) { + /* stop auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + ci_fan_ctrl_stop_smc_fan_control(rdev); + ci_fan_ctrl_set_static_mode(rdev, mode); + } else { + /* restart auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + ci_thermal_start_smc_fan_control(rdev); + else + ci_fan_ctrl_set_default_mode(rdev); + } +} + +u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev) +{ + struct ci_power_info *pi = ci_get_pi(rdev); + u32 tmp; + + if (pi->fan_is_controlled_by_smc) + return 0; + + tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK; + return (tmp >> FDO_PWM_MODE_SHIFT); +} + +#if 0 static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev, u32 *speed) { @@ -1698,10 +1731,12 @@ static int ci_set_overdrive_target_tdp(struct radeon_device *rdev, return 0; } +#if 0 static int ci_set_boot_state(struct radeon_device *rdev) { return ci_enable_sclk_mclk_dpm(rdev, false); } +#endif static u32 ci_get_average_sclk_freq(struct radeon_device *rdev) { @@ -5343,10 +5378,12 @@ int ci_dpm_set_power_state(struct radeon_device *rdev) return 0; } +#if 0 void ci_dpm_reset_asic(struct radeon_device *rdev) { ci_set_boot_state(rdev); } +#endif void ci_dpm_display_configuration_changed(struct radeon_device *rdev) { diff --git a/drivers/gpu/drm/radeon/ci_dpm.h b/drivers/gpu/drm/radeon/ci_dpm.h index 84e3d3bcf9f..723220ffbea 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.h +++ b/drivers/gpu/drm/radeon/ci_dpm.h @@ -291,6 +291,7 @@ struct ci_power_info { struct ci_ps requested_ps; /* fan control */ bool fan_ctrl_is_in_default_mode; + bool fan_is_controlled_by_smc; u32 t_min; u32 fan_ctrl_default_mode; }; diff --git a/drivers/gpu/drm/radeon/ci_smc.c b/drivers/gpu/drm/radeon/ci_smc.c index e78bcad7a43..35c6f648ba0 100644 --- a/drivers/gpu/drm/radeon/ci_smc.c +++ b/drivers/gpu/drm/radeon/ci_smc.c @@ -184,6 +184,7 @@ PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg) return (PPSMC_Result)tmp; } +#if 0 PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev) { u32 tmp; @@ -201,6 +202,7 @@ PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev) return PPSMC_Result_OK; } +#endif int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit) { diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 6dcde3798b4..e6a4ba236c7 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -27,6 +27,7 @@ #include "drmP.h" #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "cikd.h" #include "atom.h" #include "cik_blit_shaders.h" @@ -3904,7 +3905,21 @@ void cik_fence_gfx_ring_emit(struct radeon_device *rdev, struct radeon_ring *ring = &rdev->ring[fence->ring]; u64 addr = rdev->fence_drv[fence->ring].gpu_addr; - /* EVENT_WRITE_EOP - flush caches, send int */ + /* Workaround for cache flush problems. First send a dummy EOP + * event down the pipe with seq one below. + */ + radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); + radeon_ring_write(ring, (EOP_TCL1_ACTION_EN | + EOP_TC_ACTION_EN | + EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) | + EVENT_INDEX(5))); + radeon_ring_write(ring, addr & 0xfffffffc); + radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | + DATA_SEL(1) | INT_SEL(0)); + radeon_ring_write(ring, fence->seq - 1); + radeon_ring_write(ring, 0); + + /* Then send the real EOP event down the pipe. */ radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); radeon_ring_write(ring, (EOP_TCL1_ACTION_EN | EOP_TC_ACTION_EN | @@ -5707,6 +5722,28 @@ void cik_pcie_gart_tlb_flush(struct radeon_device *rdev) WREG32(VM_INVALIDATE_REQUEST, 0x1); } +static void cik_pcie_init_compute_vmid(struct radeon_device *rdev) +{ + int i; + uint32_t sh_mem_bases, sh_mem_config; + + sh_mem_bases = 0x6000 | 0x6000 << 16; + sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED); + sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED); + + mutex_lock(&rdev->srbm_mutex); + for (i = 8; i < 16; i++) { + cik_srbm_select(rdev, 0, 0, 0, i); + /* CP and shaders */ + WREG32(SH_MEM_CONFIG, sh_mem_config); + WREG32(SH_MEM_APE1_BASE, 1); + WREG32(SH_MEM_APE1_LIMIT, 0); + WREG32(SH_MEM_BASES, sh_mem_bases); + } + cik_srbm_select(rdev, 0, 0, 0, 0); + mutex_unlock(&rdev->srbm_mutex); +} + /** * cik_pcie_gart_enable - gart enable * @@ -5820,6 +5857,8 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) cik_srbm_select(rdev, 0, 0, 0, 0); mutex_unlock(&rdev->srbm_mutex); + cik_pcie_init_compute_vmid(rdev); + cik_pcie_gart_tlb_flush(rdev); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", (unsigned)(rdev->mc.gtt_size >> 20), @@ -6033,6 +6072,17 @@ void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, 0); radeon_ring_write(ring, 1 << vm_id); + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_OPERATION(0) | /* wait */ + WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ + /* compute doesn't have PFP */ if (usepfp) { /* sync PFP to ME, otherwise we might get invalid PFP reads */ @@ -7323,7 +7373,6 @@ int cik_irq_set(struct radeon_device *rdev) u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; u32 grbm_int_cntl = 0; u32 dma_cntl, dma_cntl1; - u32 thermal_int; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); @@ -7353,13 +7402,6 @@ int cik_irq_set(struct radeon_device *rdev) cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; - if (rdev->flags & RADEON_IS_IGP) - thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL) & - ~(THERM_INTH_MASK | THERM_INTL_MASK); - else - thermal_int = RREG32_SMC(CG_THERMAL_INT) & - ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); - /* enable CP interrupts on all rings */ if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { DRM_DEBUG("cik_irq_set: sw int gfx\n"); @@ -7463,14 +7505,6 @@ int cik_irq_set(struct radeon_device *rdev) hpd6 |= DC_HPDx_INT_EN; } - if (rdev->irq.dpm_thermal) { - DRM_DEBUG("dpm thermal\n"); - if (rdev->flags & RADEON_IS_IGP) - thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK; - else - thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; - } - WREG32(CP_INT_CNTL_RING0, cp_int_cntl); WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl); @@ -7517,11 +7551,6 @@ int cik_irq_set(struct radeon_device *rdev) WREG32(DC_HPD5_INT_CONTROL, hpd5); WREG32(DC_HPD6_INT_CONTROL, hpd6); - if (rdev->flags & RADEON_IS_IGP) - WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int); - else - WREG32_SMC(CG_THERMAL_INT, thermal_int); - return 0; } @@ -8482,7 +8511,7 @@ static int cik_startup(struct radeon_device *rdev) return r; } - r = dce6_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) return r; @@ -8540,7 +8569,7 @@ int cik_suspend(struct radeon_device *rdev) { radeon_kfd_suspend(rdev); radeon_pm_suspend(rdev); - dce6_audio_fini(rdev); + radeon_audio_fini(rdev); radeon_vm_manager_fini(rdev); cik_cp_enable(rdev, false); cik_sdma_enable(rdev, false); diff --git a/drivers/gpu/drm/radeon/cik_reg.h b/drivers/gpu/drm/radeon/cik_reg.h index 79c45e8a536..f667347d815 100644 --- a/drivers/gpu/drm/radeon/cik_reg.h +++ b/drivers/gpu/drm/radeon/cik_reg.h @@ -147,140 +147,41 @@ #define CIK_LB_DESKTOP_HEIGHT 0x6b0c +#define KFD_CIK_SDMA_QUEUE_OFFSET 0x200 + #define CP_HQD_IQ_RPTR 0xC970u #define AQL_ENABLE (1U << 0) - -#define IDLE (1 << 2) - -struct cik_mqd { - uint32_t header; - uint32_t compute_dispatch_initiator; - uint32_t compute_dim_x; - uint32_t compute_dim_y; - uint32_t compute_dim_z; - uint32_t compute_start_x; - uint32_t compute_start_y; - uint32_t compute_start_z; - uint32_t compute_num_thread_x; - uint32_t compute_num_thread_y; - uint32_t compute_num_thread_z; - uint32_t compute_pipelinestat_enable; - uint32_t compute_perfcount_enable; - uint32_t compute_pgm_lo; - uint32_t compute_pgm_hi; - uint32_t compute_tba_lo; - uint32_t compute_tba_hi; - uint32_t compute_tma_lo; - uint32_t compute_tma_hi; - uint32_t compute_pgm_rsrc1; - uint32_t compute_pgm_rsrc2; - uint32_t compute_vmid; - uint32_t compute_resource_limits; - uint32_t compute_static_thread_mgmt_se0; - uint32_t compute_static_thread_mgmt_se1; - uint32_t compute_tmpring_size; - uint32_t compute_static_thread_mgmt_se2; - uint32_t compute_static_thread_mgmt_se3; - uint32_t compute_restart_x; - uint32_t compute_restart_y; - uint32_t compute_restart_z; - uint32_t compute_thread_trace_enable; - uint32_t compute_misc_reserved; - uint32_t compute_user_data_0; - uint32_t compute_user_data_1; - uint32_t compute_user_data_2; - uint32_t compute_user_data_3; - uint32_t compute_user_data_4; - uint32_t compute_user_data_5; - uint32_t compute_user_data_6; - uint32_t compute_user_data_7; - uint32_t compute_user_data_8; - uint32_t compute_user_data_9; - uint32_t compute_user_data_10; - uint32_t compute_user_data_11; - uint32_t compute_user_data_12; - uint32_t compute_user_data_13; - uint32_t compute_user_data_14; - uint32_t compute_user_data_15; - uint32_t cp_compute_csinvoc_count_lo; - uint32_t cp_compute_csinvoc_count_hi; - uint32_t cp_mqd_base_addr_lo; - uint32_t cp_mqd_base_addr_hi; - uint32_t cp_hqd_active; - uint32_t cp_hqd_vmid; - uint32_t cp_hqd_persistent_state; - uint32_t cp_hqd_pipe_priority; - uint32_t cp_hqd_queue_priority; - uint32_t cp_hqd_quantum; - uint32_t cp_hqd_pq_base_lo; - uint32_t cp_hqd_pq_base_hi; - uint32_t cp_hqd_pq_rptr; - uint32_t cp_hqd_pq_rptr_report_addr_lo; - uint32_t cp_hqd_pq_rptr_report_addr_hi; - uint32_t cp_hqd_pq_wptr_poll_addr_lo; - uint32_t cp_hqd_pq_wptr_poll_addr_hi; - uint32_t cp_hqd_pq_doorbell_control; - uint32_t cp_hqd_pq_wptr; - uint32_t cp_hqd_pq_control; - uint32_t cp_hqd_ib_base_addr_lo; - uint32_t cp_hqd_ib_base_addr_hi; - uint32_t cp_hqd_ib_rptr; - uint32_t cp_hqd_ib_control; - uint32_t cp_hqd_iq_timer; - uint32_t cp_hqd_iq_rptr; - uint32_t cp_hqd_dequeue_request; - uint32_t cp_hqd_dma_offload; - uint32_t cp_hqd_sema_cmd; - uint32_t cp_hqd_msg_type; - uint32_t cp_hqd_atomic0_preop_lo; - uint32_t cp_hqd_atomic0_preop_hi; - uint32_t cp_hqd_atomic1_preop_lo; - uint32_t cp_hqd_atomic1_preop_hi; - uint32_t cp_hqd_hq_status0; - uint32_t cp_hqd_hq_control0; - uint32_t cp_mqd_control; - uint32_t cp_mqd_query_time_lo; - uint32_t cp_mqd_query_time_hi; - uint32_t cp_mqd_connect_start_time_lo; - uint32_t cp_mqd_connect_start_time_hi; - uint32_t cp_mqd_connect_end_time_lo; - uint32_t cp_mqd_connect_end_time_hi; - uint32_t cp_mqd_connect_end_wf_count; - uint32_t cp_mqd_connect_end_pq_rptr; - uint32_t cp_mqd_connect_end_pq_wptr; - uint32_t cp_mqd_connect_end_ib_rptr; - uint32_t reserved_96; - uint32_t reserved_97; - uint32_t reserved_98; - uint32_t reserved_99; - uint32_t iqtimer_pkt_header; - uint32_t iqtimer_pkt_dw0; - uint32_t iqtimer_pkt_dw1; - uint32_t iqtimer_pkt_dw2; - uint32_t iqtimer_pkt_dw3; - uint32_t iqtimer_pkt_dw4; - uint32_t iqtimer_pkt_dw5; - uint32_t iqtimer_pkt_dw6; - uint32_t reserved_108; - uint32_t reserved_109; - uint32_t reserved_110; - uint32_t reserved_111; - uint32_t queue_doorbell_id0; - uint32_t queue_doorbell_id1; - uint32_t queue_doorbell_id2; - uint32_t queue_doorbell_id3; - uint32_t queue_doorbell_id4; - uint32_t queue_doorbell_id5; - uint32_t queue_doorbell_id6; - uint32_t queue_doorbell_id7; - uint32_t queue_doorbell_id8; - uint32_t queue_doorbell_id9; - uint32_t queue_doorbell_id10; - uint32_t queue_doorbell_id11; - uint32_t queue_doorbell_id12; - uint32_t queue_doorbell_id13; - uint32_t queue_doorbell_id14; - uint32_t queue_doorbell_id15; -}; +#define SDMA0_RLC0_RB_CNTL 0xD400u +#define SDMA_RB_VMID(x) (x << 24) +#define SDMA0_RLC0_RB_BASE 0xD404u +#define SDMA0_RLC0_RB_BASE_HI 0xD408u +#define SDMA0_RLC0_RB_RPTR 0xD40Cu +#define SDMA0_RLC0_RB_WPTR 0xD410u +#define SDMA0_RLC0_RB_WPTR_POLL_CNTL 0xD414u +#define SDMA0_RLC0_RB_WPTR_POLL_ADDR_HI 0xD418u +#define SDMA0_RLC0_RB_WPTR_POLL_ADDR_LO 0xD41Cu +#define SDMA0_RLC0_RB_RPTR_ADDR_HI 0xD420u +#define SDMA0_RLC0_RB_RPTR_ADDR_LO 0xD424u +#define SDMA0_RLC0_IB_CNTL 0xD428u +#define SDMA0_RLC0_IB_RPTR 0xD42Cu +#define SDMA0_RLC0_IB_OFFSET 0xD430u +#define SDMA0_RLC0_IB_BASE_LO 0xD434u +#define SDMA0_RLC0_IB_BASE_HI 0xD438u +#define SDMA0_RLC0_IB_SIZE 0xD43Cu +#define SDMA0_RLC0_SKIP_CNTL 0xD440u +#define SDMA0_RLC0_CONTEXT_STATUS 0xD444u +#define SDMA_RLC_IDLE (1 << 2) +#define SDMA0_RLC0_DOORBELL 0xD448u +#define SDMA_OFFSET(x) (x << 0) +#define SDMA_DB_ENABLE (1 << 28) +#define SDMA0_RLC0_VIRTUAL_ADDR 0xD49Cu +#define SDMA_ATC (1 << 0) +#define SDMA_VA_PTR32 (1 << 4) +#define SDMA_VA_SHARED_BASE(x) (x << 8) +#define SDMA0_RLC0_APE1_CNTL 0xD4A0u +#define SDMA0_RLC0_DOORBELL_LOG 0xD4A4u +#define SDMA0_RLC0_WATERMARK 0xD4A8u +#define SDMA0_CNTL 0xD010 +#define SDMA1_CNTL 0xD810 #endif diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index dde5c7e29eb..f86eb54e776 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -283,6 +283,33 @@ static void cik_sdma_rlc_stop(struct radeon_device *rdev) } /** + * cik_sdma_ctx_switch_enable - enable/disable sdma engine preemption + * + * @rdev: radeon_device pointer + * @enable: enable/disable preemption. + * + * Halt or unhalt the async dma engines (CIK). + */ +static void cik_sdma_ctx_switch_enable(struct radeon_device *rdev, bool enable) +{ + uint32_t reg_offset, value; + int i; + + for (i = 0; i < 2; i++) { + if (i == 0) + reg_offset = SDMA0_REGISTER_OFFSET; + else + reg_offset = SDMA1_REGISTER_OFFSET; + value = RREG32(SDMA0_CNTL + reg_offset); + if (enable) + value |= AUTO_CTXSW_ENABLE; + else + value &= ~AUTO_CTXSW_ENABLE; + WREG32(SDMA0_CNTL + reg_offset, value); + } +} + +/** * cik_sdma_enable - stop the async dma engines * * @rdev: radeon_device pointer @@ -312,6 +339,8 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable) me_cntl |= SDMA_HALT; WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl); } + + cik_sdma_ctx_switch_enable(rdev, enable); } /** @@ -816,7 +845,6 @@ void cik_sdma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -903,6 +931,9 @@ void cik_sdma_vm_pad_ib(struct radeon_ib *ib) void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, unsigned vm_id, uint64_t pd_addr) { + u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(0) | + SDMA_POLL_REG_MEM_EXTRA_FUNC(0)); /* always */ + radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); if (vm_id < 8) { radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2); @@ -943,5 +974,12 @@ void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 1 << vm_id); + + radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits)); + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* reference */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */ } diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index ba85986febe..03003f8a6de 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -2156,4 +2156,6 @@ #define ATC_VM_APERTURE1_HIGH_ADDR 0x330Cu #define ATC_VM_APERTURE1_LOW_ADDR 0x3304u +#define IH_VMID_0_LUT 0x3D40u + #endif diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c index 9aad0327e4d..ca058589dde 100644 --- a/drivers/gpu/drm/radeon/cypress_dpm.c +++ b/drivers/gpu/drm/radeon/cypress_dpm.c @@ -2005,11 +2005,13 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev) return 0; } +#if 0 void cypress_dpm_reset_asic(struct radeon_device *rdev) { rv770_restrict_performance_levels_before_switch(rdev); rv770_set_boot_state(rdev); } +#endif void cypress_dpm_display_configuration_changed(struct radeon_device *rdev) { diff --git a/drivers/gpu/drm/radeon/dce3_1_afmt.c b/drivers/gpu/drm/radeon/dce3_1_afmt.c index 2fe8cfc966d..f04205170b8 100644 --- a/drivers/gpu/drm/radeon/dce3_1_afmt.c +++ b/drivers/gpu/drm/radeon/dce3_1_afmt.c @@ -24,37 +24,17 @@ #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "r600d.h" -static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) +void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; u32 tmp; - u8 *sadb = NULL; - int sad_count; - - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); - if (sad_count < 0) { - DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - sad_count = 0; - } /* program the speaker allocation */ - tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); + tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); /* set HDMI mode */ tmp |= HDMI_CONNECTION; @@ -62,19 +42,32 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) tmp |= SPEAKER_ALLOCATION(sadb[0]); else tmp |= SPEAKER_ALLOCATION(5); /* stereo */ - WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); - - kfree(sadb); + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); } -static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder) +void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; - struct cea_sad *sads; - int i, sad_count; + u32 tmp; + + /* program the speaker allocation */ + tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); + tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK); + /* set DP mode */ + tmp |= DP_CONNECTION; + if (sad_count) + tmp |= SPEAKER_ALLOCATION(sadb[0]); + else + tmp |= SPEAKER_ALLOCATION(5); /* stereo */ + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); +} +void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count) +{ + int i; + struct radeon_device *rdev = encoder->dev->dev_private; static const u16 eld_reg_to_type[][2] = { { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM }, { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 }, @@ -90,25 +83,6 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder) { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO }, }; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_sad(radeon_connector->edid, &sads); - if (sad_count < 0) { - DRM_ERROR("Couldn't read SADs: %d\n", sad_count); - return; - } - BUG_ON(!sads); - for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { u32 value = 0; u8 stereo_freqs = 0; @@ -135,110 +109,124 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder) value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); - WREG32(eld_reg_to_type[i][0], value); + WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value); } - - kfree(sads); } -/* - * update the info frames with the data from the current display mode - */ -void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) +void dce3_2_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock) { - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; - struct hdmi_avi_infoframe frame; - uint32_t offset; - ssize_t err; - - if (!dig || !dig->afmt) - return; - - /* Silent, r600_hdmi_enable will raise WARN for us */ - if (!dig->afmt->enabled) + struct radeon_encoder *radeon_encoder; + struct radeon_encoder_atom_dig *dig; + unsigned int max_ratio = clock / 24000; + u32 dto_phase; + u32 wallclock_ratio; + u32 dto_cntl; + + if (!crtc) return; - offset = dig->afmt->offset; - - /* disable audio prior to setting up hw */ - dig->afmt->pin = r600_audio_get_pin(rdev); - r600_audio_enable(rdev, dig->afmt->pin, 0); - r600_audio_set_dto(encoder, mode->clock); + radeon_encoder = to_radeon_encoder(crtc->encoder); + dig = radeon_encoder->enc_priv; - WREG32(HDMI0_VBI_PACKET_CONTROL + offset, - HDMI0_NULL_SEND); /* send null packets when required */ - - WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000); + if (!dig) + return; - if (ASIC_IS_DCE32(rdev)) { - WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, - HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ - HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ - WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, - AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */ - AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ + if (max_ratio >= 8) { + dto_phase = 192 * 1000; + wallclock_ratio = 3; + } else if (max_ratio >= 4) { + dto_phase = 96 * 1000; + wallclock_ratio = 2; + } else if (max_ratio >= 2) { + dto_phase = 48 * 1000; + wallclock_ratio = 1; } else { - WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, - HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ - HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ - HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ - HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ + dto_phase = 24 * 1000; + wallclock_ratio = 0; } - if (ASIC_IS_DCE32(rdev)) { - dce3_2_afmt_write_speaker_allocation(encoder); - dce3_2_afmt_write_sad_regs(encoder); + /* Express [24MHz / target pixel clock] as an exact rational + * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE + * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator + */ + if (dig->dig_encoder == 0) { + dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); + WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock); + WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ + } else { + dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl); + WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase); + WREG32(DCCG_AUDIO_DTO1_MODULE, clock); + WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ } +} + +void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; WREG32(HDMI0_ACR_PACKET_CONTROL + offset, - HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */ - HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ - - WREG32(HDMI0_VBI_PACKET_CONTROL + offset, - HDMI0_NULL_SEND | /* send null packets when required */ - HDMI0_GC_SEND | /* send general control packets */ - HDMI0_GC_CONT); /* send general control packets every frame */ - - /* TODO: HDMI0_AUDIO_INFO_UPDATE */ - WREG32(HDMI0_INFOFRAME_CONTROL0 + offset, - HDMI0_AVI_INFO_SEND | /* enable AVI info frames */ - HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */ - HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ - HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */ - - WREG32(HDMI0_INFOFRAME_CONTROL1 + offset, - HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */ - HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */ - - WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */ - - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); - if (err < 0) { - DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); - return; - } + HDMI0_ACR_SOURCE | /* select SW CTS value */ + HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ + + WREG32_P(HDMI0_ACR_32_0 + offset, + HDMI0_ACR_CTS_32(acr->cts_32khz), + ~HDMI0_ACR_CTS_32_MASK); + WREG32_P(HDMI0_ACR_32_1 + offset, + HDMI0_ACR_N_32(acr->n_32khz), + ~HDMI0_ACR_N_32_MASK); + + WREG32_P(HDMI0_ACR_44_0 + offset, + HDMI0_ACR_CTS_44(acr->cts_44_1khz), + ~HDMI0_ACR_CTS_44_MASK); + WREG32_P(HDMI0_ACR_44_1 + offset, + HDMI0_ACR_N_44(acr->n_44_1khz), + ~HDMI0_ACR_N_44_MASK); + + WREG32_P(HDMI0_ACR_48_0 + offset, + HDMI0_ACR_CTS_48(acr->cts_48khz), + ~HDMI0_ACR_CTS_48_MASK); + WREG32_P(HDMI0_ACR_48_1 + offset, + HDMI0_ACR_N_48(acr->n_48khz), + ~HDMI0_ACR_N_48_MASK); +} - err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - DRM_ERROR("failed to pack AVI infoframe: %zd\n", err); - return; - } +void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; - r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); - r600_hdmi_update_ACR(encoder, mode->clock); + WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, + HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ + HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ - /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ - WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF); - WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF); - WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001); - WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001); + WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, + AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */ + AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ - r600_hdmi_audio_workaround(encoder); + WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, + HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ + HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */ - /* enable audio after to setting up hw */ - r600_audio_enable(rdev, dig->afmt->pin, 0xf); + WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset, + HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */ +} + +void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + + if (mute) + WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE); + else + WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE); } diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index f312edf4d50..192c8038915 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c @@ -23,9 +23,10 @@ #include <linux/hdmi.h> #include <drm/drmP.h> #include "radeon.h" +#include "radeon_audio.h" #include "sid.h" -static u32 dce6_endpoint_rreg(struct radeon_device *rdev, +u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 block_offset, u32 reg) { unsigned long flags; @@ -39,7 +40,7 @@ static u32 dce6_endpoint_rreg(struct radeon_device *rdev, return r; } -static void dce6_endpoint_wreg(struct radeon_device *rdev, +void dce6_endpoint_wreg(struct radeon_device *rdev, u32 block_offset, u32 reg, u32 v) { unsigned long flags; @@ -54,10 +55,6 @@ static void dce6_endpoint_wreg(struct radeon_device *rdev, spin_unlock_irqrestore(&rdev->end_idx_lock, flags); } -#define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg)) -#define WREG32_ENDPOINT(block, reg, v) dce6_endpoint_wreg(rdev, (block), (reg), (v)) - - static void dce6_afmt_get_connected_pins(struct radeon_device *rdev) { int i; @@ -105,13 +102,11 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder) } void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, - struct drm_display_mode *mode) + struct drm_connector *connector, struct drm_display_mode *mode) { struct radeon_device *rdev = encoder->dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; u32 tmp = 0, offset; if (!dig || !dig->afmt || !dig->afmt->pin) @@ -119,18 +114,6 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, offset = dig->afmt->pin->offset; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - if (mode->flags & DRM_MODE_FLAG_INTERLACE) { if (connector->latency_present[1]) tmp = VIDEO_LIPSYNC(connector->video_latency[1]) | @@ -147,40 +130,19 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp); } -void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) +void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; u32 offset, tmp; - u8 *sadb = NULL; - int sad_count; if (!dig || !dig->afmt || !dig->afmt->pin) return; offset = dig->afmt->pin->offset; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); - if (sad_count < 0) { - DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - sad_count = 0; - } - /* program the speaker allocation */ tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER); tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); @@ -191,21 +153,41 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) else tmp |= SPEAKER_ALLOCATION(5); /* stereo */ WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp); - - kfree(sadb); } -void dce6_afmt_write_sad_regs(struct drm_encoder *encoder) +void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - u32 offset; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; - struct cea_sad *sads; - int i, sad_count; + u32 offset, tmp; + + if (!dig || !dig->afmt || !dig->afmt->pin) + return; + offset = dig->afmt->pin->offset; + + /* program the speaker allocation */ + tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER); + tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK); + /* set DP mode */ + tmp |= DP_CONNECTION; + if (sad_count) + tmp |= SPEAKER_ALLOCATION(sadb[0]); + else + tmp |= SPEAKER_ALLOCATION(5); /* stereo */ + WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp); +} + +void dce6_afmt_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count) +{ + u32 offset; + int i; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct radeon_device *rdev = encoder->dev->dev_private; static const u16 eld_reg_to_type[][2] = { { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM }, { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 }, @@ -226,25 +208,6 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder) offset = dig->afmt->pin->offset; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); - if (sad_count <= 0) { - DRM_ERROR("Couldn't read SADs: %d\n", sad_count); - return; - } - BUG_ON(!sads); - for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { u32 value = 0; u8 stereo_freqs = 0; @@ -273,13 +236,6 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder) WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value); } - - kfree(sads); -} - -static int dce6_audio_chipset_supported(struct radeon_device *rdev) -{ - return !ASIC_IS_NODCE(rdev); } void dce6_audio_enable(struct radeon_device *rdev, @@ -293,64 +249,76 @@ void dce6_audio_enable(struct radeon_device *rdev, enable_mask ? AUDIO_ENABLED : 0); } -static const u32 pin_offsets[7] = -{ - (0x5e00 - 0x5e00), - (0x5e18 - 0x5e00), - (0x5e30 - 0x5e00), - (0x5e48 - 0x5e00), - (0x5e60 - 0x5e00), - (0x5e78 - 0x5e00), - (0x5e90 - 0x5e00), -}; - -int dce6_audio_init(struct radeon_device *rdev) +void dce6_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock) { - int i; + /* Two dtos; generally use dto0 for HDMI */ + u32 value = 0; - if (!radeon_audio || !dce6_audio_chipset_supported(rdev)) - return 0; + if (crtc) + value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id); - rdev->audio.enabled = true; + WREG32(DCCG_AUDIO_DTO_SOURCE, value); - if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */ - rdev->audio.num_pins = 7; - else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */ - rdev->audio.num_pins = 3; - else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */ - rdev->audio.num_pins = 7; - else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */ - rdev->audio.num_pins = 6; - else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */ - rdev->audio.num_pins = 2; - else /* SI: 6 streams, 6 endpoints */ - rdev->audio.num_pins = 6; + /* Express [24MHz / target pixel clock] as an exact rational + * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE + * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator + */ + WREG32(DCCG_AUDIO_DTO0_PHASE, 24000); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock); +} - for (i = 0; i < rdev->audio.num_pins; i++) { - rdev->audio.pin[i].channels = -1; - rdev->audio.pin[i].rate = -1; - rdev->audio.pin[i].bits_per_sample = -1; - rdev->audio.pin[i].status_bits = 0; - rdev->audio.pin[i].category_code = 0; - rdev->audio.pin[i].connected = false; - rdev->audio.pin[i].offset = pin_offsets[i]; - rdev->audio.pin[i].id = i; - /* disable audio. it will be set up later */ - dce6_audio_enable(rdev, &rdev->audio.pin[i], false); - } +void dce6_dp_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock) +{ + /* Two dtos; generally use dto1 for DP */ + u32 value = 0; + value |= DCCG_AUDIO_DTO_SEL; + + if (crtc) + value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id); + + WREG32(DCCG_AUDIO_DTO_SOURCE, value); - return 0; + /* Express [24MHz / target pixel clock] as an exact rational + * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE + * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator + */ + WREG32(DCCG_AUDIO_DTO1_PHASE, 24000); + WREG32(DCCG_AUDIO_DTO1_MODULE, clock); } -void dce6_audio_fini(struct radeon_device *rdev) +void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable) { - int i; + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + uint32_t offset; - if (!rdev->audio.enabled) + if (!dig || !dig->afmt) return; - for (i = 0; i < rdev->audio.num_pins; i++) - dce6_audio_enable(rdev, &rdev->audio.pin[i], false); + offset = dig->afmt->offset; + + if (enable) { + if (dig->afmt->enabled) + return; + + WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1)); + WREG32(EVERGREEN_DP_SEC_CNTL + offset, + EVERGREEN_DP_SEC_ASP_ENABLE | /* Audio packet transmission */ + EVERGREEN_DP_SEC_ATP_ENABLE | /* Audio timestamp packet transmission */ + EVERGREEN_DP_SEC_AIP_ENABLE | /* Audio infoframe packet transmission */ + EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */ + radeon_audio_enable(rdev, dig->afmt->pin, true); + } else { + if (!dig->afmt->enabled) + return; + + WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0); + radeon_audio_enable(rdev, dig->afmt->pin, false); + } - rdev->audio.enabled = false; + dig->afmt->enabled = enable; } diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 85995b4e333..78600f534c8 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -26,6 +26,7 @@ #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include <drm/radeon_drm.h> #include "evergreend.h" #include "atom.h" @@ -5286,7 +5287,7 @@ static int evergreen_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { DRM_ERROR("radeon: audio init failed\n"); return r; @@ -5332,7 +5333,7 @@ int evergreen_resume(struct radeon_device *rdev) int evergreen_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_suspend(rdev); r700_cp_stop(rdev); @@ -5482,7 +5483,7 @@ int evergreen_init(struct radeon_device *rdev) void evergreen_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r700_cp_fini(rdev); r600_dma_fini(rdev); r600_irq_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 924b1b7ab45..c9e0fbbf76a 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -83,6 +83,7 @@ struct evergreen_cs_track { u32 htile_offset; u32 htile_surface; struct radeon_bo *htile_bo; + unsigned long indirect_draw_buffer_size; }; static u32 evergreen_cs_get_aray_mode(u32 tiling_flags) @@ -1896,6 +1897,14 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, } break; } + case PACKET3_INDEX_BUFFER_SIZE: + { + if (pkt->count != 0) { + DRM_ERROR("bad INDEX_BUFFER_SIZE\n"); + return -EINVAL; + } + break; + } case PACKET3_DRAW_INDEX: { uint64_t offset; @@ -2006,6 +2015,67 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, return r; } break; + case PACKET3_SET_BASE: + { + /* + DW 1 HEADER Header of the packet. Shader_Type in bit 1 of the Header will correspond to the shader type of the Load, see Type-3 Packet. + 2 BASE_INDEX Bits [3:0] BASE_INDEX - Base Index specifies which base address is specified in the last two DWs. + 0001: DX11 Draw_Index_Indirect Patch Table Base: Base address for Draw_Index_Indirect data. + 3 ADDRESS_LO Bits [31:3] - Lower bits of QWORD-Aligned Address. Bits [2:0] - Reserved + 4 ADDRESS_HI Bits [31:8] - Reserved. Bits [7:0] - Upper bits of Address [47:32] + */ + if (pkt->count != 2) { + DRM_ERROR("bad SET_BASE\n"); + return -EINVAL; + } + + /* currently only supporting setting indirect draw buffer base address */ + if (idx_value != 1) { + DRM_ERROR("bad SET_BASE\n"); + return -EINVAL; + } + + r = radeon_cs_packet_next_reloc(p, &reloc, 0); + if (r) { + DRM_ERROR("bad SET_BASE\n"); + return -EINVAL; + } + + track->indirect_draw_buffer_size = radeon_bo_size(reloc->robj); + + ib[idx+1] = reloc->gpu_offset; + ib[idx+2] = upper_32_bits(reloc->gpu_offset) & 0xff; + + break; + } + case PACKET3_DRAW_INDIRECT: + case PACKET3_DRAW_INDEX_INDIRECT: + { + u64 size = pkt->opcode == PACKET3_DRAW_INDIRECT ? 16 : 20; + + /* + DW 1 HEADER + 2 DATA_OFFSET Bits [31:0] + byte aligned offset where the required data structure starts. Bits 1:0 are zero + 3 DRAW_INITIATOR Draw Initiator Register. Written to the VGT_DRAW_INITIATOR register for the assigned context + */ + if (pkt->count != 1) { + DRM_ERROR("bad DRAW_INDIRECT\n"); + return -EINVAL; + } + + if (idx_value + size > track->indirect_draw_buffer_size) { + dev_warn(p->dev, "DRAW_INDIRECT buffer too small %u + %llu > %lu\n", + idx_value, size, track->indirect_draw_buffer_size); + return -EINVAL; + } + + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + } case PACKET3_DISPATCH_DIRECT: if (pkt->count != 3) { DRM_ERROR("bad DISPATCH_DIRECT\n"); @@ -3243,7 +3313,13 @@ static int evergreen_vm_packet3_check(struct radeon_device *rdev, switch (pkt->opcode) { case PACKET3_NOP: + break; case PACKET3_SET_BASE: + if (idx_value != 1) { + DRM_ERROR("bad SET_BASE"); + return -EINVAL; + } + break; case PACKET3_CLEAR_STATE: case PACKET3_INDEX_BUFFER_SIZE: case PACKET3_DISPATCH_DIRECT: diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index 53abd9b17a5..1d9aebc7959 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -29,17 +29,12 @@ #include <drm/radeon_drm.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "evergreend.h" #include "atom.h" -extern void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder); -extern void dce6_afmt_write_sad_regs(struct drm_encoder *encoder); -extern void dce6_afmt_select_pin(struct drm_encoder *encoder); -extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, - struct drm_display_mode *mode); - /* enable the audio stream */ -static void dce4_audio_enable(struct radeon_device *rdev, +void dce4_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, u8 enable_mask) { @@ -69,48 +64,42 @@ static void dce4_audio_enable(struct radeon_device *rdev, WREG32(AZ_HOT_PLUG_CONTROL, tmp); } -/* - * update the N and CTS parameters for a given pixel clock rate - */ -static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) +void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - uint32_t offset = dig->afmt->offset; + int bpc = 8; - WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz)); - WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz); + if (encoder->crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + bpc = radeon_crtc->bpc; + } - WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz)); - WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz); + if (bpc > 8) + WREG32(HDMI_ACR_PACKET_CONTROL + offset, + HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ + else + WREG32(HDMI_ACR_PACKET_CONTROL + offset, + HDMI_ACR_SOURCE | /* select SW CTS value */ + HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ + + WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr->cts_32khz)); + WREG32(HDMI_ACR_32_1 + offset, acr->n_32khz); - WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz)); - WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz); + WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr->cts_44_1khz)); + WREG32(HDMI_ACR_44_1 + offset, acr->n_44_1khz); + + WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr->cts_48khz)); + WREG32(HDMI_ACR_48_1 + offset, acr->n_48khz); } -static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, - struct drm_display_mode *mode) +void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; u32 tmp = 0; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - if (mode->flags & DRM_MODE_FLAG_INTERLACE) { if (connector->latency_present[1]) tmp = VIDEO_LIPSYNC(connector->video_latency[1]) | @@ -124,38 +113,17 @@ static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, else tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); } - WREG32(AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp); + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp); } -static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder) +void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; u32 tmp; - u8 *sadb = NULL; - int sad_count; - - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); - if (sad_count < 0) { - DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - sad_count = 0; - } /* program the speaker allocation */ - tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); + tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); /* set HDMI mode */ tmp |= HDMI_CONNECTION; @@ -163,19 +131,32 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder) tmp |= SPEAKER_ALLOCATION(sadb[0]); else tmp |= SPEAKER_ALLOCATION(5); /* stereo */ - WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); - - kfree(sadb); + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); } -static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder) +void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; - struct cea_sad *sads; - int i, sad_count; + u32 tmp; + /* program the speaker allocation */ + tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); + tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK); + /* set DP mode */ + tmp |= DP_CONNECTION; + if (sad_count) + tmp |= SPEAKER_ALLOCATION(sadb[0]); + else + tmp |= SPEAKER_ALLOCATION(5); /* stereo */ + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); +} + +void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count) +{ + int i; + struct radeon_device *rdev = encoder->dev->dev_private; static const u16 eld_reg_to_type[][2] = { { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM }, { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 }, @@ -191,25 +172,6 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder) { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO }, }; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); - if (sad_count <= 0) { - DRM_ERROR("Couldn't read SADs: %d\n", sad_count); - return; - } - BUG_ON(!sads); - for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { u32 value = 0; u8 stereo_freqs = 0; @@ -236,25 +198,17 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder) value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); - WREG32(eld_reg_to_type[i][0], value); + WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value); } - - kfree(sads); } /* - * build a HDMI Video Info Frame + * build a AVI Info Frame */ -static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder, - void *buffer, size_t size) +void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size) { - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - uint32_t offset = dig->afmt->offset; uint8_t *frame = buffer + 3; - uint8_t *header = buffer; WREG32(AFMT_AVI_INFO0 + offset, frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); @@ -263,104 +217,103 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder, WREG32(AFMT_AVI_INFO2 + offset, frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); WREG32(AFMT_AVI_INFO3 + offset, - frame[0xC] | (frame[0xD] << 8) | (header[1] << 24)); + frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24)); + + WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset, + HDMI_AVI_INFO_SEND | /* enable AVI info frames */ + HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */ + + WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset, + HDMI_AVI_INFO_LINE(2), /* anything other than 0 */ + ~HDMI_AVI_INFO_LINE_MASK); } -static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock) +void dce4_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock) { - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - u32 base_rate = 24000; - u32 max_ratio = clock / base_rate; + unsigned int max_ratio = clock / 24000; u32 dto_phase; - u32 dto_modulo = clock; u32 wallclock_ratio; - u32 dto_cntl; - - if (!dig || !dig->afmt) - return; - - if (ASIC_IS_DCE6(rdev)) { - dto_phase = 24 * 1000; + u32 value; + + if (max_ratio >= 8) { + dto_phase = 192 * 1000; + wallclock_ratio = 3; + } else if (max_ratio >= 4) { + dto_phase = 96 * 1000; + wallclock_ratio = 2; + } else if (max_ratio >= 2) { + dto_phase = 48 * 1000; + wallclock_ratio = 1; } else { - if (max_ratio >= 8) { - dto_phase = 192 * 1000; - wallclock_ratio = 3; - } else if (max_ratio >= 4) { - dto_phase = 96 * 1000; - wallclock_ratio = 2; - } else if (max_ratio >= 2) { - dto_phase = 48 * 1000; - wallclock_ratio = 1; - } else { - dto_phase = 24 * 1000; - wallclock_ratio = 0; - } - dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; - dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); - WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); + dto_phase = 24 * 1000; + wallclock_ratio = 0; } - /* XXX two dtos; generally use dto0 for hdmi */ + value = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + value |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + value &= ~DCCG_AUDIO_DTO1_USE_512FBR_DTO; + WREG32(DCCG_AUDIO_DTO0_CNTL, value); + + /* Two dtos; generally use dto0 for HDMI */ + value = 0; + + if (crtc) + value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id); + + WREG32(DCCG_AUDIO_DTO_SOURCE, value); + /* Express [24MHz / target pixel clock] as an exact rational * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator */ - WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); - WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock); } - -/* - * update the info frames with the data from the current display mode - */ -void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) +void dce4_dp_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock) { - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; - struct hdmi_avi_infoframe frame; - uint32_t offset; - ssize_t err; - uint32_t val; - int bpc = 8; + u32 value; - if (!dig || !dig->afmt) - return; + value = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + value |= DCCG_AUDIO_DTO1_USE_512FBR_DTO; + WREG32(DCCG_AUDIO_DTO1_CNTL, value); - /* Silent, r600_hdmi_enable will raise WARN for us */ - if (!dig->afmt->enabled) - return; - offset = dig->afmt->offset; + /* Two dtos; generally use dto1 for DP */ + value = 0; + value |= DCCG_AUDIO_DTO_SEL; - /* hdmi deep color mode general control packets setup, if bpc > 8 */ - if (encoder->crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - bpc = radeon_crtc->bpc; - } + if (crtc) + value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id); - /* disable audio prior to setting up hw */ - if (ASIC_IS_DCE6(rdev)) { - dig->afmt->pin = dce6_audio_get_pin(rdev); - dce6_audio_enable(rdev, dig->afmt->pin, 0); - } else { - dig->afmt->pin = r600_audio_get_pin(rdev); - dce4_audio_enable(rdev, dig->afmt->pin, 0); - } + WREG32(DCCG_AUDIO_DTO_SOURCE, value); + + /* Express [24MHz / target pixel clock] as an exact rational + * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE + * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator + */ + WREG32(DCCG_AUDIO_DTO1_PHASE, 24000); + WREG32(DCCG_AUDIO_DTO1_MODULE, rdev->clock.max_pixel_clock * 10); +} - evergreen_audio_set_dto(encoder, mode->clock); +void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; WREG32(HDMI_VBI_PACKET_CONTROL + offset, - HDMI_NULL_SEND); /* send null packets when required */ + HDMI_NULL_SEND | /* send null packets when required */ + HDMI_GC_SEND | /* send general control packets */ + HDMI_GC_CONT); /* send general control packets every frame */ +} - WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000); +void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, u32 offset, int bpc) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + uint32_t val; val = RREG32(HDMI_CONTROL + offset); val &= ~HDMI_DEEP_COLOR_ENABLE; @@ -390,113 +343,59 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode } WREG32(HDMI_CONTROL + offset, val); +} - WREG32(HDMI_VBI_PACKET_CONTROL + offset, - HDMI_NULL_SEND | /* send null packets when required */ - HDMI_GC_SEND | /* send general control packets */ - HDMI_GC_CONT); /* send general control packets every frame */ +void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; WREG32(HDMI_INFOFRAME_CONTROL0 + offset, - HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ - HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */ + HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ + HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */ WREG32(AFMT_INFOFRAME_CONTROL0 + offset, - AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ + AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ WREG32(HDMI_INFOFRAME_CONTROL1 + offset, - HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */ - - WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */ + HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */ WREG32(HDMI_AUDIO_PACKET_CONTROL + offset, - HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */ - HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ - - WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, - AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ - - /* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */ - - if (bpc > 8) - WREG32(HDMI_ACR_PACKET_CONTROL + offset, - HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ - else - WREG32(HDMI_ACR_PACKET_CONTROL + offset, - HDMI_ACR_SOURCE | /* select SW CTS value */ - HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ - - evergreen_hdmi_update_ACR(encoder, mode->clock); + HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */ + HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ WREG32(AFMT_60958_0 + offset, - AFMT_60958_CS_CHANNEL_NUMBER_L(1)); + AFMT_60958_CS_CHANNEL_NUMBER_L(1)); WREG32(AFMT_60958_1 + offset, - AFMT_60958_CS_CHANNEL_NUMBER_R(2)); + AFMT_60958_CS_CHANNEL_NUMBER_R(2)); WREG32(AFMT_60958_2 + offset, - AFMT_60958_CS_CHANNEL_NUMBER_2(3) | - AFMT_60958_CS_CHANNEL_NUMBER_3(4) | - AFMT_60958_CS_CHANNEL_NUMBER_4(5) | - AFMT_60958_CS_CHANNEL_NUMBER_5(6) | - AFMT_60958_CS_CHANNEL_NUMBER_6(7) | - AFMT_60958_CS_CHANNEL_NUMBER_7(8)); - - if (ASIC_IS_DCE6(rdev)) { - dce6_afmt_write_speaker_allocation(encoder); - } else { - dce4_afmt_write_speaker_allocation(encoder); - } + AFMT_60958_CS_CHANNEL_NUMBER_2(3) | + AFMT_60958_CS_CHANNEL_NUMBER_3(4) | + AFMT_60958_CS_CHANNEL_NUMBER_4(5) | + AFMT_60958_CS_CHANNEL_NUMBER_5(6) | + AFMT_60958_CS_CHANNEL_NUMBER_6(7) | + AFMT_60958_CS_CHANNEL_NUMBER_7(8)); WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset, - AFMT_AUDIO_CHANNEL_ENABLE(0xff)); - - /* fglrx sets 0x40 in 0x5f80 here */ - - if (ASIC_IS_DCE6(rdev)) { - dce6_afmt_select_pin(encoder); - dce6_afmt_write_sad_regs(encoder); - dce6_afmt_write_latency_fields(encoder, mode); - } else { - evergreen_hdmi_write_sad_regs(encoder); - dce4_afmt_write_latency_fields(encoder, mode); - } - - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); - if (err < 0) { - DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); - return; - } - - err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - DRM_ERROR("failed to pack AVI infoframe: %zd\n", err); - return; - } - - evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); - - WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset, - HDMI_AVI_INFO_SEND | /* enable AVI info frames */ - HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */ + AFMT_AUDIO_CHANNEL_ENABLE(0xff)); - WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset, - HDMI_AVI_INFO_LINE(2), /* anything other than 0 */ - ~HDMI_AVI_INFO_LINE_MASK); + /* allow 60958 channel status and send audio packets fields to be updated */ + WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, + AFMT_AUDIO_SAMPLE_SEND | AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE); +} - WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset, - AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */ - /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ - WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF); - WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF); - WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001); - WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); +void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; - /* enable audio after to setting up hw */ - if (ASIC_IS_DCE6(rdev)) - dce6_audio_enable(rdev, dig->afmt->pin, 1); + if (mute) + WREG32_OR(HDMI_GC + offset, HDMI_GC_AVMUTE); else - dce4_audio_enable(rdev, dig->afmt->pin, 0xf); + WREG32_AND(HDMI_GC + offset, ~HDMI_GC_AVMUTE); } void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) @@ -516,10 +415,7 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) return; if (!enable && dig->afmt->pin) { - if (ASIC_IS_DCE6(rdev)) - dce6_audio_enable(rdev, dig->afmt->pin, 0); - else - dce4_audio_enable(rdev, dig->afmt->pin, 0); + radeon_audio_enable(rdev, dig->afmt->pin, 0); dig->afmt->pin = NULL; } @@ -528,3 +424,57 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id); } + +void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + uint32_t offset; + + if (!dig || !dig->afmt) + return; + + offset = dig->afmt->offset; + + if (enable) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector; + uint32_t val; + + if (dig->afmt->enabled) + return; + + WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1)); + + if (radeon_connector->con_priv) { + dig_connector = radeon_connector->con_priv; + val = RREG32(EVERGREEN_DP_SEC_AUD_N + offset); + val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf); + + if (dig_connector->dp_clock == 162000) + val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(3); + else + val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5); + + WREG32(EVERGREEN_DP_SEC_AUD_N + offset, val); + } + + WREG32(EVERGREEN_DP_SEC_CNTL + offset, + EVERGREEN_DP_SEC_ASP_ENABLE | /* Audio packet transmission */ + EVERGREEN_DP_SEC_ATP_ENABLE | /* Audio timestamp packet transmission */ + EVERGREEN_DP_SEC_AIP_ENABLE | /* Audio infoframe packet transmission */ + EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */ + radeon_audio_enable(rdev, dig->afmt->pin, 0xf); + } else { + if (!dig->afmt->enabled) + return; + + WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0); + radeon_audio_enable(rdev, dig->afmt->pin, 0); + } + + dig->afmt->enabled = enable; +} diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 23bff590fb6..aa939dfed3a 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -251,4 +251,19 @@ /* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */ #define EVERGREEN_HDMI_BASE 0x7030 +/* Display Port block */ +#define EVERGREEN_DP_SEC_CNTL 0x7280 +# define EVERGREEN_DP_SEC_STREAM_ENABLE (1 << 0) +# define EVERGREEN_DP_SEC_ASP_ENABLE (1 << 4) +# define EVERGREEN_DP_SEC_ATP_ENABLE (1 << 8) +# define EVERGREEN_DP_SEC_AIP_ENABLE (1 << 12) +# define EVERGREEN_DP_SEC_GSP_ENABLE (1 << 20) +# define EVERGREEN_DP_SEC_AVI_ENABLE (1 << 24) +# define EVERGREEN_DP_SEC_MPG_ENABLE (1 << 28) +#define EVERGREEN_DP_SEC_TIMESTAMP 0x72a4 +# define EVERGREEN_DP_SEC_TIMESTAMP_MODE(x) (((x) & 0x3) << 0) +#define EVERGREEN_DP_SEC_AUD_N 0x7294 +# define EVERGREEN_DP_SEC_N_BASE_MULTIPLE(x) (((x) & 0xf) << 24) +# define EVERGREEN_DP_SEC_SS_EN (1 << 28) + #endif diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index b066d6711b8..ee83d2a8875 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -509,6 +509,7 @@ #define DCCG_AUDIO_DTO1_MODULE 0x05c4 #define DCCG_AUDIO_DTO1_LOAD 0x05c8 #define DCCG_AUDIO_DTO1_CNTL 0x05cc +# define DCCG_AUDIO_DTO1_USE_512FBR_DTO (1 << 3) /* DCE 4.0 AFMT */ #define HDMI_CONTROL 0x7030 diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index 9b42001295b..0e236d067d6 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -1169,6 +1169,19 @@ void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable) } } +static void kv_enable_thermal_int(struct radeon_device *rdev, bool enable) +{ + u32 thermal_int; + + thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL); + if (enable) + thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK; + else + thermal_int &= ~(THERM_INTH_MASK | THERM_INTL_MASK); + WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int); + +} + int kv_dpm_enable(struct radeon_device *rdev) { struct kv_power_info *pi = kv_get_pi(rdev); @@ -1280,8 +1293,7 @@ int kv_dpm_late_enable(struct radeon_device *rdev) DRM_ERROR("kv_set_thermal_temperature_range failed\n"); return ret; } - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); + kv_enable_thermal_int(rdev, true); } /* powerdown unused blocks for now */ @@ -1312,6 +1324,7 @@ void kv_dpm_disable(struct radeon_device *rdev) kv_stop_dpm(rdev); kv_enable_ulv(rdev, false); kv_reset_am(rdev); + kv_enable_thermal_int(rdev, false); kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); } @@ -1925,6 +1938,7 @@ void kv_dpm_setup_asic(struct radeon_device *rdev) kv_init_sclk_t(rdev); } +#if 0 void kv_dpm_reset_asic(struct radeon_device *rdev) { struct kv_power_info *pi = kv_get_pi(rdev); @@ -1945,6 +1959,7 @@ void kv_dpm_reset_asic(struct radeon_device *rdev) kv_set_enabled_level(rdev, pi->graphics_boot_level); } } +#endif //XXX use sumo_dpm_display_configuration_changed @@ -2745,13 +2760,11 @@ int kv_dpm_init(struct radeon_device *rdev) pi->enable_auto_thermal_throttling = true; pi->disable_nb_ps3_in_battery = false; if (radeon_bapm == -1) { - /* There are stability issues reported on with - * bapm enabled on an asrock system. - */ - if (rdev->pdev->subsystem_vendor == 0x1849) - pi->bapm_enable = false; - else + /* only enable bapm on KB, ML by default */ + if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) pi->bapm_enable = true; + else + pi->bapm_enable = false; } else if (radeon_bapm == 0) { pi->bapm_enable = false; } else { diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 360de9f1f49..24242a7f0ac 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -27,6 +27,7 @@ #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include <drm/radeon_drm.h> #include "nid.h" #include "atom.h" @@ -2097,15 +2098,9 @@ static int cayman_startup(struct radeon_device *rdev) return r; } - if (ASIC_IS_DCE6(rdev)) { - r = dce6_audio_init(rdev); - if (r) - return r; - } else { - r = r600_audio_init(rdev); - if (r) - return r; - } + r = radeon_audio_init(rdev); + if (r) + return r; return 0; } @@ -2140,10 +2135,7 @@ int cayman_resume(struct radeon_device *rdev) int cayman_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - if (ASIC_IS_DCE6(rdev)) - dce6_audio_fini(rdev); - else - r600_audio_fini(rdev); + radeon_audio_fini(rdev); radeon_vm_manager_fini(rdev); cayman_cp_enable(rdev, false); cayman_dma_stop(rdev); @@ -2516,6 +2508,16 @@ void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0)); radeon_ring_write(ring, 1 << vm_id); + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ + /* sync PFP to ME, otherwise we might get invalid PFP reads */ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); radeon_ring_write(ring, 0x0); diff --git a/drivers/gpu/drm/radeon/ni_dma.c b/drivers/gpu/drm/radeon/ni_dma.c index 50f88611ff6..ce787a9f12c 100644 --- a/drivers/gpu/drm/radeon/ni_dma.c +++ b/drivers/gpu/drm/radeon/ni_dma.c @@ -372,7 +372,6 @@ void cayman_dma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -463,5 +462,11 @@ void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); radeon_ring_write(ring, 1 << vm_id); + + /* wait for invalidate to complete */ + radeon_ring_write(ring, DMA_SRBM_READ_PACKET); + radeon_ring_write(ring, (0xff << 20) | (VM_INVALIDATE_REQUEST >> 2)); + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0); /* value */ } diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 6d2f16cf2c1..7bc9f8d9804 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -3862,11 +3862,13 @@ void ni_dpm_post_set_power_state(struct radeon_device *rdev) ni_update_current_ps(rdev, new_ps); } +#if 0 void ni_dpm_reset_asic(struct radeon_device *rdev) { ni_restrict_performance_levels_before_switch(rdev); rv770_set_boot_state(rdev); } +#endif union power_info { struct _ATOM_POWERPLAY_INFO info; diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 2e12e4d6925..ad712548689 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -1133,6 +1133,23 @@ #define PACKET3_MEM_SEMAPHORE 0x39 #define PACKET3_MPEG_INDEX 0x3A #define PACKET3_WAIT_REG_MEM 0x3C +#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) + /* 0 - always + * 1 - < + * 2 - <= + * 3 - == + * 4 - != + * 5 - >= + * 6 - > + */ +#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) + /* 0 - reg + * 1 - mem + */ +#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) + /* 0 - me + * 1 - pfp + */ #define PACKET3_MEM_WRITE 0x3D #define PACKET3_PFP_SYNC_ME 0x42 #define PACKET3_SURFACE_SYNC 0x43 @@ -1272,6 +1289,13 @@ (1 << 21) | \ (((n) & 0xFFFFF) << 0)) +#define DMA_SRBM_POLL_PACKET ((9 << 28) | \ + (1 << 27) | \ + (1 << 26)) + +#define DMA_SRBM_READ_PACKET ((9 << 28) | \ + (1 << 27)) + /* async DMA Packet types */ #define DMA_PACKET_WRITE 0x2 #define DMA_PACKET_COPY 0x3 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 74f06d54059..279801ca511 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -644,6 +644,7 @@ int r100_pci_gart_init(struct radeon_device *rdev) return r; rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry; rdev->asic->gart.set_page = &r100_pci_gart_set_page; return radeon_gart_table_ram_alloc(rdev); } @@ -681,11 +682,16 @@ void r100_pci_gart_disable(struct radeon_device *rdev) WREG32(RADEON_AIC_HI_ADDR, 0); } +uint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags) +{ + return addr; +} + void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) + uint64_t entry) { u32 *gtt = rdev->gart.ptr; - gtt[i] = cpu_to_le32(lower_32_bits(addr)); + gtt[i] = cpu_to_le32(lower_32_bits(entry)); } void r100_pci_gart_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 064ad5569cc..08d68f3e13e 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -73,11 +73,8 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) #define R300_PTE_WRITEABLE (1 << 2) #define R300_PTE_READABLE (1 << 3) -void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) +uint64_t rv370_pcie_gart_get_page_entry(uint64_t addr, uint32_t flags) { - void __iomem *ptr = rdev->gart.ptr; - addr = (lower_32_bits(addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 24); if (flags & RADEON_GART_PAGE_READ) @@ -86,10 +83,18 @@ void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, addr |= R300_PTE_WRITEABLE; if (!(flags & RADEON_GART_PAGE_SNOOP)) addr |= R300_PTE_UNSNOOPED; + return addr; +} + +void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) +{ + void __iomem *ptr = rdev->gart.ptr; + /* on x86 we want this to be CPU endian, on powerpc * on powerpc without HW swappers, it'll get swapped on way * into VRAM - so no need for cpu_to_le32 on VRAM tables */ - writel(addr, ((void __iomem *)ptr) + (i * 4)); + writel(entry, ((void __iomem *)ptr) + (i * 4)); } int rv370_pcie_gart_init(struct radeon_device *rdev) @@ -109,6 +114,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev) DRM_ERROR("Failed to register debugfs file for PCIE gart !\n"); rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &rv370_pcie_gart_get_page_entry; rdev->asic->gart.set_page = &rv370_pcie_gart_set_page; return radeon_gart_table_vram_alloc(rdev); } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index ef5d6066fa5..07a71a2488c 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -33,6 +33,7 @@ #include <drm/radeon_drm.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "radeon_mode.h" #include "r600d.h" #include "atom.h" @@ -3054,7 +3055,7 @@ static int r600_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { DRM_ERROR("radeon: audio init failed\n"); return r; @@ -3105,7 +3106,7 @@ int r600_resume(struct radeon_device *rdev) int r600_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r600_cp_stop(rdev); if (rdev->has_uvd) { uvd_v1_0_fini(rdev); @@ -3224,7 +3225,7 @@ int r600_init(struct radeon_device *rdev) void r600_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r600_cp_fini(rdev); r600_irq_fini(rdev); if (rdev->has_uvd) { diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index b90dc0eb08e..62c91ed669c 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -29,6 +29,7 @@ #include <drm/radeon_drm.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "r600d.h" #include "atom.h" @@ -55,30 +56,6 @@ enum r600_hdmi_iec_status_bits { AUDIO_STATUS_LEVEL = 0x80 }; -static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = { - /* 32kHz 44.1kHz 48kHz */ - /* Clock N CTS N CTS N CTS */ - { 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */ - { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */ - { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */ - { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */ - { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */ - { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */ - { 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */ - { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */ - { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */ - { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */ -}; - - -/* - * check if the chipset is supported - */ -static int r600_audio_chipset_supported(struct radeon_device *rdev) -{ - return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); -} - static struct r600_audio_pin r600_audio_status(struct radeon_device *rdev) { struct r600_audio_pin status; @@ -191,155 +168,56 @@ void r600_audio_enable(struct radeon_device *rdev, WREG32(AZ_HOT_PLUG_CONTROL, tmp); } -/* - * initialize the audio vars - */ -int r600_audio_init(struct radeon_device *rdev) -{ - if (!radeon_audio || !r600_audio_chipset_supported(rdev)) - return 0; - - rdev->audio.enabled = true; - - rdev->audio.num_pins = 1; - rdev->audio.pin[0].channels = -1; - rdev->audio.pin[0].rate = -1; - rdev->audio.pin[0].bits_per_sample = -1; - rdev->audio.pin[0].status_bits = 0; - rdev->audio.pin[0].category_code = 0; - rdev->audio.pin[0].id = 0; - /* disable audio. it will be set up later */ - r600_audio_enable(rdev, &rdev->audio.pin[0], 0); - - return 0; -} - -/* - * release the audio timer - * TODO: How to do this correctly on SMP systems? - */ -void r600_audio_fini(struct radeon_device *rdev) -{ - if (!rdev->audio.enabled) - return; - - r600_audio_enable(rdev, &rdev->audio.pin[0], 0); - - rdev->audio.enabled = false; -} - struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev) { /* only one pin on 6xx-NI */ return &rdev->audio.pin[0]; } -/* - * calculate CTS and N values if they are not found in the table - */ -static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq) -{ - int n, cts; - unsigned long div, mul; - - /* Safe, but overly large values */ - n = 128 * freq; - cts = clock * 1000; - - /* Smallest valid fraction */ - div = gcd(n, cts); - - n /= div; - cts /= div; - - /* - * The optimal N is 128*freq/1000. Calculate the closest larger - * value that doesn't truncate any bits. - */ - mul = ((128*freq/1000) + (n-1))/n; - - n *= mul; - cts *= mul; - - /* Check that we are in spec (not always possible) */ - if (n < (128*freq/1500)) - printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n"); - if (n > (128*freq/300)) - printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n"); - - *N = n; - *CTS = cts; - - DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n", - *N, *CTS, freq); -} - -struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock) -{ - struct radeon_hdmi_acr res; - u8 i; - - /* Precalculated values for common clocks */ - for (i = 0; i < ARRAY_SIZE(r600_hdmi_predefined_acr); i++) { - if (r600_hdmi_predefined_acr[i].clock == clock) - return r600_hdmi_predefined_acr[i]; - } - - /* And odd clocks get manually calculated */ - r600_hdmi_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000); - r600_hdmi_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100); - r600_hdmi_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000); - - return res; -} - -/* - * update the N and CTS parameters for a given pixel clock rate - */ -void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) +void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - uint32_t offset = dig->afmt->offset; + + /* DCE 3.0 uses register that's normally for CRC_CONTROL */ + uint32_t acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL : + HDMI0_ACR_PACKET_CONTROL; + WREG32_P(acr_ctl + offset, + HDMI0_ACR_SOURCE | /* select SW CTS value */ + HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */ + ~(HDMI0_ACR_SOURCE | + HDMI0_ACR_AUTO_SEND)); WREG32_P(HDMI0_ACR_32_0 + offset, - HDMI0_ACR_CTS_32(acr.cts_32khz), - ~HDMI0_ACR_CTS_32_MASK); + HDMI0_ACR_CTS_32(acr->cts_32khz), + ~HDMI0_ACR_CTS_32_MASK); WREG32_P(HDMI0_ACR_32_1 + offset, - HDMI0_ACR_N_32(acr.n_32khz), - ~HDMI0_ACR_N_32_MASK); + HDMI0_ACR_N_32(acr->n_32khz), + ~HDMI0_ACR_N_32_MASK); WREG32_P(HDMI0_ACR_44_0 + offset, - HDMI0_ACR_CTS_44(acr.cts_44_1khz), - ~HDMI0_ACR_CTS_44_MASK); + HDMI0_ACR_CTS_44(acr->cts_44_1khz), + ~HDMI0_ACR_CTS_44_MASK); WREG32_P(HDMI0_ACR_44_1 + offset, - HDMI0_ACR_N_44(acr.n_44_1khz), - ~HDMI0_ACR_N_44_MASK); + HDMI0_ACR_N_44(acr->n_44_1khz), + ~HDMI0_ACR_N_44_MASK); WREG32_P(HDMI0_ACR_48_0 + offset, - HDMI0_ACR_CTS_48(acr.cts_48khz), - ~HDMI0_ACR_CTS_48_MASK); + HDMI0_ACR_CTS_48(acr->cts_48khz), + ~HDMI0_ACR_CTS_48_MASK); WREG32_P(HDMI0_ACR_48_1 + offset, - HDMI0_ACR_N_48(acr.n_48khz), - ~HDMI0_ACR_N_48_MASK); + HDMI0_ACR_N_48(acr->n_48khz), + ~HDMI0_ACR_N_48_MASK); } /* * build a HDMI Video Info Frame */ -void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, - size_t size) +void r600_set_avi_packet(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size) { - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - uint32_t offset = dig->afmt->offset; uint8_t *frame = buffer + 3; - uint8_t *header = buffer; WREG32(HDMI0_AVI_INFO0 + offset, frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); @@ -348,7 +226,14 @@ void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, WREG32(HDMI0_AVI_INFO2 + offset, frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); WREG32(HDMI0_AVI_INFO3 + offset, - frame[0xC] | (frame[0xD] << 8) | (header[1] << 24)); + frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24)); + + WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, + HDMI0_AVI_INFO_SEND | /* enable AVI info frames */ + HDMI0_AVI_INFO_CONT); /* send AVI info frames every frame/field */ + + WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset, + HDMI0_AVI_INFO_LINE(2)); /* anything other than 0 */ } /* @@ -425,188 +310,94 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder) value, ~HDMI0_AUDIO_TEST_EN); } -void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) +void r600_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock) { - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - u32 base_rate = 24000; - u32 max_ratio = clock / base_rate; - u32 dto_phase; - u32 dto_modulo = clock; - u32 wallclock_ratio; - u32 dto_cntl; + struct radeon_encoder *radeon_encoder; + struct radeon_encoder_atom_dig *dig; - if (!dig || !dig->afmt) + if (!crtc) return; - if (max_ratio >= 8) { - dto_phase = 192 * 1000; - wallclock_ratio = 3; - } else if (max_ratio >= 4) { - dto_phase = 96 * 1000; - wallclock_ratio = 2; - } else if (max_ratio >= 2) { - dto_phase = 48 * 1000; - wallclock_ratio = 1; - } else { - dto_phase = 24 * 1000; - wallclock_ratio = 0; - } + radeon_encoder = to_radeon_encoder(crtc->encoder); + dig = radeon_encoder->enc_priv; - /* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT. - * doesn't matter which one you use. Just use the first one. - */ - /* XXX two dtos; generally use dto0 for hdmi */ - /* Express [24MHz / target pixel clock] as an exact rational - * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE - * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator - */ - if (ASIC_IS_DCE32(rdev)) { - if (dig->dig_encoder == 0) { - dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; - dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); - WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); - WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); - WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo); - WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ - } else { - dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; - dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); - WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl); - WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase); - WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo); - WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ - } + if (!dig) + return; + + if (dig->dig_encoder == 0) { + WREG32(DCCG_AUDIO_DTO0_PHASE, 24000 * 100); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); + WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ } else { - /* according to the reg specs, this should DCE3.2 only, but in - * practice it seems to cover DCE2.0/3.0/3.1 as well. - */ - if (dig->dig_encoder == 0) { - WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); - WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); - WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ - } else { - WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100); - WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100); - WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ - } + WREG32(DCCG_AUDIO_DTO1_PHASE, 24000 * 100); + WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100); + WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ } } -/* - * update the info frames with the data from the current display mode - */ -void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) +void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; - struct hdmi_avi_infoframe frame; - uint32_t offset; - uint32_t acr_ctl; - ssize_t err; - - if (!dig || !dig->afmt) - return; - - /* Silent, r600_hdmi_enable will raise WARN for us */ - if (!dig->afmt->enabled) - return; - offset = dig->afmt->offset; - /* disable audio prior to setting up hw */ - dig->afmt->pin = r600_audio_get_pin(rdev); - r600_audio_enable(rdev, dig->afmt->pin, 0xf); + WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset, + HDMI0_NULL_SEND | /* send null packets when required */ + HDMI0_GC_SEND | /* send general control packets */ + HDMI0_GC_CONT); /* send general control packets every frame */ +} - r600_audio_set_dto(encoder, mode->clock); +void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, - HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ - HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ - HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ - HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */ - ~(HDMI0_AUDIO_SAMPLE_SEND | - HDMI0_AUDIO_DELAY_EN_MASK | - HDMI0_AUDIO_PACKETS_PER_LINE_MASK | - HDMI0_60958_CS_UPDATE)); - - /* DCE 3.0 uses register that's normally for CRC_CONTROL */ - acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL : - HDMI0_ACR_PACKET_CONTROL; - WREG32_P(acr_ctl + offset, - HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */ - HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */ - ~(HDMI0_ACR_SOURCE | - HDMI0_ACR_AUTO_SEND)); - - WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset, - HDMI0_NULL_SEND | /* send null packets when required */ - HDMI0_GC_SEND | /* send general control packets */ - HDMI0_GC_CONT); /* send general control packets every frame */ + HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ + HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ + HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ + HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */ + ~(HDMI0_AUDIO_SAMPLE_SEND | + HDMI0_AUDIO_DELAY_EN_MASK | + HDMI0_AUDIO_PACKETS_PER_LINE_MASK | + HDMI0_60958_CS_UPDATE)); WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, - HDMI0_AVI_INFO_SEND | /* enable AVI info frames */ - HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */ - HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ - HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ + HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ + HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ WREG32_P(HDMI0_INFOFRAME_CONTROL1 + offset, - HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */ - HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */ - ~(HDMI0_AVI_INFO_LINE_MASK | - HDMI0_AUDIO_INFO_LINE_MASK)); - - WREG32_AND(HDMI0_GC + offset, - ~HDMI0_GC_AVMUTE); /* unset HDMI0_GC_AVMUTE */ - - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); - if (err < 0) { - DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); - return; - } - - err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - DRM_ERROR("failed to pack AVI infoframe: %zd\n", err); - return; - } - - r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); - - /* fglrx duplicates INFOFRAME_CONTROL0 & INFOFRAME_CONTROL1 ops here */ + HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */ + ~HDMI0_AUDIO_INFO_LINE_MASK); WREG32_AND(HDMI0_GENERIC_PACKET_CONTROL + offset, - ~(HDMI0_GENERIC0_SEND | - HDMI0_GENERIC0_CONT | - HDMI0_GENERIC0_UPDATE | - HDMI0_GENERIC1_SEND | - HDMI0_GENERIC1_CONT | - HDMI0_GENERIC0_LINE_MASK | - HDMI0_GENERIC1_LINE_MASK)); - - r600_hdmi_update_ACR(encoder, mode->clock); + ~(HDMI0_GENERIC0_SEND | + HDMI0_GENERIC0_CONT | + HDMI0_GENERIC0_UPDATE | + HDMI0_GENERIC1_SEND | + HDMI0_GENERIC1_CONT | + HDMI0_GENERIC0_LINE_MASK | + HDMI0_GENERIC1_LINE_MASK)); WREG32_P(HDMI0_60958_0 + offset, - HDMI0_60958_CS_CHANNEL_NUMBER_L(1), - ~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK | - HDMI0_60958_CS_CLOCK_ACCURACY_MASK)); + HDMI0_60958_CS_CHANNEL_NUMBER_L(1), + ~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK | + HDMI0_60958_CS_CLOCK_ACCURACY_MASK)); WREG32_P(HDMI0_60958_1 + offset, - HDMI0_60958_CS_CHANNEL_NUMBER_R(2), - ~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK); + HDMI0_60958_CS_CHANNEL_NUMBER_R(2), + ~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK); +} - /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ - WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF); - WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF); - WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001); - WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001); +void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; - /* enable audio after to setting up hw */ - r600_audio_enable(rdev, dig->afmt->pin, 0xf); + if (mute) + WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE); + else + WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE); } /** @@ -692,7 +483,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable) return; if (!enable && dig->afmt->pin) { - r600_audio_enable(rdev, dig->afmt->pin, 0); + radeon_audio_enable(rdev, dig->afmt->pin, 0); dig->afmt->pin = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 54529b837af..5587603b4a8 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -242,6 +242,7 @@ bool radeon_get_bios(struct radeon_device *rdev); * Dummy page */ struct radeon_dummy_page { + uint64_t entry; struct page *page; dma_addr_t addr; }; @@ -645,7 +646,7 @@ struct radeon_gart { unsigned num_cpu_pages; unsigned table_size; struct page **pages; - dma_addr_t *pages_addr; + uint64_t *pages_entry; bool ready; }; @@ -1757,6 +1758,9 @@ struct r600_audio { bool enabled; struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS]; int num_pins; + struct radeon_audio_funcs *hdmi_funcs; + struct radeon_audio_funcs *dp_funcs; + struct radeon_audio_basic_funcs *funcs; }; /* @@ -1777,8 +1781,16 @@ void radeon_test_syncing(struct radeon_device *rdev); /* * MMU Notifier */ +#if defined(CONFIG_MMU_NOTIFIER) int radeon_mn_register(struct radeon_bo *bo, unsigned long addr); void radeon_mn_unregister(struct radeon_bo *bo); +#else +static inline int radeon_mn_register(struct radeon_bo *bo, unsigned long addr) +{ + return -ENODEV; +} +static inline void radeon_mn_unregister(struct radeon_bo *bo) {} +#endif /* * Debugfs @@ -1847,8 +1859,9 @@ struct radeon_asic { /* gart */ struct { void (*tlb_flush)(struct radeon_device *rdev); + uint64_t (*get_page_entry)(uint64_t addr, uint32_t flags); void (*set_page)(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); } gart; struct { int (*init)(struct radeon_device *rdev); @@ -1967,6 +1980,10 @@ struct radeon_asic { bool (*vblank_too_short)(struct radeon_device *rdev); void (*powergate_uvd)(struct radeon_device *rdev, bool gate); void (*enable_bapm)(struct radeon_device *rdev, bool enable); + void (*fan_ctrl_set_mode)(struct radeon_device *rdev, u32 mode); + u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev); + int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed); + int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed); } dpm; /* pageflipping */ struct { @@ -2852,7 +2869,8 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v) #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) #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, f) (rdev)->asic->gart.set_page((rdev), (i), (p), (f)) +#define radeon_gart_get_page_entry(a, f) (rdev)->asic->gart.get_page_entry((a), (f)) +#define radeon_gart_set_page(rdev, i, e) (rdev)->asic->gart.set_page((rdev), (i), (e)) #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) #define radeon_asic_vm_copy_pages(rdev, ib, pe, src, count) ((rdev)->asic->vm.copy_pages((rdev), (ib), (pe), (src), (count))) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 850de57069b..c0ecd128b14 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -159,11 +159,13 @@ void radeon_agp_disable(struct radeon_device *rdev) DRM_INFO("Forcing AGP to PCIE mode\n"); rdev->flags |= RADEON_IS_PCIE; rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &rv370_pcie_gart_get_page_entry; rdev->asic->gart.set_page = &rv370_pcie_gart_set_page; } else { DRM_INFO("Forcing AGP to PCI mode\n"); rdev->flags |= RADEON_IS_PCI; rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry; rdev->asic->gart.set_page = &r100_pci_gart_set_page; } rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; @@ -199,6 +201,7 @@ static struct radeon_asic r100_asic = { .mc_wait_for_idle = &r100_mc_wait_for_idle, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -265,6 +268,7 @@ static struct radeon_asic r200_asic = { .mc_wait_for_idle = &r100_mc_wait_for_idle, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -333,6 +337,20 @@ static struct radeon_asic_ring r300_gfx_ring = { .set_wptr = &r100_gfx_set_wptr, }; +static struct radeon_asic_ring rv515_gfx_ring = { + .ib_execute = &r100_ring_ib_execute, + .emit_fence = &r300_fence_ring_emit, + .emit_semaphore = &r100_semaphore_ring_emit, + .cs_parse = &r300_cs_parse, + .ring_start = &rv515_ring_start, + .ring_test = &r100_ring_test, + .ib_test = &r100_ib_test, + .is_lockup = &r100_gpu_is_lockup, + .get_rptr = &r100_gfx_get_rptr, + .get_wptr = &r100_gfx_get_wptr, + .set_wptr = &r100_gfx_set_wptr, +}; + static struct radeon_asic r300_asic = { .init = &r300_init, .fini = &r300_fini, @@ -345,6 +363,7 @@ static struct radeon_asic r300_asic = { .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -411,6 +430,7 @@ static struct radeon_asic r300_asic_pcie = { .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { @@ -477,6 +497,7 @@ static struct radeon_asic r420_asic = { .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { @@ -543,6 +564,7 @@ static struct radeon_asic rs400_asic = { .mc_wait_for_idle = &rs400_mc_wait_for_idle, .gart = { .tlb_flush = &rs400_gart_tlb_flush, + .get_page_entry = &rs400_gart_get_page_entry, .set_page = &rs400_gart_set_page, }, .ring = { @@ -609,6 +631,7 @@ static struct radeon_asic rs600_asic = { .mc_wait_for_idle = &rs600_mc_wait_for_idle, .gart = { .tlb_flush = &rs600_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -624,8 +647,6 @@ static struct radeon_asic rs600_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r100_copy_blit, @@ -677,6 +698,7 @@ static struct radeon_asic rs690_asic = { .mc_wait_for_idle = &rs690_mc_wait_for_idle, .gart = { .tlb_flush = &rs400_gart_tlb_flush, + .get_page_entry = &rs400_gart_get_page_entry, .set_page = &rs400_gart_set_page, }, .ring = { @@ -692,8 +714,6 @@ static struct radeon_asic rs690_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r100_copy_blit, @@ -745,10 +765,11 @@ static struct radeon_asic rv515_asic = { .mc_wait_for_idle = &rv515_mc_wait_for_idle, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { - [RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring + [RADEON_RING_TYPE_GFX_INDEX] = &rv515_gfx_ring }, .irq = { .set = &rs600_irq_set, @@ -811,10 +832,11 @@ static struct radeon_asic r520_asic = { .mc_wait_for_idle = &r520_mc_wait_for_idle, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { - [RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring + [RADEON_RING_TYPE_GFX_INDEX] = &rv515_gfx_ring }, .irq = { .set = &rs600_irq_set, @@ -905,6 +927,7 @@ static struct radeon_asic r600_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -921,8 +944,6 @@ static struct radeon_asic r600_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -990,6 +1011,7 @@ static struct radeon_asic rv6xx_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1007,8 +1029,6 @@ static struct radeon_asic rv6xx_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1081,6 +1101,7 @@ static struct radeon_asic rs780_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1098,8 +1119,6 @@ static struct radeon_asic rs780_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1185,6 +1204,7 @@ static struct radeon_asic rv770_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1202,8 +1222,6 @@ static struct radeon_asic rv770_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &dce3_1_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1303,6 +1321,7 @@ static struct radeon_asic evergreen_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1320,8 +1339,6 @@ static struct radeon_asic evergreen_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1395,6 +1412,7 @@ static struct radeon_asic sumo_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1412,8 +1430,6 @@ static struct radeon_asic sumo_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1486,6 +1502,7 @@ static struct radeon_asic btc_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1503,8 +1520,6 @@ static struct radeon_asic btc_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1621,6 +1636,7 @@ static struct radeon_asic cayman_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &cayman_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -1649,8 +1665,6 @@ static struct radeon_asic cayman_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1724,6 +1738,7 @@ static struct radeon_asic trinity_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &cayman_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -1752,8 +1767,6 @@ static struct radeon_asic trinity_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1857,6 +1870,7 @@ static struct radeon_asic si_asic = { .get_gpu_clock_counter = &si_get_gpu_clock_counter, .gart = { .tlb_flush = &si_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -1885,8 +1899,6 @@ static struct radeon_asic si_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1939,6 +1951,10 @@ static struct radeon_asic si_asic = { .debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level, .force_performance_level = &si_dpm_force_performance_level, .vblank_too_short = &ni_dpm_vblank_too_short, + .fan_ctrl_set_mode = &si_fan_ctrl_set_mode, + .fan_ctrl_get_mode = &si_fan_ctrl_get_mode, + .get_fan_speed_percent = &si_fan_ctrl_get_fan_speed_percent, + .set_fan_speed_percent = &si_fan_ctrl_set_fan_speed_percent, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -2018,6 +2034,7 @@ static struct radeon_asic ci_asic = { .get_gpu_clock_counter = &cik_get_gpu_clock_counter, .gart = { .tlb_flush = &cik_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -2048,8 +2065,6 @@ static struct radeon_asic ci_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &cik_copy_cpdma, @@ -2104,6 +2119,10 @@ static struct radeon_asic ci_asic = { .force_performance_level = &ci_dpm_force_performance_level, .vblank_too_short = &ci_dpm_vblank_too_short, .powergate_uvd = &ci_dpm_powergate_uvd, + .fan_ctrl_set_mode = &ci_fan_ctrl_set_mode, + .fan_ctrl_get_mode = &ci_fan_ctrl_get_mode, + .get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent, + .set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -2125,6 +2144,7 @@ static struct radeon_asic kv_asic = { .get_gpu_clock_counter = &cik_get_gpu_clock_counter, .gart = { .tlb_flush = &cik_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -2155,8 +2175,6 @@ static struct radeon_asic kv_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &cik_copy_cpdma, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 2a45d548d5e..72bdd3bf0d8 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -67,8 +67,9 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); 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); +uint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags); void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring); int r100_irq_set(struct radeon_device *rdev); int r100_irq_process(struct radeon_device *rdev); @@ -172,8 +173,9 @@ extern void r300_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence); extern int r300_cs_parse(struct radeon_cs_parser *p); extern void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev); +extern uint64_t rv370_pcie_gart_get_page_entry(uint64_t addr, uint32_t flags); extern void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes); extern int rv370_get_pcie_lanes(struct radeon_device *rdev); extern void r300_set_reg_safe(struct radeon_device *rdev); @@ -208,8 +210,9 @@ extern void rs400_fini(struct radeon_device *rdev); extern int rs400_suspend(struct radeon_device *rdev); extern int rs400_resume(struct radeon_device *rdev); void rs400_gart_tlb_flush(struct radeon_device *rdev); +uint64_t rs400_gart_get_page_entry(uint64_t addr, uint32_t flags); void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); int rs400_gart_init(struct radeon_device *rdev); @@ -232,8 +235,9 @@ int rs600_irq_process(struct radeon_device *rdev); void rs600_irq_disable(struct radeon_device *rdev); u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc); void rs600_gart_tlb_flush(struct radeon_device *rdev); +uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags); void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rs600_bandwidth_update(struct radeon_device *rdev); @@ -390,7 +394,6 @@ void r600_irq_suspend(struct radeon_device *rdev); void r600_disable_interrupts(struct radeon_device *rdev); void r600_rlc_stop(struct radeon_device *rdev); /* r600 audio */ -int r600_audio_init(struct radeon_device *rdev); void r600_audio_fini(struct radeon_device *rdev); void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock); void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, @@ -399,8 +402,6 @@ void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock); void r600_hdmi_audio_workaround(struct drm_encoder *encoder); int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder); void r600_hdmi_update_audio_settings(struct drm_encoder *encoder); -void r600_hdmi_enable(struct drm_encoder *encoder, bool enable); -void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); int r600_mc_wait_for_idle(struct radeon_device *rdev); u32 r600_get_xclk(struct radeon_device *rdev); uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev); @@ -469,8 +470,6 @@ struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev, u32 rv770_get_xclk(struct radeon_device *rdev); int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); int rv770_get_temp(struct radeon_device *rdev); -/* hdmi */ -void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); /* rv7xx pm */ int rv770_dpm_init(struct radeon_device *rdev); int rv770_dpm_enable(struct radeon_device *rdev); @@ -540,8 +539,6 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, struct reservation_object *resv); -void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable); -void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); int evergreen_get_temp(struct radeon_device *rdev); int sumo_get_temp(struct radeon_device *rdev); int tn_get_temp(struct radeon_device *rdev); @@ -680,7 +677,6 @@ void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable); /* DCE6 - SI */ void dce6_bandwidth_update(struct radeon_device *rdev); -int dce6_audio_init(struct radeon_device *rdev); void dce6_audio_fini(struct radeon_device *rdev); /* @@ -744,6 +740,12 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m); int si_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); +int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, + u32 *speed); +int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, + u32 speed); +u32 si_fan_ctrl_get_mode(struct radeon_device *rdev); +void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode); /* DCE8 - CIK */ void dce8_bandwidth_update(struct radeon_device *rdev); @@ -861,6 +863,13 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev, bool ci_dpm_vblank_too_short(struct radeon_device *rdev); void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); +int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, + u32 *speed); +int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, + u32 speed); +u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev); +void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode); + int kv_dpm_init(struct radeon_device *rdev); int kv_dpm_enable(struct radeon_device *rdev); int kv_dpm_late_enable(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index dbc94f30029..fc1b3f34cf1 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -3289,6 +3289,7 @@ int radeon_atom_get_voltage_evv(struct radeon_device *rdev, args.in.ucVoltageType = VOLTAGE_TYPE_VDDC; args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE; + args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id); args.in.ulSCLKFreq = cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk); diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c new file mode 100644 index 00000000000..a3ceef6d963 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -0,0 +1,766 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Slava Grigorev <slava.grigorev@amd.com> + */ + +#include <linux/gcd.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include "radeon.h" +#include "atom.h" +#include "radeon_audio.h" + +void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, + u8 enable_mask); +void dce4_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, + u8 enable_mask); +void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, + u8 enable_mask); +u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg); +void dce6_endpoint_wreg(struct radeon_device *rdev, + u32 offset, u32 reg, u32 v); +void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count); +void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count); +void dce6_afmt_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count); +void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode); +void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode); +struct r600_audio_pin* r600_audio_get_pin(struct radeon_device *rdev); +struct r600_audio_pin* dce6_audio_get_pin(struct radeon_device *rdev); +void dce6_afmt_select_pin(struct drm_encoder *encoder); +void r600_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce3_2_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce4_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce4_dp_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce6_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce6_dp_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void r600_set_avi_packet(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size); +void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size); +void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr); +void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr); +void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr); +void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset); +void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset); +void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, + u32 offset, int bpc); +void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset); +void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset); +void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset); +void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute); +void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute); +void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute); +static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode); +static void radeon_audio_dp_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode); +void r600_hdmi_enable(struct drm_encoder *encoder, bool enable); +void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable); +void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable); +void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable); + +static const u32 pin_offsets[7] = +{ + (0x5e00 - 0x5e00), + (0x5e18 - 0x5e00), + (0x5e30 - 0x5e00), + (0x5e48 - 0x5e00), + (0x5e60 - 0x5e00), + (0x5e78 - 0x5e00), + (0x5e90 - 0x5e00), +}; + +static u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg) +{ + return RREG32(reg); +} + +static void radeon_audio_wreg(struct radeon_device *rdev, u32 offset, + u32 reg, u32 v) +{ + WREG32(reg, v); +} + +static struct radeon_audio_basic_funcs r600_funcs = { + .endpoint_rreg = radeon_audio_rreg, + .endpoint_wreg = radeon_audio_wreg, + .enable = r600_audio_enable, +}; + +static struct radeon_audio_basic_funcs dce32_funcs = { + .endpoint_rreg = radeon_audio_rreg, + .endpoint_wreg = radeon_audio_wreg, + .enable = r600_audio_enable, +}; + +static struct radeon_audio_basic_funcs dce4_funcs = { + .endpoint_rreg = radeon_audio_rreg, + .endpoint_wreg = radeon_audio_wreg, + .enable = dce4_audio_enable, +}; + +static struct radeon_audio_basic_funcs dce6_funcs = { + .endpoint_rreg = dce6_endpoint_rreg, + .endpoint_wreg = dce6_endpoint_wreg, + .enable = dce6_audio_enable, +}; + +static struct radeon_audio_funcs r600_hdmi_funcs = { + .get_pin = r600_audio_get_pin, + .set_dto = r600_hdmi_audio_set_dto, + .update_acr = r600_hdmi_update_acr, + .set_vbi_packet = r600_set_vbi_packet, + .set_avi_packet = r600_set_avi_packet, + .set_audio_packet = r600_set_audio_packet, + .set_mute = r600_set_mute, + .mode_set = radeon_audio_hdmi_mode_set, + .dpms = r600_hdmi_enable, +}; + +static struct radeon_audio_funcs dce32_hdmi_funcs = { + .get_pin = r600_audio_get_pin, + .write_sad_regs = dce3_2_afmt_write_sad_regs, + .write_speaker_allocation = dce3_2_afmt_hdmi_write_speaker_allocation, + .set_dto = dce3_2_audio_set_dto, + .update_acr = dce3_2_hdmi_update_acr, + .set_vbi_packet = r600_set_vbi_packet, + .set_avi_packet = r600_set_avi_packet, + .set_audio_packet = dce3_2_set_audio_packet, + .set_mute = dce3_2_set_mute, + .mode_set = radeon_audio_hdmi_mode_set, + .dpms = r600_hdmi_enable, +}; + +static struct radeon_audio_funcs dce32_dp_funcs = { + .get_pin = r600_audio_get_pin, + .write_sad_regs = dce3_2_afmt_write_sad_regs, + .write_speaker_allocation = dce3_2_afmt_dp_write_speaker_allocation, + .set_dto = dce3_2_audio_set_dto, + .set_avi_packet = r600_set_avi_packet, + .set_audio_packet = dce3_2_set_audio_packet, +}; + +static struct radeon_audio_funcs dce4_hdmi_funcs = { + .get_pin = r600_audio_get_pin, + .write_sad_regs = evergreen_hdmi_write_sad_regs, + .write_speaker_allocation = dce4_afmt_hdmi_write_speaker_allocation, + .write_latency_fields = dce4_afmt_write_latency_fields, + .set_dto = dce4_hdmi_audio_set_dto, + .update_acr = evergreen_hdmi_update_acr, + .set_vbi_packet = dce4_set_vbi_packet, + .set_color_depth = dce4_hdmi_set_color_depth, + .set_avi_packet = evergreen_set_avi_packet, + .set_audio_packet = dce4_set_audio_packet, + .set_mute = dce4_set_mute, + .mode_set = radeon_audio_hdmi_mode_set, + .dpms = evergreen_hdmi_enable, +}; + +static struct radeon_audio_funcs dce4_dp_funcs = { + .get_pin = r600_audio_get_pin, + .write_sad_regs = evergreen_hdmi_write_sad_regs, + .write_speaker_allocation = dce4_afmt_dp_write_speaker_allocation, + .write_latency_fields = dce4_afmt_write_latency_fields, + .set_dto = dce4_dp_audio_set_dto, + .set_avi_packet = evergreen_set_avi_packet, + .set_audio_packet = dce4_set_audio_packet, + .mode_set = radeon_audio_dp_mode_set, + .dpms = evergreen_enable_dp_audio_packets, +}; + +static struct radeon_audio_funcs dce6_hdmi_funcs = { + .select_pin = dce6_afmt_select_pin, + .get_pin = dce6_audio_get_pin, + .write_sad_regs = dce6_afmt_write_sad_regs, + .write_speaker_allocation = dce6_afmt_hdmi_write_speaker_allocation, + .write_latency_fields = dce6_afmt_write_latency_fields, + .set_dto = dce6_hdmi_audio_set_dto, + .update_acr = evergreen_hdmi_update_acr, + .set_vbi_packet = dce4_set_vbi_packet, + .set_color_depth = dce4_hdmi_set_color_depth, + .set_avi_packet = evergreen_set_avi_packet, + .set_audio_packet = dce4_set_audio_packet, + .set_mute = dce4_set_mute, + .mode_set = radeon_audio_hdmi_mode_set, + .dpms = evergreen_hdmi_enable, +}; + +static struct radeon_audio_funcs dce6_dp_funcs = { + .select_pin = dce6_afmt_select_pin, + .get_pin = dce6_audio_get_pin, + .write_sad_regs = dce6_afmt_write_sad_regs, + .write_speaker_allocation = dce6_afmt_dp_write_speaker_allocation, + .write_latency_fields = dce6_afmt_write_latency_fields, + .set_dto = dce6_dp_audio_set_dto, + .set_avi_packet = evergreen_set_avi_packet, + .set_audio_packet = dce4_set_audio_packet, + .mode_set = radeon_audio_dp_mode_set, + .dpms = dce6_enable_dp_audio_packets, +}; + +static void radeon_audio_interface_init(struct radeon_device *rdev) +{ + if (ASIC_IS_DCE6(rdev)) { + rdev->audio.funcs = &dce6_funcs; + rdev->audio.hdmi_funcs = &dce6_hdmi_funcs; + rdev->audio.dp_funcs = &dce6_dp_funcs; + } else if (ASIC_IS_DCE4(rdev)) { + rdev->audio.funcs = &dce4_funcs; + rdev->audio.hdmi_funcs = &dce4_hdmi_funcs; + rdev->audio.dp_funcs = &dce4_dp_funcs; + } else if (ASIC_IS_DCE32(rdev)) { + rdev->audio.funcs = &dce32_funcs; + rdev->audio.hdmi_funcs = &dce32_hdmi_funcs; + rdev->audio.dp_funcs = &dce32_dp_funcs; + } else { + rdev->audio.funcs = &r600_funcs; + rdev->audio.hdmi_funcs = &r600_hdmi_funcs; + rdev->audio.dp_funcs = 0; + } +} + +static int radeon_audio_chipset_supported(struct radeon_device *rdev) +{ + return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); +} + +int radeon_audio_init(struct radeon_device *rdev) +{ + int i; + + if (!radeon_audio || !radeon_audio_chipset_supported(rdev)) + return 0; + + rdev->audio.enabled = true; + + if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */ + rdev->audio.num_pins = 3; + else if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */ + rdev->audio.num_pins = 7; + else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */ + rdev->audio.num_pins = 7; + else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */ + rdev->audio.num_pins = 2; + else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */ + rdev->audio.num_pins = 6; + else if (ASIC_IS_DCE6(rdev)) /* SI: 6 streams, 6 endpoints */ + rdev->audio.num_pins = 6; + else + rdev->audio.num_pins = 1; + + for (i = 0; i < rdev->audio.num_pins; i++) { + rdev->audio.pin[i].channels = -1; + rdev->audio.pin[i].rate = -1; + rdev->audio.pin[i].bits_per_sample = -1; + rdev->audio.pin[i].status_bits = 0; + rdev->audio.pin[i].category_code = 0; + rdev->audio.pin[i].connected = false; + rdev->audio.pin[i].offset = pin_offsets[i]; + rdev->audio.pin[i].id = i; + } + + radeon_audio_interface_init(rdev); + + /* disable audio. it will be set up later */ + for (i = 0; i < rdev->audio.num_pins; i++) + radeon_audio_enable(rdev, &rdev->audio.pin[i], false); + + return 0; +} + +u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg) +{ + if (rdev->audio.funcs->endpoint_rreg) + return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg); + + return 0; +} + +void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset, + u32 reg, u32 v) +{ + if (rdev->audio.funcs->endpoint_wreg) + rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v); +} + +static void radeon_audio_write_sad_regs(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder; + struct drm_connector *connector; + struct radeon_connector *radeon_connector = NULL; + struct cea_sad *sads; + int sad_count; + + list_for_each_entry(connector, + &encoder->dev->mode_config.connector_list, head) { + if (connector->encoder == encoder) { + radeon_connector = to_radeon_connector(connector); + break; + } + } + + if (!radeon_connector) { + DRM_ERROR("Couldn't find encoder's connector\n"); + return; + } + + sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); + if (sad_count <= 0) { + DRM_ERROR("Couldn't read SADs: %d\n", sad_count); + return; + } + BUG_ON(!sads); + + radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs) + radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count); + + kfree(sads); +} + +static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector; + struct radeon_connector *radeon_connector = NULL; + u8 *sadb = NULL; + int sad_count; + + list_for_each_entry(connector, + &encoder->dev->mode_config.connector_list, head) { + if (connector->encoder == encoder) { + radeon_connector = to_radeon_connector(connector); + break; + } + } + + if (!radeon_connector) { + DRM_ERROR("Couldn't find encoder's connector\n"); + return; + } + + sad_count = drm_edid_to_speaker_allocation( + radeon_connector_edid(connector), &sadb); + if (sad_count < 0) { + DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", + sad_count); + sad_count = 0; + } + + if (radeon_encoder->audio && radeon_encoder->audio->write_speaker_allocation) + radeon_encoder->audio->write_speaker_allocation(encoder, sadb, sad_count); + + kfree(sadb); +} + +static void radeon_audio_write_latency_fields(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct radeon_encoder *radeon_encoder; + struct drm_connector *connector; + struct radeon_connector *radeon_connector = 0; + + list_for_each_entry(connector, + &encoder->dev->mode_config.connector_list, head) { + if (connector->encoder == encoder) { + radeon_connector = to_radeon_connector(connector); + break; + } + } + + if (!radeon_connector) { + DRM_ERROR("Couldn't find encoder's connector\n"); + return; + } + + radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields) + radeon_encoder->audio->write_latency_fields(encoder, connector, mode); +} + +struct r600_audio_pin* radeon_audio_get_pin(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->get_pin) + return radeon_encoder->audio->get_pin(rdev); + + return NULL; +} + +static void radeon_audio_select_pin(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->select_pin) + radeon_encoder->audio->select_pin(encoder); +} + +void radeon_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, u8 enable_mask) +{ + if (rdev->audio.funcs->enable) + rdev->audio.funcs->enable(rdev, pin, enable_mask); +} + +void radeon_audio_detect(struct drm_connector *connector, + enum drm_connector_status status) +{ + struct radeon_device *rdev; + struct radeon_encoder *radeon_encoder; + struct radeon_encoder_atom_dig *dig; + + if (!connector || !connector->encoder) + return; + + rdev = connector->encoder->dev->dev_private; + radeon_encoder = to_radeon_encoder(connector->encoder); + dig = radeon_encoder->enc_priv; + + if (status == connector_status_connected) { + struct radeon_connector *radeon_connector; + int sink_type; + + if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) { + radeon_encoder->audio = NULL; + return; + } + + radeon_connector = to_radeon_connector(connector); + sink_type = radeon_dp_getsinktype(radeon_connector); + + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort && + sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) + radeon_encoder->audio = rdev->audio.dp_funcs; + else + radeon_encoder->audio = rdev->audio.hdmi_funcs; + + radeon_audio_write_speaker_allocation(connector->encoder); + radeon_audio_write_sad_regs(connector->encoder); + if (connector->encoder->crtc) + radeon_audio_write_latency_fields(connector->encoder, + &connector->encoder->crtc->mode); + radeon_audio_enable(rdev, dig->afmt->pin, 0xf); + } else { + radeon_audio_enable(rdev, dig->afmt->pin, 0); + } +} + +void radeon_audio_fini(struct radeon_device *rdev) +{ + int i; + + if (!rdev->audio.enabled) + return; + + for (i = 0; i < rdev->audio.num_pins; i++) + radeon_audio_enable(rdev, &rdev->audio.pin[i], false); + + rdev->audio.enabled = false; +} + +static void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *crtc = to_radeon_crtc(encoder->crtc); + + if (radeon_encoder->audio && radeon_encoder->audio->set_dto) + radeon_encoder->audio->set_dto(rdev, crtc, clock); +} + +static int radeon_audio_set_avi_packet(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; + struct hdmi_avi_infoframe frame; + int err; + + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); + if (err < 0) { + DRM_ERROR("failed to setup AVI infoframe: %d\n", err); + return err; + } + + err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); + if (err < 0) { + DRM_ERROR("failed to pack AVI infoframe: %d\n", err); + return err; + } + + if (dig && dig->afmt && + radeon_encoder->audio && radeon_encoder->audio->set_avi_packet) + radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset, + buffer, sizeof(buffer)); + + return 0; +} + +/* + * calculate CTS and N values if they are not found in the table + */ +static void radeon_audio_calc_cts(unsigned int clock, int *CTS, int *N, int freq) +{ + int n, cts; + unsigned long div, mul; + + /* Safe, but overly large values */ + n = 128 * freq; + cts = clock * 1000; + + /* Smallest valid fraction */ + div = gcd(n, cts); + + n /= div; + cts /= div; + + /* + * The optimal N is 128*freq/1000. Calculate the closest larger + * value that doesn't truncate any bits. + */ + mul = ((128*freq/1000) + (n-1))/n; + + n *= mul; + cts *= mul; + + /* Check that we are in spec (not always possible) */ + if (n < (128*freq/1500)) + printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n"); + if (n > (128*freq/300)) + printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n"); + + *N = n; + *CTS = cts; + + DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n", + *N, *CTS, freq); +} + +static const struct radeon_hdmi_acr* radeon_audio_acr(unsigned int clock) +{ + static struct radeon_hdmi_acr res; + u8 i; + + static const struct radeon_hdmi_acr hdmi_predefined_acr[] = { + /* 32kHz 44.1kHz 48kHz */ + /* Clock N CTS N CTS N CTS */ + { 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */ + { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */ + { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */ + { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */ + { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */ + { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */ + { 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */ + { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */ + { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */ + { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */ + }; + + /* Precalculated values for common clocks */ + for (i = 0; i < ARRAY_SIZE(hdmi_predefined_acr); i++) + if (hdmi_predefined_acr[i].clock == clock) + return &hdmi_predefined_acr[i]; + + /* And odd clocks get manually calculated */ + radeon_audio_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000); + radeon_audio_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100); + radeon_audio_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000); + + return &res; +} + +/* + * update the N and CTS parameters for a given pixel clock rate + */ +static void radeon_audio_update_acr(struct drm_encoder *encoder, unsigned int clock) +{ + const struct radeon_hdmi_acr *acr = radeon_audio_acr(clock); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->update_acr) + radeon_encoder->audio->update_acr(encoder, dig->afmt->offset, acr); +} + +static void radeon_audio_set_vbi_packet(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->set_vbi_packet) + radeon_encoder->audio->set_vbi_packet(encoder, dig->afmt->offset); +} + +static void radeon_hdmi_set_color_depth(struct drm_encoder *encoder) +{ + int bpc = 8; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (encoder->crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + bpc = radeon_crtc->bpc; + } + + if (radeon_encoder->audio && radeon_encoder->audio->set_color_depth) + radeon_encoder->audio->set_color_depth(encoder, dig->afmt->offset, bpc); +} + +static void radeon_audio_set_audio_packet(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->set_audio_packet) + radeon_encoder->audio->set_audio_packet(encoder, dig->afmt->offset); +} + +static void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->set_mute) + radeon_encoder->audio->set_mute(encoder, dig->afmt->offset, mute); +} + +/* + * update the info frames with the data from the current display mode + */ +static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + /* disable audio prior to setting up hw */ + dig->afmt->pin = radeon_audio_get_pin(encoder); + radeon_audio_enable(rdev, dig->afmt->pin, 0); + + radeon_audio_set_dto(encoder, mode->clock); + radeon_audio_set_vbi_packet(encoder); + radeon_hdmi_set_color_depth(encoder); + radeon_audio_set_mute(encoder, false); + radeon_audio_update_acr(encoder, mode->clock); + radeon_audio_set_audio_packet(encoder); + radeon_audio_select_pin(encoder); + + if (radeon_audio_set_avi_packet(encoder, mode) < 0) + return; + + /* enable audio after to setting up hw */ + radeon_audio_enable(rdev, dig->afmt->pin, 0xf); +} + +static void radeon_audio_dp_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + /* disable audio prior to setting up hw */ + dig->afmt->pin = radeon_audio_get_pin(encoder); + radeon_audio_enable(rdev, dig->afmt->pin, 0); + + radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10); + radeon_audio_set_audio_packet(encoder); + radeon_audio_select_pin(encoder); + + if (radeon_audio_set_avi_packet(encoder, mode) < 0) + return; + + /* enable audio after to setting up hw */ + radeon_audio_enable(rdev, dig->afmt->pin, 0xf); +} + +void radeon_audio_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->mode_set) + radeon_encoder->audio->mode_set(encoder, mode); +} + +void radeon_audio_dpms(struct drm_encoder *encoder, int mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->dpms) + radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON); +} diff --git a/drivers/gpu/drm/radeon/radeon_audio.h b/drivers/gpu/drm/radeon/radeon_audio.h new file mode 100644 index 00000000000..c92d059ab20 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_audio.h @@ -0,0 +1,84 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Slava Grigorev <slava.grigorev@amd.com> + */ + +#ifndef __RADEON_AUDIO_H__ +#define __RADEON_AUDIO_H__ + +#include <linux/types.h> + +#define RREG32_ENDPOINT(block, reg) \ + radeon_audio_endpoint_rreg(rdev, (block), (reg)) +#define WREG32_ENDPOINT(block, reg, v) \ + radeon_audio_endpoint_wreg(rdev, (block), (reg), (v)) + +struct radeon_audio_basic_funcs +{ + u32 (*endpoint_rreg)(struct radeon_device *rdev, u32 offset, u32 reg); + void (*endpoint_wreg)(struct radeon_device *rdev, + u32 offset, u32 reg, u32 v); + void (*enable)(struct radeon_device *rdev, + struct r600_audio_pin *pin, u8 enable_mask); +}; + +struct radeon_audio_funcs +{ + void (*select_pin)(struct drm_encoder *encoder); + struct r600_audio_pin* (*get_pin)(struct radeon_device *rdev); + void (*write_latency_fields)(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode); + void (*write_sad_regs)(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count); + void (*write_speaker_allocation)(struct drm_encoder *encoder, + u8 *sadb, int sad_count); + void (*set_dto)(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); + void (*update_acr)(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr); + void (*set_vbi_packet)(struct drm_encoder *encoder, u32 offset); + void (*set_color_depth)(struct drm_encoder *encoder, u32 offset, int bpc); + void (*set_avi_packet)(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size); + void (*set_audio_packet)(struct drm_encoder *encoder, u32 offset); + void (*set_mute)(struct drm_encoder *encoder, u32 offset, bool mute); + void (*mode_set)(struct drm_encoder *encoder, + struct drm_display_mode *mode); + void (*dpms)(struct drm_encoder *encoder, bool mode); +}; + +int radeon_audio_init(struct radeon_device *rdev); +void radeon_audio_detect(struct drm_connector *connector, + enum drm_connector_status status); +u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, + u32 offset, u32 reg); +void radeon_audio_endpoint_wreg(struct radeon_device *rdev, + u32 offset, u32 reg, u32 v); +struct r600_audio_pin *radeon_audio_get_pin(struct drm_encoder *encoder); +void radeon_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, u8 enable_mask); +void radeon_audio_fini(struct radeon_device *rdev); +void radeon_audio_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode); +void radeon_audio_dpms(struct drm_encoder *encoder, int mode); + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 9e7f23dd14b..87d5fb21cb6 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -34,7 +34,8 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size, uint64_t saddr, uint64_t daddr, - int flag, int n) + int flag, int n, + struct reservation_object *resv) { unsigned long start_jiffies; unsigned long end_jiffies; @@ -47,12 +48,12 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size, case RADEON_BENCHMARK_COPY_DMA: fence = radeon_copy_dma(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, - NULL); + resv); break; case RADEON_BENCHMARK_COPY_BLIT: fence = radeon_copy_blit(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, - NULL); + resv); break; default: DRM_ERROR("Unknown copy method\n"); @@ -120,7 +121,8 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, if (rdev->asic->copy.dma) { time = radeon_benchmark_do_move(rdev, size, saddr, daddr, - RADEON_BENCHMARK_COPY_DMA, n); + RADEON_BENCHMARK_COPY_DMA, n, + dobj->tbo.resv); if (time < 0) goto out_cleanup; if (time > 0) @@ -130,7 +132,8 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, if (rdev->asic->copy.blit) { time = radeon_benchmark_do_move(rdev, size, saddr, daddr, - RADEON_BENCHMARK_COPY_BLIT, n); + RADEON_BENCHMARK_COPY_BLIT, n, + dobj->tbo.resv); if (time < 0) goto out_cleanup; if (time > 0) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 26baa9c05f6..27def67cb6b 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -29,6 +29,7 @@ #include <drm/drm_fb_helper.h> #include <drm/radeon_drm.h> #include "radeon.h" +#include "radeon_audio.h" #include "atom.h" #include <linux/pm_runtime.h> @@ -1332,6 +1333,9 @@ out: /* updated in get modes as well since we need to know if it's analog or digital */ radeon_connector_update_scratch_regs(connector, ret); + if (radeon_audio != 0) + radeon_audio_detect(connector, ret); + exit: pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev); @@ -1654,6 +1658,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force) } radeon_connector_update_scratch_regs(connector, ret); + + if (radeon_audio != 0) + radeon_audio_detect(connector, ret); + out: pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 0ec65168f33..bd7519fdd3f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -774,6 +774,8 @@ int radeon_dummy_page_init(struct radeon_device *rdev) rdev->dummy_page.page = NULL; return -ENOMEM; } + rdev->dummy_page.entry = radeon_gart_get_page_entry(rdev->dummy_page.addr, + RADEON_GART_PAGE_DUMMY); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 102116902a0..913fafa597a 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -960,6 +960,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && pll->flags & RADEON_PLL_USE_REF_DIV) ref_div_max = pll->reference_div; + else if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) + /* fix for problems on RS880 */ + ref_div_max = min(pll->max_ref_div, 7u); else ref_div_max = pll->max_ref_div; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 4f50fb0e3d9..5d684beb48d 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -88,9 +88,10 @@ * 2.39.0 - Add INFO query for number of active CUs * 2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting * CS to GPU on >= r600 + * 2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing support */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 40 +#define KMS_DRIVER_MINOR 41 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 29b9220ec39..ea276ff6d17 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -390,18 +390,27 @@ int radeon_fbdev_init(struct radeon_device *rdev) ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper, rdev->num_crtc, RADEONFB_CONN_LIMIT); - if (ret) { - kfree(rfbdev); - return ret; - } + if (ret) + goto free; - drm_fb_helper_single_add_all_connectors(&rfbdev->helper); + ret = drm_fb_helper_single_add_all_connectors(&rfbdev->helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(rdev->ddev); - drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); + ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); + if (ret) + goto fini; + return 0; + +fini: + drm_fb_helper_fini(&rfbdev->helper); +free: + kfree(rfbdev); + return ret; } void radeon_fbdev_fini(struct radeon_device *rdev) @@ -419,16 +428,6 @@ void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state) fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state); } -int radeon_fbdev_total_size(struct radeon_device *rdev) -{ - struct radeon_bo *robj; - int size = 0; - - robj = gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj); - size += radeon_bo_size(robj); - return size; -} - bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj) { if (robj == gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj)) diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 84146d5901a..5450fa95a47 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -165,6 +165,19 @@ int radeon_gart_table_vram_pin(struct radeon_device *rdev) radeon_bo_unpin(rdev->gart.robj); radeon_bo_unreserve(rdev->gart.robj); rdev->gart.table_addr = gpu_addr; + + if (!r) { + int i; + + /* We might have dropped some GART table updates while it wasn't + * mapped, restore all entries + */ + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + radeon_gart_set_page(rdev, i, rdev->gart.pages_entry[i]); + mb(); + radeon_gart_tlb_flush(rdev); + } + return r; } @@ -228,7 +241,6 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, unsigned t; unsigned p; int i, j; - u64 page_base; if (!rdev->gart.ready) { WARN(1, "trying to unbind memory from uninitialized GART !\n"); @@ -239,14 +251,12 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, for (i = 0; i < pages; i++, p++) { if (rdev->gart.pages[p]) { rdev->gart.pages[p] = NULL; - rdev->gart.pages_addr[p] = rdev->dummy_page.addr; - page_base = rdev->gart.pages_addr[p]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + rdev->gart.pages_entry[t] = rdev->dummy_page.entry; if (rdev->gart.ptr) { - radeon_gart_set_page(rdev, t, page_base, - RADEON_GART_PAGE_DUMMY); + radeon_gart_set_page(rdev, t, + rdev->dummy_page.entry); } - page_base += RADEON_GPU_PAGE_SIZE; } } } @@ -274,7 +284,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, { unsigned t; unsigned p; - uint64_t page_base; + uint64_t page_base, page_entry; int i, j; if (!rdev->gart.ready) { @@ -285,14 +295,15 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); for (i = 0; i < pages; i++, p++) { - rdev->gart.pages_addr[p] = dma_addr[i]; rdev->gart.pages[p] = pagelist[i]; - if (rdev->gart.ptr) { - page_base = rdev->gart.pages_addr[p]; - for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base, flags); - page_base += RADEON_GPU_PAGE_SIZE; + page_base = dma_addr[i]; + for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + page_entry = radeon_gart_get_page_entry(page_base, flags); + rdev->gart.pages_entry[t] = page_entry; + if (rdev->gart.ptr) { + radeon_gart_set_page(rdev, t, page_entry); } + page_base += RADEON_GPU_PAGE_SIZE; } } mb(); @@ -334,16 +345,15 @@ int radeon_gart_init(struct radeon_device *rdev) radeon_gart_fini(rdev); return -ENOMEM; } - rdev->gart.pages_addr = vzalloc(sizeof(dma_addr_t) * - rdev->gart.num_cpu_pages); - if (rdev->gart.pages_addr == NULL) { + rdev->gart.pages_entry = vmalloc(sizeof(uint64_t) * + rdev->gart.num_gpu_pages); + if (rdev->gart.pages_entry == NULL) { radeon_gart_fini(rdev); return -ENOMEM; } /* set GART entry to point to the dummy page by default */ - for (i = 0; i < rdev->gart.num_cpu_pages; i++) { - rdev->gart.pages_addr[i] = rdev->dummy_page.addr; - } + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + rdev->gart.pages_entry[i] = rdev->dummy_page.entry; return 0; } @@ -356,15 +366,15 @@ int radeon_gart_init(struct radeon_device *rdev) */ void radeon_gart_fini(struct radeon_device *rdev) { - if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) { + if (rdev->gart.ready) { /* unbind pages */ radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages); } rdev->gart.ready = false; vfree(rdev->gart.pages); - vfree(rdev->gart.pages_addr); + vfree(rdev->gart.pages_entry); rdev->gart.pages = NULL; - rdev->gart.pages_addr = NULL; + rdev->gart.pages_entry = NULL; radeon_dummy_page_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index fe48f229043..ac3c1310b95 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -146,7 +146,8 @@ int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri struct radeon_bo_va *bo_va; int r; - if (rdev->family < CHIP_CAYMAN) { + if ((rdev->family < CHIP_CAYMAN) || + (!rdev->accel_working)) { return 0; } @@ -176,7 +177,8 @@ void radeon_gem_object_close(struct drm_gem_object *obj, struct radeon_bo_va *bo_va; int r; - if (rdev->family < CHIP_CAYMAN) { + if ((rdev->family < CHIP_CAYMAN) || + (!rdev->accel_working)) { return; } @@ -394,10 +396,9 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, return r; } -static int radeon_mode_mmap(struct drm_file *filp, - struct drm_device *dev, - uint32_t handle, bool dumb, - uint64_t *offset_p) +int radeon_mode_dumb_mmap(struct drm_file *filp, + struct drm_device *dev, + uint32_t handle, uint64_t *offset_p) { struct drm_gem_object *gobj; struct radeon_bo *robj; @@ -406,14 +407,6 @@ static int radeon_mode_mmap(struct drm_file *filp, if (gobj == NULL) { return -ENOENT; } - - /* - * We don't allow dumb mmaps on objects created using another - * interface. - */ - WARN_ONCE(dumb && !(gobj->dumb || gobj->import_attach), - "Illegal dumb map of GPU buffer.\n"); - robj = gem_to_radeon_bo(gobj); if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) { drm_gem_object_unreference_unlocked(gobj); @@ -424,20 +417,12 @@ static int radeon_mode_mmap(struct drm_file *filp, return 0; } -int radeon_mode_dumb_mmap(struct drm_file *filp, - struct drm_device *dev, - uint32_t handle, uint64_t *offset_p) -{ - return radeon_mode_mmap(filp, dev, handle, true, offset_p); -} - int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct drm_radeon_gem_mmap *args = data; - return radeon_mode_mmap(filp, dev, args->handle, false, - &args->addr_ptr); + return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr); } int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, @@ -593,7 +578,7 @@ error_unreserve: error_free: drm_free_large(vm_bos); - if (r) + if (r && r != -ERESTARTSYS) DRM_ERROR("Couldn't update BO_VA (%d)\n", r); } @@ -763,7 +748,6 @@ int radeon_mode_dumb_create(struct drm_file *file_priv, return -ENOMEM; r = drm_gem_handle_create(file_priv, gobj, &handle); - gobj->dumb = true; /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(gobj); if (r) { diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index add62200840..9590bcd321c 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -1048,11 +1048,6 @@ struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev, return NULL; } -struct drm_encoder *radeon_best_encoder(struct drm_connector *connector) -{ - return NULL; -} - void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus, u8 slave_addr, u8 addr, diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c index 065d02068ec..061eaa9c19c 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.c +++ b/drivers/gpu/drm/radeon/radeon_kfd.c @@ -28,27 +28,30 @@ #include "cikd.h" #include "cik_reg.h" #include "radeon_kfd.h" +#include "radeon_ucode.h" +#include <linux/firmware.h> +#include "cik_structs.h" #define CIK_PIPE_PER_MEC (4) struct kgd_mem { - struct radeon_sa_bo *sa_bo; + struct radeon_bo *bo; uint64_t gpu_addr; - void *ptr; + void *cpu_ptr; }; -static int init_sa_manager(struct kgd_dev *kgd, unsigned int size); -static void fini_sa_manager(struct kgd_dev *kgd); -static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment, - enum kgd_memory_pool pool, struct kgd_mem **mem); +static int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, + void **mem_obj, uint64_t *gpu_addr, + void **cpu_ptr); -static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem); +static void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj); static uint64_t get_vmem_size(struct kgd_dev *kgd); static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd); static uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd); +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); /* * Register access functions @@ -61,42 +64,45 @@ static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, unsigned int vmid); -static int kgd_init_memory(struct kgd_dev *kgd); - static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, uint32_t hpd_size, uint64_t hpd_gpu_addr); static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, uint32_t queue_id, uint32_t __user *wptr); - -static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address, +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd); +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, uint32_t pipe_id, uint32_t queue_id); static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, unsigned int timeout, uint32_t pipe_id, uint32_t queue_id); +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd); +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout); static const struct kfd2kgd_calls kfd2kgd = { - .init_sa_manager = init_sa_manager, - .fini_sa_manager = fini_sa_manager, - .allocate_mem = allocate_mem, - .free_mem = free_mem, + .init_gtt_mem_allocation = alloc_gtt_mem, + .free_gtt_mem = free_gtt_mem, .get_vmem_size = get_vmem_size, .get_gpu_clock_counter = get_gpu_clock_counter, .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, .program_sh_mem_settings = kgd_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, - .init_memory = kgd_init_memory, .init_pipeline = kgd_init_pipeline, .hqd_load = kgd_hqd_load, - .hqd_is_occupies = kgd_hqd_is_occupies, + .hqd_sdma_load = kgd_hqd_sdma_load, + .hqd_is_occupied = kgd_hqd_is_occupied, + .hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied, .hqd_destroy = kgd_hqd_destroy, + .hqd_sdma_destroy = kgd_hqd_sdma_destroy, + .get_fw_version = get_fw_version }; static const struct kgd2kfd_calls *kgd2kfd; bool radeon_kfd_init(void) { +#if defined(CONFIG_HSA_AMD_MODULE) bool (*kgd2kfd_init_p)(unsigned, const struct kfd2kgd_calls*, const struct kgd2kfd_calls**); @@ -113,6 +119,17 @@ bool radeon_kfd_init(void) } return true; +#elif defined(CONFIG_HSA_AMD) + if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) { + kgd2kfd = NULL; + + return false; + } + + return true; +#else + return false; +#endif } void radeon_kfd_fini(void) @@ -178,87 +195,78 @@ int radeon_kfd_resume(struct radeon_device *rdev) return r; } -static u32 pool_to_domain(enum kgd_memory_pool p) -{ - switch (p) { - case KGD_POOL_FRAMEBUFFER: return RADEON_GEM_DOMAIN_VRAM; - default: return RADEON_GEM_DOMAIN_GTT; - } -} - -static int init_sa_manager(struct kgd_dev *kgd, unsigned int size) +static int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, + void **mem_obj, uint64_t *gpu_addr, + void **cpu_ptr) { struct radeon_device *rdev = (struct radeon_device *)kgd; + struct kgd_mem **mem = (struct kgd_mem **) mem_obj; int r; BUG_ON(kgd == NULL); + BUG_ON(gpu_addr == NULL); + BUG_ON(cpu_ptr == NULL); - r = radeon_sa_bo_manager_init(rdev, &rdev->kfd_bo, - size, - RADEON_GPU_PAGE_SIZE, - RADEON_GEM_DOMAIN_GTT, - RADEON_GEM_GTT_WC); + *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL); + if ((*mem) == NULL) + return -ENOMEM; - if (r) + r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, + RADEON_GEM_GTT_WC, NULL, NULL, &(*mem)->bo); + if (r) { + dev_err(rdev->dev, + "failed to allocate BO for amdkfd (%d)\n", r); return r; + } - r = radeon_sa_bo_manager_start(rdev, &rdev->kfd_bo); - if (r) - radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo); - - return r; -} - -static void fini_sa_manager(struct kgd_dev *kgd) -{ - struct radeon_device *rdev = (struct radeon_device *)kgd; - - BUG_ON(kgd == NULL); - - radeon_sa_bo_manager_suspend(rdev, &rdev->kfd_bo); - radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo); -} - -static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment, - enum kgd_memory_pool pool, struct kgd_mem **mem) -{ - struct radeon_device *rdev = (struct radeon_device *)kgd; - u32 domain; - int r; - - BUG_ON(kgd == NULL); - - domain = pool_to_domain(pool); - if (domain != RADEON_GEM_DOMAIN_GTT) { - dev_err(rdev->dev, - "Only allowed to allocate gart memory for kfd\n"); - return -EINVAL; + /* map the buffer */ + r = radeon_bo_reserve((*mem)->bo, true); + if (r) { + dev_err(rdev->dev, "(%d) failed to reserve bo for amdkfd\n", r); + goto allocate_mem_reserve_bo_failed; } - *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL); - if ((*mem) == NULL) - return -ENOMEM; + r = radeon_bo_pin((*mem)->bo, RADEON_GEM_DOMAIN_GTT, + &(*mem)->gpu_addr); + if (r) { + dev_err(rdev->dev, "(%d) failed to pin bo for amdkfd\n", r); + goto allocate_mem_pin_bo_failed; + } + *gpu_addr = (*mem)->gpu_addr; - r = radeon_sa_bo_new(rdev, &rdev->kfd_bo, &(*mem)->sa_bo, size, - alignment); + r = radeon_bo_kmap((*mem)->bo, &(*mem)->cpu_ptr); if (r) { - dev_err(rdev->dev, "failed to get memory for kfd (%d)\n", r); - return r; + dev_err(rdev->dev, + "(%d) failed to map bo to kernel for amdkfd\n", r); + goto allocate_mem_kmap_bo_failed; } + *cpu_ptr = (*mem)->cpu_ptr; - (*mem)->ptr = radeon_sa_bo_cpu_addr((*mem)->sa_bo); - (*mem)->gpu_addr = radeon_sa_bo_gpu_addr((*mem)->sa_bo); + radeon_bo_unreserve((*mem)->bo); return 0; + +allocate_mem_kmap_bo_failed: + radeon_bo_unpin((*mem)->bo); +allocate_mem_pin_bo_failed: + radeon_bo_unreserve((*mem)->bo); +allocate_mem_reserve_bo_failed: + radeon_bo_unref(&(*mem)->bo); + + return r; } -static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem) +static void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj) { - struct radeon_device *rdev = (struct radeon_device *)kgd; + struct kgd_mem *mem = (struct kgd_mem *) mem_obj; - BUG_ON(kgd == NULL); + BUG_ON(mem == NULL); - radeon_sa_bo_free(rdev, &mem->sa_bo, NULL); + radeon_bo_reserve(mem->bo, true); + radeon_bo_kunmap(mem->bo); + radeon_bo_unpin(mem->bo); + radeon_bo_unreserve(mem->bo); + radeon_bo_unref(&(mem->bo)); kfree(mem); } @@ -374,41 +382,9 @@ static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, cpu_relax(); write_register(kgd, ATC_VMID_PASID_MAPPING_UPDATE_STATUS, 1U << vmid); - return 0; -} - -static int kgd_init_memory(struct kgd_dev *kgd) -{ - /* - * Configure apertures: - * LDS: 0x60000000'00000000 - 0x60000001'00000000 (4GB) - * Scratch: 0x60000001'00000000 - 0x60000002'00000000 (4GB) - * GPUVM: 0x60010000'00000000 - 0x60020000'00000000 (1TB) - */ - int i; - uint32_t sh_mem_bases = PRIVATE_BASE(0x6000) | SHARED_BASE(0x6000); - - for (i = 8; i < 16; i++) { - uint32_t sh_mem_config; - - lock_srbm(kgd, 0, 0, 0, i); - - sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED); - sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED); - - write_register(kgd, SH_MEM_CONFIG, sh_mem_config); - - write_register(kgd, SH_MEM_BASES, sh_mem_bases); - - /* Scratch aperture is not supported for now. */ - write_register(kgd, SH_STATIC_MEM_CONFIG, 0); - - /* APE1 disabled for now. */ - write_register(kgd, SH_MEM_APE1_BASE, 1); - write_register(kgd, SH_MEM_APE1_LIMIT, 0); - - unlock_srbm(kgd); - } + /* Mapping vmid to pasid also for IH block */ + write_register(kgd, IH_VMID_0_LUT + vmid * sizeof(uint32_t), + pasid_mapping); return 0; } @@ -416,7 +392,7 @@ static int kgd_init_memory(struct kgd_dev *kgd) static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, uint32_t hpd_size, uint64_t hpd_gpu_addr) { - uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1; + uint32_t mec = (pipe_id / CIK_PIPE_PER_MEC) + 1; uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC); lock_srbm(kgd, mec, pipe, 0, 0); @@ -431,11 +407,28 @@ static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, return 0; } +static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m) +{ + uint32_t retval; + + retval = m->sdma_engine_id * SDMA1_REGISTER_OFFSET + + m->sdma_queue_id * KFD_CIK_SDMA_QUEUE_OFFSET; + + pr_debug("kfd: sdma base address: 0x%x\n", retval); + + return retval; +} + static inline struct cik_mqd *get_mqd(void *mqd) { return (struct cik_mqd *)mqd; } +static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) +{ + return (struct cik_sdma_rlc_registers *)mqd; +} + static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, uint32_t queue_id, uint32_t __user *wptr) { @@ -513,7 +506,46 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, return 0; } -static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address, +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd) +{ + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + write_register(kgd, + sdma_base_addr + SDMA0_RLC0_VIRTUAL_ADDR, + m->sdma_rlc_virtual_addr); + + write_register(kgd, + sdma_base_addr + SDMA0_RLC0_RB_BASE, + m->sdma_rlc_rb_base); + + write_register(kgd, + sdma_base_addr + SDMA0_RLC0_RB_BASE_HI, + m->sdma_rlc_rb_base_hi); + + write_register(kgd, + sdma_base_addr + SDMA0_RLC0_RB_RPTR_ADDR_LO, + m->sdma_rlc_rb_rptr_addr_lo); + + write_register(kgd, + sdma_base_addr + SDMA0_RLC0_RB_RPTR_ADDR_HI, + m->sdma_rlc_rb_rptr_addr_hi); + + write_register(kgd, + sdma_base_addr + SDMA0_RLC0_DOORBELL, + m->sdma_rlc_doorbell); + + write_register(kgd, + sdma_base_addr + SDMA0_RLC0_RB_CNTL, + m->sdma_rlc_rb_cntl); + + return 0; +} + +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, uint32_t pipe_id, uint32_t queue_id) { uint32_t act; @@ -534,6 +566,24 @@ static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address, return retval; } +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd) +{ + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t sdma_rlc_rb_cntl; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + sdma_rlc_rb_cntl = read_register(kgd, + sdma_base_addr + SDMA0_RLC0_RB_CNTL); + + if (sdma_rlc_rb_cntl & SDMA_RB_ENABLE) + return true; + + return false; +} + static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, unsigned int timeout, uint32_t pipe_id, uint32_t queue_id) @@ -552,6 +602,7 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, if (timeout == 0) { pr_err("kfd: cp queue preemption time out (%dms)\n", temp); + release_queue(kgd); return -ETIME; } msleep(20); @@ -561,3 +612,85 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, release_queue(kgd); return 0; } + +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout) +{ + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t temp; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + temp = read_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_CNTL); + temp = temp & ~SDMA_RB_ENABLE; + write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_CNTL, temp); + + while (true) { + temp = read_register(kgd, sdma_base_addr + + SDMA0_RLC0_CONTEXT_STATUS); + if (temp & SDMA_RLC_IDLE) + break; + if (timeout == 0) + return -ETIME; + msleep(20); + timeout -= 20; + } + + write_register(kgd, sdma_base_addr + SDMA0_RLC0_DOORBELL, 0); + write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_RPTR, 0); + write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_WPTR, 0); + write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_BASE, 0); + + return 0; +} + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) +{ + struct radeon_device *rdev = (struct radeon_device *) kgd; + const union radeon_firmware_header *hdr; + + BUG_ON(kgd == NULL || rdev->mec_fw == NULL); + + switch (type) { + case KGD_ENGINE_PFP: + hdr = (const union radeon_firmware_header *) rdev->pfp_fw->data; + break; + + case KGD_ENGINE_ME: + hdr = (const union radeon_firmware_header *) rdev->me_fw->data; + break; + + case KGD_ENGINE_CE: + hdr = (const union radeon_firmware_header *) rdev->ce_fw->data; + break; + + case KGD_ENGINE_MEC1: + hdr = (const union radeon_firmware_header *) rdev->mec_fw->data; + break; + + case KGD_ENGINE_MEC2: + hdr = (const union radeon_firmware_header *) + rdev->mec2_fw->data; + break; + + case KGD_ENGINE_RLC: + hdr = (const union radeon_firmware_header *) rdev->rlc_fw->data; + break; + + case KGD_ENGINE_SDMA: + hdr = (const union radeon_firmware_header *) + rdev->sdma_fw->data; + break; + + default: + return 0; + } + + if (hdr == NULL) + return 0; + + /* Only 12 bit in use*/ + return hdr->common.ucode_version; +} diff --git a/drivers/gpu/drm/radeon/radeon_kfd.h b/drivers/gpu/drm/radeon/radeon_kfd.h index f90e161ca50..1103f9082f6 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.h +++ b/drivers/gpu/drm/radeon/radeon_kfd.h @@ -29,7 +29,7 @@ #define RADEON_KFD_H_INCLUDED #include <linux/types.h> -#include "../amd/include/kgd_kfd_interface.h" +#include "kgd_kfd_interface.h" struct radeon_device; diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 3cf9c1fa647..686411e4e4f 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -605,14 +605,14 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) return -ENOMEM; } - vm = &fpriv->vm; - r = radeon_vm_init(rdev, vm); - if (r) { - kfree(fpriv); - return r; - } - if (rdev->accel_working) { + vm = &fpriv->vm; + r = radeon_vm_init(rdev, vm); + if (r) { + kfree(fpriv); + return r; + } + r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); if (r) { radeon_vm_fini(rdev, vm); @@ -668,9 +668,9 @@ void radeon_driver_postclose_kms(struct drm_device *dev, radeon_vm_bo_rmv(rdev, vm->ib_bo_va); radeon_bo_unreserve(rdev->ring_tmp_bo.bo); } + radeon_vm_fini(rdev, vm); } - radeon_vm_fini(rdev, vm); kfree(fpriv); file_priv->driver_priv = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 390db897f32..920a8be8aba 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -449,6 +449,7 @@ struct radeon_encoder { int audio_polling_active; bool is_ext_encoder; u16 caps; + struct radeon_audio_funcs *audio; }; struct radeon_connector_atom_dig { @@ -745,8 +746,6 @@ extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connec extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux); -extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); - extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev, struct radeon_atom_ss *ss, int id); @@ -925,7 +924,6 @@ void dce8_program_fmt(struct drm_encoder *encoder); int radeon_fbdev_init(struct radeon_device *rdev); void radeon_fbdev_fini(struct radeon_device *rdev); void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state); -int radeon_fbdev_total_size(struct radeon_device *rdev); bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); void radeon_fb_output_poll_changed(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 7d68223eb46..43e09942823 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -238,6 +238,18 @@ int radeon_bo_create(struct radeon_device *rdev, * See https://bugs.freedesktop.org/show_bug.cgi?id=84627 */ bo->flags &= ~RADEON_GEM_GTT_WC; +#elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT) + /* Don't try to enable write-combining when it can't work, or things + * may be slow + * See https://bugs.freedesktop.org/show_bug.cgi?id=88758 + */ + +#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ + thanks to write-combining + + DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " + "better performance thanks to write-combining\n"); + bo->flags &= ~RADEON_GEM_GTT_WC; #endif radeon_ttm_placement_from_domain(bo, domain); @@ -529,9 +541,6 @@ int radeon_bo_list_validate(struct radeon_device *rdev, u32 current_domain = radeon_mem_type_to_domain(bo->tbo.mem.mem_type); - WARN_ONCE(bo->gem_base.dumb, - "GPU use of dumb buffer is illegal.\n"); - /* Check if this buffer will be moved and don't move it * if we have moved too many buffers for this IB already. * @@ -579,12 +588,6 @@ int radeon_bo_list_validate(struct radeon_device *rdev, return 0; } -int radeon_bo_fbdev_mmap(struct radeon_bo *bo, - struct vm_area_struct *vma) -{ - return ttm_fbdev_mmap(vma, &bo->tbo); -} - int radeon_bo_get_surface_reg(struct radeon_bo *bo) { struct radeon_device *rdev = bo->rdev; diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 3b0b377f76c..d8d295ee7c1 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -143,8 +143,6 @@ extern void radeon_bo_fini(struct radeon_device *rdev); extern int radeon_bo_list_validate(struct radeon_device *rdev, struct ww_acquire_ctx *ticket, struct list_head *head, int ring); -extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, - struct vm_area_struct *vma); extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, u32 tiling_flags, u32 pitch); extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 32522cc940a..9f758d39420 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -24,6 +24,7 @@ #include "radeon.h" #include "avivod.h" #include "atom.h" +#include "r600_dpm.h" #include <linux/power_supply.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> @@ -554,6 +555,100 @@ fail: return count; } +static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + u32 pwm_mode = 0; + + if (rdev->asic->dpm.fan_ctrl_get_mode) + pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev); + + /* never 0 (full-speed), fuse or smc-controlled always */ + return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2); +} + +static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + int value; + + if(!rdev->asic->dpm.fan_ctrl_set_mode) + return -EINVAL; + + err = kstrtoint(buf, 10, &value); + if (err) + return err; + + switch (value) { + case 1: /* manual, percent-based */ + rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC); + break; + default: /* disable */ + rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0); + break; + } + + return count; +} + +static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%i\n", 0); +} + +static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%i\n", 255); +} + +static ssize_t radeon_hwmon_set_pwm1(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + u32 value; + + err = kstrtou32(buf, 10, &value); + if (err) + return err; + + value = (value * 100) / 255; + + err = rdev->asic->dpm.set_fan_speed_percent(rdev, value); + if (err) + return err; + + return count; +} + +static ssize_t radeon_hwmon_get_pwm1(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + u32 speed; + + err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed); + if (err) + return err; + + speed = (speed * 255) / 100; + + return sprintf(buf, "%i\n", speed); +} + 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 DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state); @@ -601,11 +696,20 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev, static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0); +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0); +static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0); +static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0); + static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_min.dev_attr.attr, + &sensor_dev_attr_pwm1_max.dev_attr.attr, NULL }; @@ -614,6 +718,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct radeon_device *rdev = dev_get_drvdata(dev); + umode_t effective_mode = attr->mode; /* Skip limit attributes if DPM is not enabled */ if (rdev->pm.pm_method != PM_METHOD_DPM && @@ -621,7 +726,35 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)) return 0; - return attr->mode; + /* Skip fan attributes if fan is not present */ + if (rdev->pm.no_fan && + (attr == &sensor_dev_attr_pwm1.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) + return 0; + + /* mask fan attributes if we have no bindings for this asic to expose */ + if ((!rdev->asic->dpm.get_fan_speed_percent && + attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */ + (!rdev->asic->dpm.fan_ctrl_get_mode && + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */ + effective_mode &= ~S_IRUGO; + + if ((!rdev->asic->dpm.set_fan_speed_percent && + attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */ + (!rdev->asic->dpm.fan_ctrl_set_mode && + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */ + effective_mode &= ~S_IWUSR; + + /* hide max/min values if we can't both query and manage the fan */ + if ((!rdev->asic->dpm.set_fan_speed_percent && + !rdev->asic->dpm.get_fan_speed_percent) && + (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) + return 0; + + return effective_mode; } static const struct attribute_group hwmon_attrgroup = { @@ -1287,8 +1420,39 @@ dpm_failed: return ret; } +struct radeon_dpm_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; +}; + +/* cards with dpm stability problems */ +static struct radeon_dpm_quirk radeon_dpm_quirk_list[] = { + /* TURKS - https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1386534 */ + { PCI_VENDOR_ID_ATI, 0x6759, 0x1682, 0x3195 }, + /* TURKS - https://bugzilla.kernel.org/show_bug.cgi?id=83731 */ + { PCI_VENDOR_ID_ATI, 0x6840, 0x1179, 0xfb81 }, + { 0, 0, 0, 0 }, +}; + int radeon_pm_init(struct radeon_device *rdev) { + struct radeon_dpm_quirk *p = radeon_dpm_quirk_list; + bool disable_dpm = false; + + /* Apply dpm quirks */ + while (p && p->chip_device != 0) { + if (rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + disable_dpm = true; + break; + } + ++p; + } + /* enable dpm on rv6xx+ */ switch (rdev->family) { case CHIP_RV610: @@ -1344,6 +1508,8 @@ int radeon_pm_init(struct radeon_device *rdev) (!(rdev->flags & RADEON_IS_IGP)) && (!rdev->smc_fw)) rdev->pm.pm_method = PM_METHOD_PROFILE; + else if (disable_dpm && (radeon_dpm == -1)) + rdev->pm.pm_method = PM_METHOD_PROFILE; else if (radeon_dpm == 0) rdev->pm.pm_method = PM_METHOD_PROFILE; else diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 535403e0c8a..15aee723db7 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -1703,7 +1703,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev, u32 format; u32 *buffer; const u8 __user *data; - int size, dwords, tex_width, blit_width, spitch; + unsigned int size, dwords, tex_width, blit_width, spitch; u32 height; int i; u32 texpitch, microtile; diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 07b506b4100..791818165c7 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -119,11 +119,11 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) if (ring == R600_RING_TYPE_DMA_INDEX) fence = radeon_copy_dma(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, - NULL); + vram_obj->tbo.resv); else fence = radeon_copy_blit(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, - NULL); + vram_obj->tbo.resv); if (IS_ERR(fence)) { DRM_ERROR("Failed GTT->VRAM copy %d\n", i); r = PTR_ERR(fence); @@ -170,11 +170,11 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) if (ring == R600_RING_TYPE_DMA_INDEX) fence = radeon_copy_dma(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, - NULL); + vram_obj->tbo.resv); else fence = radeon_copy_blit(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, - NULL); + vram_obj->tbo.resv); if (IS_ERR(fence)) { DRM_ERROR("Failed VRAM->GTT copy %d\n", i); r = PTR_ERR(fence); diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index cde48c42b30..2a5a4a9e772 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -587,10 +587,8 @@ uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr) uint64_t result; /* page table offset */ - result = rdev->gart.pages_addr[addr >> PAGE_SHIFT]; - - /* in case cpu page size != gpu page size*/ - result |= addr & (~PAGE_MASK); + result = rdev->gart.pages_entry[addr >> RADEON_GPU_PAGE_SHIFT]; + result &= ~RADEON_GPU_PAGE_MASK; return result; } @@ -745,9 +743,11 @@ static void radeon_vm_frag_ptes(struct radeon_device *rdev, */ /* NI is optimized for 256KB fragments, SI and newer for 64KB */ - uint64_t frag_flags = rdev->family == CHIP_CAYMAN ? + uint64_t frag_flags = ((rdev->family == CHIP_CAYMAN) || + (rdev->family == CHIP_ARUBA)) ? R600_PTE_FRAG_256KB : R600_PTE_FRAG_64KB; - uint64_t frag_align = rdev->family == CHIP_CAYMAN ? 0x200 : 0x80; + uint64_t frag_align = ((rdev->family == CHIP_CAYMAN) || + (rdev->family == CHIP_ARUBA)) ? 0x200 : 0x80; uint64_t frag_start = ALIGN(pe_start, frag_align); uint64_t frag_end = pe_end & ~(frag_align - 1); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index c5799f16aa4..34e3235f41d 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -212,11 +212,9 @@ void rs400_gart_fini(struct radeon_device *rdev) #define RS400_PTE_WRITEABLE (1 << 2) #define RS400_PTE_READABLE (1 << 3) -void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) +uint64_t rs400_gart_get_page_entry(uint64_t addr, uint32_t flags) { uint32_t entry; - u32 *gtt = rdev->gart.ptr; entry = (lower_32_bits(addr) & PAGE_MASK) | ((upper_32_bits(addr) & 0xff) << 4); @@ -226,8 +224,14 @@ void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, entry |= RS400_PTE_WRITEABLE; if (!(flags & RADEON_GART_PAGE_SNOOP)) entry |= RS400_PTE_UNSNOOPED; - entry = cpu_to_le32(entry); - gtt[i] = entry; + return entry; +} + +void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) +{ + u32 *gtt = rdev->gart.ptr; + gtt[i] = cpu_to_le32(lower_32_bits(entry)); } int rs400_mc_wait_for_idle(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 9acb1c3c005..d81182ad53e 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -38,6 +38,7 @@ #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "atom.h" #include "rs600d.h" @@ -625,11 +626,8 @@ static void rs600_gart_fini(struct radeon_device *rdev) radeon_gart_table_vram_free(rdev); } -void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) +uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags) { - void __iomem *ptr = (void *)rdev->gart.ptr; - addr = addr & 0xFFFFFFFFFFFFF000ULL; addr |= R600_PTE_SYSTEM; if (flags & RADEON_GART_PAGE_VALID) @@ -640,7 +638,14 @@ void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, addr |= R600_PTE_WRITEABLE; if (flags & RADEON_GART_PAGE_SNOOP) addr |= R600_PTE_SNOOPED; - writeq(addr, ptr + (i * 8)); + return addr; +} + +void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) +{ + void __iomem *ptr = (void *)rdev->gart.ptr; + writeq(entry, ptr + (i * 8)); } int rs600_irq_set(struct radeon_device *rdev) @@ -1012,7 +1017,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; @@ -1053,7 +1058,7 @@ int rs600_resume(struct radeon_device *rdev) int rs600_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); rs600_irq_disable(rdev); @@ -1064,7 +1069,7 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 0a2d36e8110..516ca27cfa1 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -28,6 +28,7 @@ #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "atom.h" #include "rs690d.h" @@ -729,7 +730,7 @@ static int rs690_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; @@ -770,7 +771,7 @@ int rs690_resume(struct radeon_device *rdev) int rs690_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); rs600_irq_disable(rdev); @@ -781,7 +782,7 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 372016e266d..01ee96acb39 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -30,6 +30,7 @@ #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include <drm/radeon_drm.h> #include "rv770d.h" #include "atom.h" @@ -1788,7 +1789,7 @@ static int rv770_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { DRM_ERROR("radeon: audio init failed\n"); return r; @@ -1829,7 +1830,7 @@ int rv770_resume(struct radeon_device *rdev) int rv770_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_suspend(rdev); r700_cp_stop(rdev); diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 755a8f96fe4..306732641b2 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -231,6 +231,7 @@ u8 rv770_get_seq_value(struct radeon_device *rdev, MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1; } +#if 0 int rv770_read_smc_soft_register(struct radeon_device *rdev, u16 reg_offset, u32 *value) { @@ -240,6 +241,7 @@ int rv770_read_smc_soft_register(struct radeon_device *rdev, pi->soft_regs_start + reg_offset, value, pi->sram_end); } +#endif int rv770_write_smc_soft_register(struct radeon_device *rdev, u16 reg_offset, u32 value) @@ -2075,6 +2077,7 @@ int rv770_dpm_set_power_state(struct radeon_device *rdev) return 0; } +#if 0 void rv770_dpm_reset_asic(struct radeon_device *rdev) { struct rv7xx_power_info *pi = rv770_get_pi(rdev); @@ -2087,6 +2090,7 @@ void rv770_dpm_reset_asic(struct radeon_device *rdev) if (pi->dcodt) rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps); } +#endif void rv770_dpm_setup_asic(struct radeon_device *rdev) { diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h index f776634840c..d12beab7f3e 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.h +++ b/drivers/gpu/drm/radeon/rv770_dpm.h @@ -278,8 +278,6 @@ void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, void rv770_get_engine_memory_ss(struct radeon_device *rdev); /* smc */ -int rv770_read_smc_soft_register(struct radeon_device *rdev, - u16 reg_offset, u32 *value); int rv770_write_smc_soft_register(struct radeon_device *rdev, u16 reg_offset, u32 value); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 60df444bd07..73107fe9e46 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -27,6 +27,7 @@ #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include <drm/radeon_drm.h> #include "sid.h" #include "atom.h" @@ -5057,6 +5058,16 @@ void si_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, 0); radeon_ring_write(ring, 1 << vm_id); + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ + /* sync PFP to ME, otherwise we might get invalid PFP reads */ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); radeon_ring_write(ring, 0x0); @@ -6859,7 +6870,7 @@ static int si_startup(struct radeon_device *rdev) return r; } - r = dce6_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) return r; @@ -6898,7 +6909,7 @@ int si_resume(struct radeon_device *rdev) int si_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - dce6_audio_fini(rdev); + radeon_audio_fini(rdev); radeon_vm_manager_fini(rdev); si_cp_enable(rdev, false); cayman_dma_stop(rdev); diff --git a/drivers/gpu/drm/radeon/si_dma.c b/drivers/gpu/drm/radeon/si_dma.c index f5cc777e1c5..83207929fc6 100644 --- a/drivers/gpu/drm/radeon/si_dma.c +++ b/drivers/gpu/drm/radeon/si_dma.c @@ -123,7 +123,6 @@ void si_dma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -206,6 +205,14 @@ void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); radeon_ring_write(ring, 1 << vm_id); + + /* wait for invalidate to complete */ + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0)); + radeon_ring_write(ring, VM_INVALIDATE_REQUEST); + radeon_ring_write(ring, 0xff << 16); /* retry */ + radeon_ring_write(ring, 1 << vm_id); /* mask */ + radeon_ring_write(ring, 0); /* value */ + radeon_ring_write(ring, (0 << 28) | 0x20); /* func(always) | poll interval */ } /** diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 32e354b8b0a..7be11651b7e 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1756,6 +1756,9 @@ static int si_calculate_sclk_params(struct radeon_device *rdev, u32 engine_clock, SISLANDS_SMC_SCLK_VALUE *sclk); +static void si_thermal_start_smc_fan_control(struct radeon_device *rdev); +static void si_fan_ctrl_set_default_mode(struct radeon_device *rdev); + static struct si_power_info *si_get_pi(struct radeon_device *rdev) { struct si_power_info *pi = rdev->pm.dpm.priv; @@ -2908,6 +2911,22 @@ static int si_init_smc_spll_table(struct radeon_device *rdev) return ret; } +struct si_dpm_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; + u32 max_sclk; + u32 max_mclk; +}; + +/* cards with dpm stability problems */ +static struct si_dpm_quirk si_dpm_quirk_list[] = { + /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */ + { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 }, + { 0, 0, 0, 0 }, +}; + static void si_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_ps *rps) { @@ -2918,7 +2937,22 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, u32 mclk, sclk; u16 vddc, vddci; u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; + u32 max_sclk = 0, max_mclk = 0; int i; + struct si_dpm_quirk *p = si_dpm_quirk_list; + + /* Apply dpm quirks */ + while (p && p->chip_device != 0) { + if (rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + max_sclk = p->max_sclk; + max_mclk = p->max_mclk; + break; + } + ++p; + } if ((rdev->pm.dpm.new_active_crtc_count > 1) || ni_dpm_vblank_too_short(rdev)) @@ -2972,6 +3006,14 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, if (ps->performance_levels[i].mclk > max_mclk_vddc) ps->performance_levels[i].mclk = max_mclk_vddc; } + if (max_mclk) { + if (ps->performance_levels[i].mclk > max_mclk) + ps->performance_levels[i].mclk = max_mclk; + } + if (max_sclk) { + if (ps->performance_levels[i].sclk > max_sclk) + ps->performance_levels[i].sclk = max_sclk; + } } /* XXX validate the min clocks required for display */ @@ -3320,11 +3362,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev, return 0; } +#if 0 static int si_set_boot_state(struct radeon_device *rdev) { return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ? 0 : -EINVAL; } +#endif static int si_set_sw_state(struct radeon_device *rdev) { @@ -5934,6 +5978,10 @@ static int si_thermal_setup_fan_table(struct radeon_device *rdev) slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); + fan_table.temp_min = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100); + fan_table.temp_med = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100); + fan_table.temp_max = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100); + fan_table.slope1 = cpu_to_be16(slope1); fan_table.slope2 = cpu_to_be16(slope2); @@ -5973,29 +6021,35 @@ static int si_thermal_setup_fan_table(struct radeon_device *rdev) static int si_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev) { + struct si_power_info *si_pi = si_get_pi(rdev); PPSMC_Result ret; ret = si_send_msg_to_smc(rdev, PPSMC_StartFanControl); - if (ret == PPSMC_Result_OK) + if (ret == PPSMC_Result_OK) { + si_pi->fan_is_controlled_by_smc = true; return 0; - else + } else { return -EINVAL; + } } static int si_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev) { + struct si_power_info *si_pi = si_get_pi(rdev); PPSMC_Result ret; ret = si_send_msg_to_smc(rdev, PPSMC_StopFanControl); - if (ret == PPSMC_Result_OK) + + if (ret == PPSMC_Result_OK) { + si_pi->fan_is_controlled_by_smc = false; return 0; - else + } else { return -EINVAL; + } } -#if 0 -static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, - u32 *speed) +int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, + u32 *speed) { u32 duty, duty100; u64 tmp64; @@ -6019,9 +6073,10 @@ static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, return 0; } -static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, - u32 speed) +int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, + u32 speed) { + struct si_power_info *si_pi = si_get_pi(rdev); u32 tmp; u32 duty, duty100; u64 tmp64; @@ -6029,11 +6084,11 @@ static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, if (rdev->pm.no_fan) return -ENOENT; - if (speed > 100) + if (si_pi->fan_is_controlled_by_smc) return -EINVAL; - if (rdev->pm.dpm.fan.ucode_fan_control) - si_fan_ctrl_stop_smc_fan_control(rdev); + if (speed > 100) + return -EINVAL; duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; @@ -6048,11 +6103,38 @@ static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, tmp |= FDO_STATIC_DUTY(duty); WREG32(CG_FDO_CTRL0, tmp); - si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC); - return 0; } +void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode) +{ + if (mode) { + /* stop auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + si_fan_ctrl_stop_smc_fan_control(rdev); + si_fan_ctrl_set_static_mode(rdev, mode); + } else { + /* restart auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + si_thermal_start_smc_fan_control(rdev); + else + si_fan_ctrl_set_default_mode(rdev); + } +} + +u32 si_fan_ctrl_get_mode(struct radeon_device *rdev) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + u32 tmp; + + if (si_pi->fan_is_controlled_by_smc) + return 0; + + tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK; + return (tmp >> FDO_PWM_MODE_SHIFT); +} + +#if 0 static int si_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev, u32 *speed) { @@ -6499,13 +6581,14 @@ void si_dpm_post_set_power_state(struct radeon_device *rdev) ni_update_current_ps(rdev, new_ps); } - +#if 0 void si_dpm_reset_asic(struct radeon_device *rdev) { si_restrict_performance_levels_before_switch(rdev); si_disable_ulv(rdev); si_set_boot_state(rdev); } +#endif void si_dpm_display_configuration_changed(struct radeon_device *rdev) { @@ -6873,7 +6956,6 @@ int si_dpm_init(struct radeon_device *rdev) rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; si_pi->fan_ctrl_is_in_default_mode = true; - rdev->pm.dpm.fan.ucode_fan_control = false; return 0; } diff --git a/drivers/gpu/drm/radeon/si_dpm.h b/drivers/gpu/drm/radeon/si_dpm.h index d16bb1b5f10..1032a68be79 100644 --- a/drivers/gpu/drm/radeon/si_dpm.h +++ b/drivers/gpu/drm/radeon/si_dpm.h @@ -202,6 +202,7 @@ struct si_power_info { bool fan_ctrl_is_in_default_mode; u32 t_min; u32 fan_ctrl_default_mode; + bool fan_is_controlled_by_smc; }; #define SISLANDS_INITIAL_STATE_ARB_INDEX 0 diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 4069be89e58..cbd91d226f3 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -901,6 +901,16 @@ /* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */ #define CRTC_STATUS_FRAME_COUNT 0x6e98 +/* Audio clocks */ +#define DCCG_AUDIO_DTO_SOURCE 0x05ac +# define DCCG_AUDIO_DTO0_SOURCE_SEL(x) ((x) << 0) /* crtc0 - crtc5 */ +# define DCCG_AUDIO_DTO_SEL (1 << 4) /* 0=dto0 1=dto1 */ + +#define DCCG_AUDIO_DTO0_PHASE 0x05b0 +#define DCCG_AUDIO_DTO0_MODULE 0x05b4 +#define DCCG_AUDIO_DTO1_PHASE 0x05b8 +#define DCCG_AUDIO_DTO1_MODULE 0x05bc + #define AFMT_AUDIO_SRC_CONTROL 0x713c #define AFMT_AUDIO_SRC_SELECT(x) (((x) & 7) << 0) /* AFMT_AUDIO_SRC_SELECT @@ -1632,6 +1642,23 @@ #define PACKET3_MPEG_INDEX 0x3A #define PACKET3_COPY_DW 0x3B #define PACKET3_WAIT_REG_MEM 0x3C +#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) + /* 0 - always + * 1 - < + * 2 - <= + * 3 - == + * 4 - != + * 5 - >= + * 6 - > + */ +#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) + /* 0 - reg + * 1 - mem + */ +#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) + /* 0 - me + * 1 - pfp + */ #define PACKET3_MEM_WRITE 0x3D #define PACKET3_COPY_DATA 0x40 #define PACKET3_CP_DMA 0x41 @@ -1835,6 +1862,7 @@ #define DMA_PACKET_TRAP 0x7 #define DMA_PACKET_SRBM_WRITE 0x9 #define DMA_PACKET_CONSTANT_FILL 0xd +#define DMA_PACKET_POLL_REG_MEM 0xe #define DMA_PACKET_NOP 0xf #define VCE_STATUS 0x20004 diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index 1f8a8833e1b..25fd4ced36c 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -1338,6 +1338,7 @@ void sumo_dpm_post_set_power_state(struct radeon_device *rdev) sumo_update_current_ps(rdev, new_ps); } +#if 0 void sumo_dpm_reset_asic(struct radeon_device *rdev) { sumo_program_bootup_state(rdev); @@ -1349,6 +1350,7 @@ void sumo_dpm_reset_asic(struct radeon_device *rdev) sumo_set_forced_mode_enabled(rdev); sumo_set_forced_mode_disabled(rdev); } +#endif void sumo_dpm_setup_asic(struct radeon_device *rdev) { @@ -1537,6 +1539,7 @@ u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev, return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit; } +#if 0 u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev, struct sumo_vid_mapping_table *vid_mapping_table, u32 vid_7bit) @@ -1550,6 +1553,7 @@ u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev, return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit; } +#endif static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev, u32 vid_2bit) diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h index db1ea32a907..07dda299c78 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.h +++ b/drivers/gpu/drm/radeon/sumo_dpm.h @@ -202,9 +202,6 @@ void sumo_construct_vid_mapping_table(struct radeon_device *rdev, u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev, struct sumo_vid_mapping_table *vid_mapping_table, u32 vid_2bit); -u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev, - struct sumo_vid_mapping_table *vid_mapping_table, - u32 vid_7bit); u32 sumo_get_sleep_divider_from_id(u32 id); u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev, u32 sclk, diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index b4ec5c4e796..38dacb7a368 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -1269,6 +1269,7 @@ void trinity_dpm_setup_asic(struct radeon_device *rdev) trinity_release_mutex(rdev); } +#if 0 void trinity_dpm_reset_asic(struct radeon_device *rdev) { struct trinity_power_info *pi = trinity_get_pi(rdev); @@ -1284,6 +1285,7 @@ void trinity_dpm_reset_asic(struct radeon_device *rdev) } trinity_release_mutex(rdev); } +#endif static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev, u32 vid_2bit) |