diff options
Diffstat (limited to 'drivers/gpu/drm/radeon')
121 files changed, 11009 insertions, 5037 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 306364a1ecd..dbcbfe80aac 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -72,7 +72,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \  	radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \  	rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \  	r200.o radeon_legacy_tv.o r600_cs.o r600_blit_shaders.o \ -	radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ +	radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o dce3_1_afmt.o \  	evergreen.o evergreen_cs.o evergreen_blit_shaders.o \  	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \  	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \ @@ -80,7 +80,7 @@ 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 +	ci_dpm.o dce6_afmt.o radeon_vm.o  # add async DMA block  radeon-y += \ @@ -99,6 +99,12 @@ radeon-y += \  	uvd_v3_1.o \  	uvd_v4_2.o +# add VCE block +radeon-y += \ +	radeon_vce.o \ +	vce_v1_0.o \ +	vce_v2_0.o \ +  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o  radeon-$(CONFIG_ACPI) += radeon_acpi.o diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index af10f8571d8..92be50c39ff 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -1711,7 +1711,9 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V6  #define PIXEL_CLOCK_V6_MISC_HDMI_BPP_MASK           0x0c  #define PIXEL_CLOCK_V6_MISC_HDMI_24BPP              0x00  #define PIXEL_CLOCK_V6_MISC_HDMI_36BPP              0x04 +#define PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6           0x08    //for V6, the correct defintion for 36bpp should be 2 for 36bpp(2:1)  #define PIXEL_CLOCK_V6_MISC_HDMI_30BPP              0x08 +#define PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6           0x04    //for V6, the correct defintion for 30bpp should be 1 for 36bpp(5:4)  #define PIXEL_CLOCK_V6_MISC_HDMI_48BPP              0x0c  #define PIXEL_CLOCK_V6_MISC_REF_DIV_SRC             0x10  #define PIXEL_CLOCK_V6_MISC_GEN_DPREFCLK            0x40 @@ -2223,7 +2225,7 @@ typedef struct	_SET_VOLTAGE_PARAMETERS_V2    USHORT   usVoltageLevel;              // real voltage level  }SET_VOLTAGE_PARAMETERS_V2; - +// used by both SetVoltageTable v1.3 and v1.4  typedef struct	_SET_VOLTAGE_PARAMETERS_V1_3  {    UCHAR    ucVoltageType;               // To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI @@ -2290,15 +2292,36 @@ typedef struct  _GET_LEAKAGE_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1  #define	ATOM_GET_VOLTAGE_VID                0x00  #define ATOM_GET_VOTLAGE_INIT_SEQ           0x03  #define ATOM_GET_VOLTTAGE_PHASE_PHASE_VID   0x04 -// for SI, this state map to 0xff02 voltage state in Power Play table, which is power boost state -#define	ATOM_GET_VOLTAGE_STATE0_LEAKAGE_VID 0x10 +#define ATOM_GET_VOLTAGE_SVID2              0x07        //Get SVI2 Regulator Info +// for SI, this state map to 0xff02 voltage state in Power Play table, which is power boost state +#define ATOM_GET_VOLTAGE_STATE0_LEAKAGE_VID 0x10  // for SI, this state map to 0xff01 voltage state in Power Play table, which is performance state  #define	ATOM_GET_VOLTAGE_STATE1_LEAKAGE_VID 0x11 -// undefined power state +  #define	ATOM_GET_VOLTAGE_STATE2_LEAKAGE_VID 0x12  #define	ATOM_GET_VOLTAGE_STATE3_LEAKAGE_VID 0x13 +// New Added from CI Hawaii for GetVoltageInfoTable, input parameter structure +typedef struct  _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 +{ +  UCHAR    ucVoltageType;               // Input: To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI +  UCHAR    ucVoltageMode;               // Input: Indicate action: Get voltage info +  USHORT   usVoltageLevel;              // Input: real voltage level in unit of mv or Voltage Phase (0, 1, 2, .. ) or Leakage Id  +  ULONG    ulSCLKFreq;                  // Input: when ucVoltageMode= ATOM_GET_VOLTAGE_EVV_VOLTAGE, DPM state SCLK frequency, Define in PPTable SCLK/Voltage dependence table +}GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2; + +// New in GetVoltageInfo v1.2 ucVoltageMode +#define ATOM_GET_VOLTAGE_EVV_VOLTAGE        0x09         + +// New Added from CI Hawaii for EVV feature  +typedef struct  _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 +{ +  USHORT   usVoltageLevel;                               // real voltage level in unit of mv +  USHORT   usVoltageId;                                  // Voltage Id programmed in Voltage Regulator +  ULONG    ulReseved; +}GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2; +  /****************************************************************************/	  // Structures used by TVEncoderControlTable  /****************************************************************************/	 @@ -3864,6 +3887,8 @@ typedef struct _ATOM_GPIO_PIN_ASSIGNMENT  #define PP_AC_DC_SWITCH_GPIO_PINID          60  //from SMU7.x, if ucGPIO_ID=VDDC_REGULATOR_VRHOT_GPIO_PINID in GPIO_LUTable, VRHot feature is enable  #define VDDC_VRHOT_GPIO_PINID               61 +//if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable, Peak Current Control feature is enabled +#define VDDC_PCC_GPIO_PINID                 62  typedef struct _ATOM_GPIO_PIN_LUT  { @@ -4169,10 +4194,10 @@ typedef struct _ATOM_COMMON_RECORD_HEADER  #define ATOM_OBJECT_LINK_RECORD_TYPE                   18 //Once this record is present under one object, it indicats the oobject is linked to another obj described by the record  #define ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE          19  #define ATOM_ENCODER_CAP_RECORD_TYPE                   20 - +#define ATOM_BRACKET_LAYOUT_RECORD_TYPE                21  //Must be updated when new record type is added,equal to that record definition! -#define ATOM_MAX_OBJECT_RECORD_NUMBER             ATOM_ENCODER_CAP_RECORD_TYPE +#define ATOM_MAX_OBJECT_RECORD_NUMBER             ATOM_BRACKET_LAYOUT_RECORD_TYPE  typedef struct  _ATOM_I2C_RECORD  { @@ -4397,6 +4422,31 @@ typedef struct _ATOM_CONNECTOR_REMOTE_CAP_RECORD    USHORT                      usReserved;  }ATOM_CONNECTOR_REMOTE_CAP_RECORD; +typedef struct  _ATOM_CONNECTOR_LAYOUT_INFO +{ +   USHORT usConnectorObjectId; +   UCHAR  ucConnectorType; +   UCHAR  ucPosition; +}ATOM_CONNECTOR_LAYOUT_INFO; + +// define ATOM_CONNECTOR_LAYOUT_INFO.ucConnectorType to describe the display connector size +#define CONNECTOR_TYPE_DVI_D                 1 +#define CONNECTOR_TYPE_DVI_I                 2 +#define CONNECTOR_TYPE_VGA                   3 +#define CONNECTOR_TYPE_HDMI                  4 +#define CONNECTOR_TYPE_DISPLAY_PORT          5 +#define CONNECTOR_TYPE_MINI_DISPLAY_PORT     6 + +typedef struct  _ATOM_BRACKET_LAYOUT_RECORD +{ +  ATOM_COMMON_RECORD_HEADER   sheader; +  UCHAR                       ucLength; +  UCHAR                       ucWidth; +  UCHAR                       ucConnNum; +  UCHAR                       ucReserved; +  ATOM_CONNECTOR_LAYOUT_INFO  asConnInfo[1]; +}ATOM_BRACKET_LAYOUT_RECORD; +  /****************************************************************************/	  // ASIC voltage data table  /****************************************************************************/	 @@ -4524,8 +4574,9 @@ typedef struct _ATOM_VOLTAGE_OBJECT_HEADER_V3{  #define VOLTAGE_OBJ_VR_I2C_INIT_SEQ          3        //VOLTAGE REGULATOR INIT sequece through I2C -> ATOM_I2C_VOLTAGE_OBJECT_V3  #define VOLTAGE_OBJ_PHASE_LUT                4        //Set Vregulator Phase lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_V3  #define VOLTAGE_OBJ_SVID2                    7        //Indicate voltage control by SVID2 ->ATOM_SVID2_VOLTAGE_OBJECT_V3 -#define	VOLTAGE_OBJ_PWRBOOST_LEAKAGE_LUT     0x10     //Powerboost Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 -#define	VOLTAGE_OBJ_HIGH_STATE_LEAKAGE_LUT   0x11     //High voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 +#define VOLTAGE_OBJ_EVV                      8  +#define VOLTAGE_OBJ_PWRBOOST_LEAKAGE_LUT     0x10     //Powerboost Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 +#define VOLTAGE_OBJ_HIGH_STATE_LEAKAGE_LUT   0x11     //High voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3  #define VOLTAGE_OBJ_HIGH1_STATE_LEAKAGE_LUT  0x12     //High1 voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3  typedef struct  _VOLTAGE_LUT_ENTRY_V2 @@ -4552,6 +4603,10 @@ typedef struct  _ATOM_I2C_VOLTAGE_OBJECT_V3     VOLTAGE_LUT_ENTRY asVolI2cLut[1];        // end with 0xff  }ATOM_I2C_VOLTAGE_OBJECT_V3; +// ATOM_I2C_VOLTAGE_OBJECT_V3.ucVoltageControlFlag +#define VOLTAGE_DATA_ONE_BYTE                0 +#define VOLTAGE_DATA_TWO_BYTE                1 +  typedef struct  _ATOM_GPIO_VOLTAGE_OBJECT_V3  {     ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;   // voltage mode = VOLTAGE_OBJ_GPIO_LUT or VOLTAGE_OBJ_PHASE_LUT @@ -4584,7 +4639,8 @@ typedef struct  _ATOM_SVID2_VOLTAGE_OBJECT_V3  // 1:0  offset trim,      USHORT   usLoadLine_PSI;      // GPU GPIO pin Id to SVID2 regulator VRHot pin. possible value 0~31. 0 means GPIO0, 31 means GPIO31 -   UCHAR    ucReserved[2]; +   UCHAR    ucSVDGpioId;     //0~31 indicate GPIO0~31 +   UCHAR    ucSVCGpioId;     //0~31 indicate GPIO0~31     ULONG    ulReserved;  }ATOM_SVID2_VOLTAGE_OBJECT_V3; @@ -4637,6 +4693,49 @@ typedef struct  _ATOM_ASIC_PROFILING_INFO_V2_1    USHORT usElbVDDCI_LevelArrayOffset;    // offset of 2 dimension voltage level USHORT array  }ATOM_ASIC_PROFILING_INFO_V2_1; +typedef struct  _ATOM_ASIC_PROFILING_INFO_V3_1 +{ +  ATOM_COMMON_TABLE_HEADER         asHeader;  +  ULONG  ulEvvDerateTdp; +  ULONG  ulEvvDerateTdc; +  ULONG  ulBoardCoreTemp; +  ULONG  ulMaxVddc; +  ULONG  ulMinVddc; +  ULONG  ulLoadLineSlop; +  ULONG  ulLeakageTemp; +  ULONG  ulLeakageVoltage; +  ULONG  ulCACmEncodeRange; +  ULONG  ulCACmEncodeAverage; +  ULONG  ulCACbEncodeRange; +  ULONG  ulCACbEncodeAverage; +  ULONG  ulKt_bEncodeRange; +  ULONG  ulKt_bEncodeAverage; +  ULONG  ulKv_mEncodeRange; +  ULONG  ulKv_mEncodeAverage; +  ULONG  ulKv_bEncodeRange; +  ULONG  ulKv_bEncodeAverage; +  ULONG  ulLkgEncodeLn_MaxDivMin; +  ULONG  ulLkgEncodeMin; +  ULONG  ulEfuseLogisticAlpha; +  USHORT usPowerDpm0; +  USHORT usCurrentDpm0; +  USHORT usPowerDpm1; +  USHORT usCurrentDpm1; +  USHORT usPowerDpm2; +  USHORT usCurrentDpm2; +  USHORT usPowerDpm3; +  USHORT usCurrentDpm3; +  USHORT usPowerDpm4; +  USHORT usCurrentDpm4; +  USHORT usPowerDpm5; +  USHORT usCurrentDpm5; +  USHORT usPowerDpm6; +  USHORT usCurrentDpm6; +  USHORT usPowerDpm7; +  USHORT usCurrentDpm7; +}ATOM_ASIC_PROFILING_INFO_V3_1; + +  typedef struct _ATOM_POWER_SOURCE_OBJECT  {  	UCHAR	ucPwrSrcId;													// Power source @@ -5808,6 +5907,8 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3  #define ATOM_S7_DOS_MODE_PIXEL_DEPTHb0      0x0C  #define ATOM_S7_DOS_MODE_PIXEL_FORMATb0     0xF0  #define ATOM_S7_DOS_8BIT_DAC_ENb1           0x01 +#define ATOM_S7_ASIC_INIT_COMPLETEb1        0x02 +#define ATOM_S7_ASIC_INIT_COMPLETE_MASK     0x00000200  #define ATOM_S7_DOS_MODE_NUMBERw1           0x0FFFF  #define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT       8 @@ -6242,6 +6343,7 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE  #define _128Mx32            0x53  #define _256Mx8             0x61  #define _256Mx16            0x62 +#define _512Mx8             0x71  #define SAMSUNG             0x1  #define INFINEON            0x2 @@ -6987,9 +7089,10 @@ typedef struct _ATOM_DISP_OUT_INFO_V3    UCHAR  ucMaxDispEngineNum;    UCHAR  ucMaxActiveDispEngineNum;    UCHAR  ucMaxPPLLNum; -  UCHAR  ucCoreRefClkSource;                          // value of CORE_REF_CLK_SOURCE -  UCHAR  ucReserved[3]; -	ASIC_TRANSMITTER_INFO_V2  asTransmitterInfo[1];     // for alligment only +  UCHAR  ucCoreRefClkSource;                    // value of CORE_REF_CLK_SOURCE +  UCHAR  ucDispCaps; +  UCHAR  ucReserved[2]; +  ASIC_TRANSMITTER_INFO_V2  asTransmitterInfo[1];     // for alligment only  }ATOM_DISP_OUT_INFO_V3;  //ucDispCaps diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index bf87f6d435f..30d242b2507 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -209,6 +209,16 @@ static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)  	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);  } +static const u32 vga_control_regs[6] = +{ +	AVIVO_D1VGA_CONTROL, +	AVIVO_D2VGA_CONTROL, +	EVERGREEN_D3VGA_CONTROL, +	EVERGREEN_D4VGA_CONTROL, +	EVERGREEN_D5VGA_CONTROL, +	EVERGREEN_D6VGA_CONTROL, +}; +  static void atombios_blank_crtc(struct drm_crtc *crtc, int state)  {  	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -216,13 +226,23 @@ static void atombios_blank_crtc(struct drm_crtc *crtc, int state)  	struct radeon_device *rdev = dev->dev_private;  	int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);  	BLANK_CRTC_PS_ALLOCATION args; +	u32 vga_control = 0;  	memset(&args, 0, sizeof(args)); +	if (ASIC_IS_DCE8(rdev)) { +		vga_control = RREG32(vga_control_regs[radeon_crtc->crtc_id]); +		WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control | 1); +	} +  	args.ucCRTC = radeon_crtc->crtc_id;  	args.ucBlanking = state;  	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +	if (ASIC_IS_DCE8(rdev)) { +		WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control); +	}  }  static void atombios_powergate_crtc(struct drm_crtc *crtc, int state) @@ -250,8 +270,6 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)  	switch (mode) {  	case DRM_MODE_DPMS_ON:  		radeon_crtc->enabled = true; -		/* adjust pm to dpms changes BEFORE enabling crtcs */ -		radeon_pm_compute_clocks(rdev);  		atombios_enable_crtc(crtc, ATOM_ENABLE);  		if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))  			atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); @@ -269,10 +287,10 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)  			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);  		atombios_enable_crtc(crtc, ATOM_DISABLE);  		radeon_crtc->enabled = false; -		/* adjust pm to dpms changes AFTER disabling crtcs */ -		radeon_pm_compute_clocks(rdev);  		break;  	} +	/* adjust pm to dpms */ +	radeon_pm_compute_clocks(rdev);  }  static void @@ -423,7 +441,17 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev,  	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);  	union atom_enable_ss args; -	if (!enable) { +	if (enable) { +		/* Don't mess with SS if percentage is 0 or external ss. +		 * SS is already disabled previously, and disabling it +		 * again can cause display problems if the pll is already +		 * programmed. +		 */ +		if (ss->percentage == 0) +			return; +		if (ss->type & ATOM_EXTERNAL_SS_MASK) +			return; +	} else {  		for (i = 0; i < rdev->num_crtc; i++) {  			if (rdev->mode_info.crtcs[i] &&  			    rdev->mode_info.crtcs[i]->enabled && @@ -459,8 +487,6 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev,  		args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);  		args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);  		args.v3.ucEnable = enable; -		if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE61(rdev)) -			args.v3.ucEnable = ATOM_DISABLE;  	} else if (ASIC_IS_DCE4(rdev)) {  		args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);  		args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; @@ -480,8 +506,6 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev,  		args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);  		args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step);  		args.v2.ucEnable = enable; -		if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE41(rdev)) -			args.v2.ucEnable = ATOM_DISABLE;  	} else if (ASIC_IS_DCE3(rdev)) {  		args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);  		args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; @@ -503,8 +527,7 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev,  		args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;  		args.lvds_ss_2.ucEnable = enable;  	} else { -		if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || -		    (ss->type & ATOM_EXTERNAL_SS_MASK)) { +		if (enable == ATOM_DISABLE) {  			atombios_disable_ss(rdev, pll_id);  			return;  		} @@ -534,7 +557,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,  	u32 adjusted_clock = mode->clock;  	int encoder_mode = atombios_get_encoder_mode(encoder);  	u32 dp_clock = mode->clock; -	int bpc = radeon_get_monitor_bpc(connector); +	u32 clock = mode->clock; +	int bpc = radeon_crtc->bpc;  	bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);  	/* reset the pll flags */ @@ -609,6 +633,24 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,  			radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;  	} +	/* adjust pll for deep color modes */ +	if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { +		switch (bpc) { +		case 8: +		default: +			break; +		case 10: +			clock = (clock * 5) / 4; +			break; +		case 12: +			clock = (clock * 3) / 2; +			break; +		case 16: +			clock = clock * 2; +			break; +		} +	} +  	/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock  	 * accordingly based on the encoder/transmitter to work around  	 * special hw requirements. @@ -630,7 +672,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,  			switch (crev) {  			case 1:  			case 2: -				args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); +				args.v1.usPixelClock = cpu_to_le16(clock / 10);  				args.v1.ucTransmitterID = radeon_encoder->encoder_id;  				args.v1.ucEncodeMode = encoder_mode;  				if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) @@ -642,7 +684,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,  				adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;  				break;  			case 3: -				args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); +				args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);  				args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;  				args.v3.sInput.ucEncodeMode = encoder_mode;  				args.v3.sInput.ucDispPllConfig = 0; @@ -656,10 +698,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,  					args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);  				} else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {  					struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; -					if (encoder_mode == ATOM_ENCODER_MODE_HDMI) -						/* deep color support */ -						args.v3.sInput.usPixelClock = -							cpu_to_le16((mode->clock * bpc / 8) / 10);  					if (dig->coherent_mode)  						args.v3.sInput.ucDispPllConfig |=  							DISPPLL_CONFIG_COHERENT_MODE; @@ -839,14 +877,21 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,  			args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */  			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))  				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; -			switch (bpc) { -			case 8: -			default: -				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; -				break; -			case 10: -				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; -				break; +			if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { +				switch (bpc) { +				case 8: +				default: +					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; +					break; +				case 10: +					/* yes this is correct, the atom define is wrong */ +					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP; +					break; +				case 12: +					/* yes this is correct, the atom define is wrong */ +					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; +					break; +				}  			}  			args.v5.ucTransmitterID = encoder_id;  			args.v5.ucEncoderMode = encoder_mode; @@ -861,20 +906,22 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,  			args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */  			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))  				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; -			switch (bpc) { -			case 8: -			default: -				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; -				break; -			case 10: -				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP; -				break; -			case 12: -				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP; -				break; -			case 16: -				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; -				break; +			if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { +				switch (bpc) { +				case 8: +				default: +					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; +					break; +				case 10: +					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6; +					break; +				case 12: +					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6; +					break; +				case 16: +					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; +					break; +				}  			}  			args.v6.ucTransmitterID = encoder_id;  			args.v6.ucEncoderMode = encoder_mode; @@ -915,6 +962,9 @@ static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_  		struct radeon_connector_atom_dig *dig_connector =  			radeon_connector->con_priv;  		int dp_clock; + +		/* Assign mode clock for hdmi deep color max clock limit check */ +		radeon_connector->pixelclock_for_modeset = mode->clock;  		radeon_crtc->bpc = radeon_get_monitor_bpc(connector);  		switch (encoder_mode) { @@ -938,11 +988,14 @@ static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_  							radeon_atombios_get_ppll_ss_info(rdev,  											 &radeon_crtc->ss,  											 ATOM_DP_SS_ID1); -				} else +				} else {  					radeon_crtc->ss_enabled =  						radeon_atombios_get_ppll_ss_info(rdev,  										 &radeon_crtc->ss,  										 ATOM_DP_SS_ID1); +				} +				/* disable spread spectrum on DCE3 DP */ +				radeon_crtc->ss_enabled = false;  			}  			break;  		case ATOM_ENCODER_MODE_LVDS: @@ -993,10 +1046,17 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode  	struct radeon_encoder *radeon_encoder =  		to_radeon_encoder(radeon_crtc->encoder);  	u32 pll_clock = mode->clock; +	u32 clock = mode->clock;  	u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;  	struct radeon_pll *pll;  	int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); +	/* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */ +	if (ASIC_IS_DCE5(rdev) && +	    (encoder_mode == ATOM_ENCODER_MODE_HDMI) && +	    (radeon_crtc->bpc > 8)) +		clock = radeon_crtc->adjusted_clock; +  	switch (radeon_crtc->pll_id) {  	case ATOM_PPLL1:  		pll = &rdev->clock.p1pll; @@ -1031,7 +1091,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode  				 radeon_crtc->crtc_id, &radeon_crtc->ss);  	atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, -				  encoder_mode, radeon_encoder->encoder_id, mode->clock, +				  encoder_mode, radeon_encoder->encoder_id, clock,  				  ref_div, fb_div, frac_fb_div, post_div,  				  radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss); @@ -1039,15 +1099,17 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode  		/* calculate ss amount and step size */  		if (ASIC_IS_DCE4(rdev)) {  			u32 step_size; -			u32 amount = (((fb_div * 10) + frac_fb_div) * radeon_crtc->ss.percentage) / 10000; +			u32 amount = (((fb_div * 10) + frac_fb_div) * +				      (u32)radeon_crtc->ss.percentage) / +				(100 * (u32)radeon_crtc->ss.percentage_divider);  			radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;  			radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &  				ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;  			if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) -				step_size = (4 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) / +				step_size = (4 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) /  					(125 * 25 * pll->reference_freq / 100);  			else -				step_size = (2 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) / +				step_size = (2 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) /  					(125 * 25 * pll->reference_freq / 100);  			radeon_crtc->ss.step = step_size;  		} @@ -1074,9 +1136,10 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,  	u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);  	u32 tmp, viewport_w, viewport_h;  	int r; +	bool bypass_lut = false;  	/* no fb bound */ -	if (!atomic && !crtc->fb) { +	if (!atomic && !crtc->primary->fb) {  		DRM_DEBUG_KMS("No FB bound\n");  		return 0;  	} @@ -1086,8 +1149,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,  		target_fb = fb;  	}  	else { -		radeon_fb = to_radeon_framebuffer(crtc->fb); -		target_fb = crtc->fb; +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb); +		target_fb = crtc->primary->fb;  	}  	/* If atomic, assume fb object is pinned & idle & fenced and @@ -1112,62 +1175,141 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,  	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);  	radeon_bo_unreserve(rbo); -	switch (target_fb->bits_per_pixel) { -	case 8: +	switch (target_fb->pixel_format) { +	case DRM_FORMAT_C8:  		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |  			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));  		break; -	case 15: +	case DRM_FORMAT_XRGB4444: +	case DRM_FORMAT_ARGB4444: +		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | +			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB4444)); +#ifdef __BIG_ENDIAN +		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); +#endif +		break; +	case DRM_FORMAT_XRGB1555: +	case DRM_FORMAT_ARGB1555:  		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |  			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); +#ifdef __BIG_ENDIAN +		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); +#endif  		break; -	case 16: +	case DRM_FORMAT_BGRX5551: +	case DRM_FORMAT_BGRA5551: +		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | +			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA5551)); +#ifdef __BIG_ENDIAN +		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); +#endif +		break; +	case DRM_FORMAT_RGB565:  		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |  			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));  #ifdef __BIG_ENDIAN  		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);  #endif  		break; -	case 24: -	case 32: +	case DRM_FORMAT_XRGB8888: +	case DRM_FORMAT_ARGB8888:  		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |  			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));  #ifdef __BIG_ENDIAN  		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);  #endif  		break; +	case DRM_FORMAT_XRGB2101010: +	case DRM_FORMAT_ARGB2101010: +		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | +			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB2101010)); +#ifdef __BIG_ENDIAN +		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); +#endif +		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ +		bypass_lut = true; +		break; +	case DRM_FORMAT_BGRX1010102: +	case DRM_FORMAT_BGRA1010102: +		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | +			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA1010102)); +#ifdef __BIG_ENDIAN +		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); +#endif +		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ +		bypass_lut = true; +		break;  	default: -		DRM_ERROR("Unsupported screen depth %d\n", -			  target_fb->bits_per_pixel); +		DRM_ERROR("Unsupported screen format %s\n", +			  drm_get_format_name(target_fb->pixel_format));  		return -EINVAL;  	}  	if (tiling_flags & RADEON_TILING_MACRO) { -		if (rdev->family >= CHIP_BONAIRE) -			tmp = rdev->config.cik.tile_config; -		else if (rdev->family >= CHIP_TAHITI) -			tmp = rdev->config.si.tile_config; -		else if (rdev->family >= CHIP_CAYMAN) -			tmp = rdev->config.cayman.tile_config; -		else -			tmp = rdev->config.evergreen.tile_config; +		evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); -		switch ((tmp & 0xf0) >> 4) { -		case 0: /* 4 banks */ -			fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); -			break; -		case 1: /* 8 banks */ -		default: -			fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); -			break; -		case 2: /* 16 banks */ -			fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); -			break; +		/* Set NUM_BANKS. */ +		if (rdev->family >= CHIP_TAHITI) { +			unsigned index, num_banks; + +			if (rdev->family >= CHIP_BONAIRE) { +				unsigned tileb, tile_split_bytes; + +				/* Calculate the macrotile mode index. */ +				tile_split_bytes = 64 << tile_split; +				tileb = 8 * 8 * target_fb->bits_per_pixel / 8; +				tileb = min(tile_split_bytes, tileb); + +				for (index = 0; tileb > 64; index++) +					tileb >>= 1; + +				if (index >= 16) { +					DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n", +						  target_fb->bits_per_pixel, tile_split); +					return -EINVAL; +				} + +				num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; +			} else { +				switch (target_fb->bits_per_pixel) { +				case 8: +					index = 10; +					break; +				case 16: +					index = SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP; +					break; +				default: +				case 32: +					index = SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP; +					break; +				} + +				num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3; +			} + +			fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks); +		} else { +			/* NI and older. */ +			if (rdev->family >= CHIP_CAYMAN) +				tmp = rdev->config.cayman.tile_config; +			else +				tmp = rdev->config.evergreen.tile_config; + +			switch ((tmp & 0xf0) >> 4) { +			case 0: /* 4 banks */ +				fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); +				break; +			case 1: /* 8 banks */ +			default: +				fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); +				break; +			case 2: /* 16 banks */ +				fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); +				break; +			}  		}  		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); - -		evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);  		fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split);  		fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);  		fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh); @@ -1180,23 +1322,18 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,  		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);  	if (rdev->family >= CHIP_BONAIRE) { -		u32 num_pipe_configs = rdev->config.cik.max_tile_pipes; -		u32 num_rb = rdev->config.cik.max_backends_per_se; -		if (num_pipe_configs > 8) -			num_pipe_configs = 8; -		if (num_pipe_configs == 8) -			fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P8_32x32_16x16); -		else if (num_pipe_configs == 4) { -			if (num_rb == 4) -				fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_16x16); -			else if (num_rb < 4) -				fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_8x16); -		} else if (num_pipe_configs == 2) -			fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P2); +		/* Read the pipe config from the 2D TILED SCANOUT mode. +		 * It should be the same for the other modes too, but not all +		 * modes set the pipe config field. */ +		u32 pipe_config = (rdev->config.cik.tile_mode_array[10] >> 6) & 0x1f; + +		fb_format |= CIK_GRPH_PIPE_CONFIG(pipe_config);  	} else if ((rdev->family == CHIP_TAHITI) ||  		   (rdev->family == CHIP_PITCAIRN))  		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16); -	else if (rdev->family == CHIP_VERDE) +	else if ((rdev->family == CHIP_VERDE) || +		 (rdev->family == CHIP_OLAND) || +		 (rdev->family == CHIP_HAINAN)) /* for completeness.  HAINAN has no display hw */  		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16);  	switch (radeon_crtc->crtc_id) { @@ -1233,6 +1370,18 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,  	WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);  	WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); +	/* +	 * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT +	 * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to +	 * retain the full precision throughout the pipeline. +	 */ +	WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset, +		 (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0), +		 ~EVERGREEN_LUT_10BIT_BYPASS_EN); + +	if (bypass_lut) +		DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); +  	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);  	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);  	WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); @@ -1265,10 +1414,10 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,  	tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN;  	WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); -	/* set pageflip to happen anywhere in vblank interval */ -	WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); +	/* set pageflip to happen only at start of vblank interval (front porch) */ +	WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); -	if (!atomic && fb && fb != crtc->fb) { +	if (!atomic && fb && fb != crtc->primary->fb) {  		radeon_fb = to_radeon_framebuffer(fb);  		rbo = gem_to_radeon_bo(radeon_fb->obj);  		r = radeon_bo_reserve(rbo, false); @@ -1300,9 +1449,10 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,  	u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE;  	u32 tmp, viewport_w, viewport_h;  	int r; +	bool bypass_lut = false;  	/* no fb bound */ -	if (!atomic && !crtc->fb) { +	if (!atomic && !crtc->primary->fb) {  		DRM_DEBUG_KMS("No FB bound\n");  		return 0;  	} @@ -1312,8 +1462,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,  		target_fb = fb;  	}  	else { -		radeon_fb = to_radeon_framebuffer(crtc->fb); -		target_fb = crtc->fb; +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb); +		target_fb = crtc->primary->fb;  	}  	obj = radeon_fb->obj; @@ -1337,18 +1487,30 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,  	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);  	radeon_bo_unreserve(rbo); -	switch (target_fb->bits_per_pixel) { -	case 8: +	switch (target_fb->pixel_format) { +	case DRM_FORMAT_C8:  		fb_format =  		    AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |  		    AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;  		break; -	case 15: +	case DRM_FORMAT_XRGB4444: +	case DRM_FORMAT_ARGB4444: +		fb_format = +		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | +		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444; +#ifdef __BIG_ENDIAN +		fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; +#endif +		break; +	case DRM_FORMAT_XRGB1555:  		fb_format =  		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |  		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; +#ifdef __BIG_ENDIAN +		fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; +#endif  		break; -	case 16: +	case DRM_FORMAT_RGB565:  		fb_format =  		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |  		    AVIVO_D1GRPH_CONTROL_16BPP_RGB565; @@ -1356,8 +1518,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,  		fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT;  #endif  		break; -	case 24: -	case 32: +	case DRM_FORMAT_XRGB8888: +	case DRM_FORMAT_ARGB8888:  		fb_format =  		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |  		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; @@ -1365,9 +1527,20 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,  		fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT;  #endif  		break; +	case DRM_FORMAT_XRGB2101010: +	case DRM_FORMAT_ARGB2101010: +		fb_format = +		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | +		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010; +#ifdef __BIG_ENDIAN +		fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; +#endif +		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ +		bypass_lut = true; +		break;  	default: -		DRM_ERROR("Unsupported screen depth %d\n", -			  target_fb->bits_per_pixel); +		DRM_ERROR("Unsupported screen format %s\n", +			  drm_get_format_name(target_fb->pixel_format));  		return -EINVAL;  	} @@ -1406,6 +1579,13 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,  	if (rdev->family >= CHIP_R600)  		WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); +	/* LUT only has 256 slots for 8 bpc fb. Bypass for > 8 bpc scanout for precision */ +	WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, +		 (bypass_lut ? AVIVO_LUT_10BIT_BYPASS_EN : 0), ~AVIVO_LUT_10BIT_BYPASS_EN); + +	if (bypass_lut) +		DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); +  	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);  	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);  	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); @@ -1434,10 +1614,10 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,  	tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN;  	WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); -	/* set pageflip to happen anywhere in vblank interval */ -	WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); +	/* set pageflip to happen only at start of vblank interval (front porch) */ +	WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); -	if (!atomic && fb && fb != crtc->fb) { +	if (!atomic && fb && fb != crtc->primary->fb) {  		radeon_fb = to_radeon_framebuffer(fb);  		rbo = gem_to_radeon_bo(radeon_fb->obj);  		r = radeon_bo_reserve(rbo, false); @@ -1672,8 +1852,9 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)  		}  		/* otherwise, pick one of the plls */  		if ((rdev->family == CHIP_KAVERI) || -		    (rdev->family == CHIP_KABINI)) { -			/* KB/KV has PPLL1 and PPLL2 */ +		    (rdev->family == CHIP_KABINI) || +		    (rdev->family == CHIP_MULLINS)) { +			/* KB/KV/ML has PPLL1 and PPLL2 */  			pll_in_use = radeon_get_pll_use_mask(crtc);  			if (!(pll_in_use & (1 << ATOM_PPLL2)))  				return ATOM_PPLL2; @@ -1726,6 +1907,20 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)  			return ATOM_PPLL1;  		DRM_ERROR("unable to allocate a PPLL\n");  		return ATOM_PPLL_INVALID; +	} else if (ASIC_IS_DCE41(rdev)) { +		/* Don't share PLLs on DCE4.1 chips */ +		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { +			if (rdev->clock.dp_extclk) +				/* skip PPLL programming if using ext clock */ +				return ATOM_PPLL_INVALID; +		} +		pll_in_use = radeon_get_pll_use_mask(crtc); +		if (!(pll_in_use & (1 << ATOM_PPLL1))) +			return ATOM_PPLL1; +		if (!(pll_in_use & (1 << ATOM_PPLL2))) +			return ATOM_PPLL2; +		DRM_ERROR("unable to allocate a PPLL\n"); +		return ATOM_PPLL_INVALID;  	} else if (ASIC_IS_DCE4(rdev)) {  		/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,  		 * depending on the asic: @@ -1823,6 +2018,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,  	    (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))  		is_tvcv = true; +	if (!radeon_crtc->adjusted_clock) +		return -EINVAL; +  	atombios_crtc_set_pll(crtc, adjusted_mode);  	if (ASIC_IS_DCE4(rdev)) @@ -1910,6 +2108,21 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)  	int i;  	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +	if (crtc->primary->fb) { +		int r; +		struct radeon_framebuffer *radeon_fb; +		struct radeon_bo *rbo; + +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb); +		rbo = gem_to_radeon_bo(radeon_fb->obj); +		r = radeon_bo_reserve(rbo, false); +		if (unlikely(r)) +			DRM_ERROR("failed to reserve rbo before unpin\n"); +		else { +			radeon_bo_unpin(rbo); +			radeon_bo_unreserve(rbo); +		} +	}  	/* disable the GRPH */  	if (ASIC_IS_DCE4(rdev))  		WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 0); @@ -1940,7 +2153,9 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)  		break;  	case ATOM_PPLL0:  		/* disable the ppll */ -		if ((rdev->family == CHIP_ARUBA) || (rdev->family == CHIP_BONAIRE)) +		if ((rdev->family == CHIP_ARUBA) || +		    (rdev->family == CHIP_BONAIRE) || +		    (rdev->family == CHIP_HAWAII))  			atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,  						  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);  		break; diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 00885417fff..b1e11f8434e 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -95,9 +95,12 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,  	int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);  	unsigned char *base;  	int recv_bytes; +	int r = 0;  	memset(&args, 0, sizeof(args)); +	mutex_lock(&chan->mutex); +  	base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);  	radeon_atom_copy_swap(base, send, send_bytes, true); @@ -117,19 +120,22 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,  	/* timeout */  	if (args.v1.ucReplyStatus == 1) {  		DRM_DEBUG_KMS("dp_aux_ch timeout\n"); -		return -ETIMEDOUT; +		r = -ETIMEDOUT; +		goto done;  	}  	/* flags not zero */  	if (args.v1.ucReplyStatus == 2) {  		DRM_DEBUG_KMS("dp_aux_ch flags not zero\n"); -		return -EBUSY; +		r = -EIO; +		goto done;  	}  	/* error */  	if (args.v1.ucReplyStatus == 3) {  		DRM_DEBUG_KMS("dp_aux_ch error\n"); -		return -EIO; +		r = -EIO; +		goto done;  	}  	recv_bytes = args.v1.ucDataOutLen; @@ -139,187 +145,89 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,  	if (recv && recv_size)  		radeon_atom_copy_swap(recv, base + 16, recv_bytes, false); -	return recv_bytes; -} - -static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, -				      u16 address, u8 *send, u8 send_bytes, u8 delay) -{ -	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; -	int ret; -	u8 msg[20]; -	int msg_bytes = send_bytes + 4; -	u8 ack; -	unsigned retry; - -	if (send_bytes > 16) -		return -1; - -	msg[0] = address; -	msg[1] = address >> 8; -	msg[2] = AUX_NATIVE_WRITE << 4; -	msg[3] = (msg_bytes << 4) | (send_bytes - 1); -	memcpy(&msg[4], send, send_bytes); - -	for (retry = 0; retry < 4; retry++) { -		ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, -					    msg, msg_bytes, NULL, 0, delay, &ack); -		if (ret == -EBUSY) -			continue; -		else if (ret < 0) -			return ret; -		if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) -			return send_bytes; -		else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) -			udelay(400); -		else -			return -EIO; -	} +	r = recv_bytes; +done: +	mutex_unlock(&chan->mutex); -	return -EIO; +	return r;  } -static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, -				     u16 address, u8 *recv, int recv_bytes, u8 delay) +#define BARE_ADDRESS_SIZE 3 +#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1) + +static ssize_t +radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  { -	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; -	u8 msg[4]; -	int msg_bytes = 4; -	u8 ack; +	struct radeon_i2c_chan *chan = +		container_of(aux, struct radeon_i2c_chan, aux);  	int ret; -	unsigned retry; - -	msg[0] = address; -	msg[1] = address >> 8; -	msg[2] = AUX_NATIVE_READ << 4; -	msg[3] = (msg_bytes << 4) | (recv_bytes - 1); - -	for (retry = 0; retry < 4; retry++) { -		ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, -					    msg, msg_bytes, recv, recv_bytes, delay, &ack); -		if (ret == -EBUSY) -			continue; -		else if (ret < 0) -			return ret; -		if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) -			return ret; -		else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) -			udelay(400); -		else if (ret == 0) -			return -EPROTO; +	u8 tx_buf[20]; +	size_t tx_size; +	u8 ack, delay = 0; + +	if (WARN_ON(msg->size > 16)) +		return -E2BIG; + +	tx_buf[0] = msg->address & 0xff; +	tx_buf[1] = msg->address >> 8; +	tx_buf[2] = msg->request << 4; +	tx_buf[3] = msg->size ? (msg->size - 1) : 0; + +	switch (msg->request & ~DP_AUX_I2C_MOT) { +	case DP_AUX_NATIVE_WRITE: +	case DP_AUX_I2C_WRITE: +		/* tx_size needs to be 4 even for bare address packets since the atom +		 * table needs the info in tx_buf[3]. +		 */ +		tx_size = HEADER_SIZE + msg->size; +		if (msg->size == 0) +			tx_buf[3] |= BARE_ADDRESS_SIZE << 4;  		else -			return -EIO; +			tx_buf[3] |= tx_size << 4; +		memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size); +		ret = radeon_process_aux_ch(chan, +					    tx_buf, tx_size, NULL, 0, delay, &ack); +		if (ret >= 0) +			/* Return payload size. */ +			ret = msg->size; +		break; +	case DP_AUX_NATIVE_READ: +	case DP_AUX_I2C_READ: +		/* tx_size needs to be 4 even for bare address packets since the atom +		 * table needs the info in tx_buf[3]. +		 */ +		tx_size = HEADER_SIZE; +		if (msg->size == 0) +			tx_buf[3] |= BARE_ADDRESS_SIZE << 4; +		else +			tx_buf[3] |= tx_size << 4; +		ret = radeon_process_aux_ch(chan, +					    tx_buf, tx_size, msg->buffer, msg->size, delay, &ack); +		break; +	default: +		ret = -EINVAL; +		break;  	} -	return -EIO; -} - -static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector, -				 u16 reg, u8 val) -{ -	radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0); -} - -static u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector, -			       u16 reg) -{ -	u8 val = 0; - -	radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0); +	if (ret >= 0) +		msg->reply = ack >> 4; -	return val; +	return ret;  } -int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, -			 u8 write_byte, u8 *read_byte) +void radeon_dp_aux_init(struct radeon_connector *radeon_connector)  { -	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; -	struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter; -	u16 address = algo_data->address; -	u8 msg[5]; -	u8 reply[2]; -	unsigned retry; -	int msg_bytes; -	int reply_bytes = 1;  	int ret; -	u8 ack; -	/* Set up the command byte */ -	if (mode & MODE_I2C_READ) -		msg[2] = AUX_I2C_READ << 4; -	else -		msg[2] = AUX_I2C_WRITE << 4; - -	if (!(mode & MODE_I2C_STOP)) -		msg[2] |= AUX_I2C_MOT << 4; - -	msg[0] = address; -	msg[1] = address >> 8; +	radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd; +	radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev; +	radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer; -	switch (mode) { -	case MODE_I2C_WRITE: -		msg_bytes = 5; -		msg[3] = msg_bytes << 4; -		msg[4] = write_byte; -		break; -	case MODE_I2C_READ: -		msg_bytes = 4; -		msg[3] = msg_bytes << 4; -		break; -	default: -		msg_bytes = 4; -		msg[3] = 3 << 4; -		break; -	} - -	for (retry = 0; retry < 4; retry++) { -		ret = radeon_process_aux_ch(auxch, -					    msg, msg_bytes, reply, reply_bytes, 0, &ack); -		if (ret == -EBUSY) -			continue; -		else if (ret < 0) { -			DRM_DEBUG_KMS("aux_ch failed %d\n", ret); -			return ret; -		} - -		switch (ack & AUX_NATIVE_REPLY_MASK) { -		case AUX_NATIVE_REPLY_ACK: -			/* I2C-over-AUX Reply field is only valid -			 * when paired with AUX ACK. -			 */ -			break; -		case AUX_NATIVE_REPLY_NACK: -			DRM_DEBUG_KMS("aux_ch native nack\n"); -			return -EREMOTEIO; -		case AUX_NATIVE_REPLY_DEFER: -			DRM_DEBUG_KMS("aux_ch native defer\n"); -			udelay(400); -			continue; -		default: -			DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack); -			return -EREMOTEIO; -		} - -		switch (ack & AUX_I2C_REPLY_MASK) { -		case AUX_I2C_REPLY_ACK: -			if (mode == MODE_I2C_READ) -				*read_byte = reply[0]; -			return ret; -		case AUX_I2C_REPLY_NACK: -			DRM_DEBUG_KMS("aux_i2c nack\n"); -			return -EREMOTEIO; -		case AUX_I2C_REPLY_DEFER: -			DRM_DEBUG_KMS("aux_i2c defer\n"); -			udelay(400); -			break; -		default: -			DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack); -			return -EREMOTEIO; -		} -	} +	ret = drm_dp_aux_register(&radeon_connector->ddc_bus->aux); +	if (!ret) +		radeon_connector->ddc_bus->has_aux = true; -	DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); -	return -EREMOTEIO; +	WARN(ret, "drm_dp_aux_register() failed with error %d\n", ret);  }  /***** general DP utility functions *****/ @@ -384,6 +292,19 @@ static int dp_get_max_dp_pix_clock(int link_rate,  /***** radeon specific DP functions *****/ +static int radeon_dp_get_max_link_rate(struct drm_connector *connector, +				       u8 dpcd[DP_DPCD_SIZE]) +{ +	int max_link_rate; + +	if (radeon_connector_is_dp12_capable(connector)) +		max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000); +	else +		max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000); + +	return max_link_rate; +} +  /* First get the min lane# when low rate is used according to pixel clock   * (prefer low rate), second check max lane# supported by DP panel,   * if the max lane# < low rate lane# then use max lane# instead. @@ -393,7 +314,7 @@ static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,  					int pix_clock)  {  	int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector)); -	int max_link_rate = drm_dp_max_link_rate(dpcd); +	int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd);  	int max_lane_num = drm_dp_max_lane_count(dpcd);  	int lane_num;  	int max_dp_pix_clock; @@ -431,7 +352,7 @@ static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,  			return 540000;  	} -	return drm_dp_max_link_rate(dpcd); +	return radeon_dp_get_max_link_rate(connector, dpcd);  }  static u8 radeon_dp_encoder_service(struct radeon_device *rdev, @@ -454,12 +375,11 @@ static u8 radeon_dp_encoder_service(struct radeon_device *rdev,  u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector)  { -	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;  	struct drm_device *dev = radeon_connector->base.dev;  	struct radeon_device *rdev = dev->dev_private;  	return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0, -					 dig_connector->dp_i2c_bus->rec.i2c_id, 0); +					 radeon_connector->ddc_bus->rec.i2c_id, 0);  }  static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) @@ -470,11 +390,11 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector)  	if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))  		return; -	if (radeon_dp_aux_native_read(radeon_connector, DP_SINK_OUI, buf, 3, 0)) +	if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3) == 3)  		DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",  			      buf[0], buf[1], buf[2]); -	if (radeon_dp_aux_native_read(radeon_connector, DP_BRANCH_OUI, buf, 3, 0)) +	if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3) == 3)  		DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",  			      buf[0], buf[1], buf[2]);  } @@ -483,16 +403,18 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)  {  	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;  	u8 msg[DP_DPCD_SIZE]; -	int ret, i; +	int ret; + +	char dpcd_hex_dump[DP_DPCD_SIZE * 3]; -	ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, -					DP_DPCD_SIZE, 0); +	ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, +			       DP_DPCD_SIZE);  	if (ret > 0) {  		memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); -		DRM_DEBUG_KMS("DPCD: "); -		for (i = 0; i < DP_DPCD_SIZE; i++) -			DRM_DEBUG_KMS("%02x ", msg[i]); -		DRM_DEBUG_KMS("\n"); + +		hex_dump_to_buffer(dig_connector->dpcd, sizeof(dig_connector->dpcd), +				   32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false); +		DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump);  		radeon_dp_probe_oui(radeon_connector); @@ -508,6 +430,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,  	struct drm_device *dev = encoder->dev;  	struct radeon_device *rdev = dev->dev_private;  	struct radeon_connector *radeon_connector = to_radeon_connector(connector); +	struct radeon_connector_atom_dig *dig_connector;  	int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;  	u16 dp_bridge = radeon_connector_encoder_get_dp_bridge_encoder_id(connector);  	u8 tmp; @@ -515,21 +438,30 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,  	if (!ASIC_IS_DCE4(rdev))  		return panel_mode; +	if (!radeon_connector->con_priv) +		return panel_mode; + +	dig_connector = radeon_connector->con_priv; +  	if (dp_bridge != ENCODER_OBJECT_ID_NONE) {  		/* DP bridge chips */ -		tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); -		if (tmp & 1) -			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; -		else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) || -			 (dp_bridge == ENCODER_OBJECT_ID_TRAVIS)) -			panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; -		else -			panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; +		if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, +				      DP_EDP_CONFIGURATION_CAP, &tmp) == 1) { +			if (tmp & 1) +				panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; +			else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) || +				 (dp_bridge == ENCODER_OBJECT_ID_TRAVIS)) +				panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; +			else +				panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; +		}  	} else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {  		/* eDP */ -		tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); -		if (tmp & 1) -			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; +		if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, +				      DP_EDP_CONFIGURATION_CAP, &tmp) == 1) { +			if (tmp & 1) +				panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; +		}  	}  	return panel_mode; @@ -575,37 +507,43 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,  	return MODE_OK;  } -static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector, -				      u8 link_status[DP_LINK_STATUS_SIZE]) -{ -	int ret; -	ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, -					link_status, DP_LINK_STATUS_SIZE, 100); -	if (ret <= 0) { -		return false; -	} - -	DRM_DEBUG_KMS("link status %6ph\n", link_status); -	return true; -} -  bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)  {  	u8 link_status[DP_LINK_STATUS_SIZE];  	struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; -	if (!radeon_dp_get_link_status(radeon_connector, link_status)) +	if (drm_dp_dpcd_read_link_status(&radeon_connector->ddc_bus->aux, link_status) +	    <= 0)  		return false;  	if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))  		return false;  	return true;  } +void radeon_dp_set_rx_power_state(struct drm_connector *connector, +				  u8 power_state) +{ +	struct radeon_connector *radeon_connector = to_radeon_connector(connector); +	struct radeon_connector_atom_dig *dig_connector; + +	if (!radeon_connector->con_priv) +		return; + +	dig_connector = radeon_connector->con_priv; + +	/* power up/down the sink */ +	if (dig_connector->dpcd[0] >= 0x11) { +		drm_dp_dpcd_writeb(&radeon_connector->ddc_bus->aux, +				   DP_SET_POWER, power_state); +		usleep_range(1000, 2000); +	} +} + +  struct radeon_dp_link_train_info {  	struct radeon_device *rdev;  	struct drm_encoder *encoder;  	struct drm_connector *connector; -	struct radeon_connector *radeon_connector;  	int enc_id;  	int dp_clock;  	int dp_lane_count; @@ -615,6 +553,7 @@ struct radeon_dp_link_train_info {  	u8 link_status[DP_LINK_STATUS_SIZE];  	u8 tries;  	bool use_dpencoder; +	struct drm_dp_aux *aux;  };  static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info) @@ -625,8 +564,8 @@ static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)  				       0, dp_info->train_set[0]); /* sets all lanes at once */  	/* set the vs/emph on the sink */ -	radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET, -				   dp_info->train_set, dp_info->dp_lane_count, 0); +	drm_dp_dpcd_write(dp_info->aux, DP_TRAINING_LANE0_SET, +			  dp_info->train_set, dp_info->dp_lane_count);  }  static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp) @@ -661,7 +600,7 @@ static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)  	}  	/* enable training pattern on the sink */ -	radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp); +	drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp);  }  static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) @@ -671,33 +610,30 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)  	u8 tmp;  	/* power up the sink */ -	if (dp_info->dpcd[0] >= 0x11) -		radeon_write_dpcd_reg(dp_info->radeon_connector, -				      DP_SET_POWER, DP_SET_POWER_D0); +	radeon_dp_set_rx_power_state(dp_info->connector, DP_SET_POWER_D0);  	/* possibly enable downspread on the sink */  	if (dp_info->dpcd[3] & 0x1) -		radeon_write_dpcd_reg(dp_info->radeon_connector, -				      DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); +		drm_dp_dpcd_writeb(dp_info->aux, +				   DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);  	else -		radeon_write_dpcd_reg(dp_info->radeon_connector, -				      DP_DOWNSPREAD_CTRL, 0); +		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)) { -		radeon_write_dpcd_reg(dp_info->radeon_connector, DP_EDP_CONFIGURATION_SET, 1); +		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; -	if (dp_info->dpcd[DP_DPCD_REV] >= 0x11 && -	    dp_info->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP) +	if (drm_dp_enhanced_frame_cap(dp_info->dpcd))  		tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN; -	radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp); +	drm_dp_dpcd_writeb(dp_info->aux, DP_LANE_COUNT_SET, tmp);  	/* set the link rate on the sink */  	tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock); -	radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp); +	drm_dp_dpcd_writeb(dp_info->aux, DP_LINK_BW_SET, tmp);  	/* start training on the source */  	if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) @@ -708,9 +644,9 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)  					  dp_info->dp_clock, dp_info->enc_id, 0);  	/* disable the training pattern on the sink */ -	radeon_write_dpcd_reg(dp_info->radeon_connector, -			      DP_TRAINING_PATTERN_SET, -			      DP_TRAINING_PATTERN_DISABLE); +	drm_dp_dpcd_writeb(dp_info->aux, +			   DP_TRAINING_PATTERN_SET, +			   DP_TRAINING_PATTERN_DISABLE);  	return 0;  } @@ -720,9 +656,9 @@ static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info  	udelay(400);  	/* disable the training pattern on the sink */ -	radeon_write_dpcd_reg(dp_info->radeon_connector, -			      DP_TRAINING_PATTERN_SET, -			      DP_TRAINING_PATTERN_DISABLE); +	drm_dp_dpcd_writeb(dp_info->aux, +			   DP_TRAINING_PATTERN_SET, +			   DP_TRAINING_PATTERN_DISABLE);  	/* disable the training pattern on the source */  	if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) @@ -754,7 +690,8 @@ static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info)  	while (1) {  		drm_dp_link_train_clock_recovery_delay(dp_info->dpcd); -		if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { +		if (drm_dp_dpcd_read_link_status(dp_info->aux, +						 dp_info->link_status) <= 0) {  			DRM_ERROR("displayport link status failed\n");  			break;  		} @@ -816,7 +753,8 @@ static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)  	while (1) {  		drm_dp_link_train_channel_eq_delay(dp_info->dpcd); -		if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { +		if (drm_dp_dpcd_read_link_status(dp_info->aux, +						 dp_info->link_status) <= 0) {  			DRM_ERROR("displayport link status failed\n");  			break;  		} @@ -899,19 +837,23 @@ void radeon_dp_link_train(struct drm_encoder *encoder,  	else  		dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A; -	tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT); -	if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED)) -		dp_info.tp3_supported = true; -	else +	if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_MAX_LANE_COUNT, &tmp) +	    == 1) { +		if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED)) +			dp_info.tp3_supported = true; +		else +			dp_info.tp3_supported = false; +	} else {  		dp_info.tp3_supported = false; +	}  	memcpy(dp_info.dpcd, dig_connector->dpcd, DP_RECEIVER_CAP_SIZE);  	dp_info.rdev = rdev;  	dp_info.encoder = encoder;  	dp_info.connector = connector; -	dp_info.radeon_connector = radeon_connector;  	dp_info.dp_lane_count = dig_connector->dp_lane_count;  	dp_info.dp_clock = dig_connector->dp_clock; +	dp_info.aux = &radeon_connector->ddc_bus->aux;  	if (radeon_dp_link_train_init(&dp_info))  		goto done; diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 32923d2f600..7d68203a373 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -183,7 +183,6 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,  	struct backlight_properties props;  	struct radeon_backlight_privdata *pdata;  	struct radeon_encoder_atom_dig *dig; -	u8 backlight_level;  	char bl_name[16];  	/* Mac laptops with multiple GPUs use the gmux driver for backlight @@ -213,7 +212,7 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,  	props.type = BACKLIGHT_RAW;  	snprintf(bl_name, sizeof(bl_name),  		 "radeon_bl%d", dev->primary->index); -	bd = backlight_device_register(bl_name, &drm_connector->kdev, +	bd = backlight_device_register(bl_name, drm_connector->kdev,  				       pdata, &radeon_atom_backlight_ops, &props);  	if (IS_ERR(bd)) {  		DRM_ERROR("Backlight registration failed\n"); @@ -222,12 +221,17 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,  	pdata->encoder = radeon_encoder; -	backlight_level = radeon_atom_get_backlight_level_from_reg(rdev); -  	dig = radeon_encoder->enc_priv;  	dig->bl_dev = bd;  	bd->props.brightness = radeon_atom_backlight_get_brightness(bd); +	/* Set a reasonable default here if the level is 0 otherwise +	 * fbdev will attempt to turn the backlight on after console +	 * unblanking and it will try and restore 0 which turns the backlight +	 * off again. +	 */ +	if (bd->props.brightness == 0) +		bd->props.brightness = RADEON_MAX_BL_LEVEL;  	bd->props.power = FB_BLANK_UNBLANK;  	backlight_update_status(bd); @@ -464,11 +468,12 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)  static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)  { -	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);  	int bpc = 8; -	if (connector) -		bpc = radeon_get_monitor_bpc(connector); +	if (encoder->crtc) { +		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); +		bpc = radeon_crtc->bpc; +	}  	switch (bpc) {  	case 0: @@ -707,24 +712,37 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)  	switch (connector->connector_type) {  	case DRM_MODE_CONNECTOR_DVII:  	case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ -		if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) || -		    (drm_detect_hdmi_monitor(radeon_connector->edid) && -		     (radeon_connector->audio == RADEON_AUDIO_AUTO))) -			return ATOM_ENCODER_MODE_HDMI; -		else if (radeon_connector->use_digital) +		if (radeon_audio != 0) { +			if (radeon_connector->use_digital && +			    (radeon_connector->audio == RADEON_AUDIO_ENABLE)) +				return ATOM_ENCODER_MODE_HDMI; +			else if (drm_detect_hdmi_monitor(radeon_connector->edid) && +				 (radeon_connector->audio == RADEON_AUDIO_AUTO)) +				return ATOM_ENCODER_MODE_HDMI; +			else if (radeon_connector->use_digital) +				return ATOM_ENCODER_MODE_DVI; +			else +				return ATOM_ENCODER_MODE_CRT; +		} else if (radeon_connector->use_digital) {  			return ATOM_ENCODER_MODE_DVI; -		else +		} else {  			return ATOM_ENCODER_MODE_CRT; +		}  		break;  	case DRM_MODE_CONNECTOR_DVID:  	case DRM_MODE_CONNECTOR_HDMIA:  	default: -		if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) || -		    (drm_detect_hdmi_monitor(radeon_connector->edid) && -		     (radeon_connector->audio == RADEON_AUDIO_AUTO))) -			return ATOM_ENCODER_MODE_HDMI; -		else +		if (radeon_audio != 0) { +			if (radeon_connector->audio == RADEON_AUDIO_ENABLE) +				return ATOM_ENCODER_MODE_HDMI; +			else if (drm_detect_hdmi_monitor(radeon_connector->edid) && +				 (radeon_connector->audio == RADEON_AUDIO_AUTO)) +				return ATOM_ENCODER_MODE_HDMI; +			else +				return ATOM_ENCODER_MODE_DVI; +		} else {  			return ATOM_ENCODER_MODE_DVI; +		}  		break;  	case DRM_MODE_CONNECTOR_LVDS:  		return ATOM_ENCODER_MODE_LVDS; @@ -732,14 +750,19 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)  	case DRM_MODE_CONNECTOR_DisplayPort:  		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)) +		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {  			return ATOM_ENCODER_MODE_DP; -		else if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) || -			 (drm_detect_hdmi_monitor(radeon_connector->edid) && -			  (radeon_connector->audio == RADEON_AUDIO_AUTO))) -			return ATOM_ENCODER_MODE_HDMI; -		else +		} else if (radeon_audio != 0) { +			if (radeon_connector->audio == RADEON_AUDIO_ENABLE) +				return ATOM_ENCODER_MODE_HDMI; +			else if (drm_detect_hdmi_monitor(radeon_connector->edid) && +				 (radeon_connector->audio == RADEON_AUDIO_AUTO)) +				return ATOM_ENCODER_MODE_HDMI; +			else +				return ATOM_ENCODER_MODE_DVI; +		} else {  			return ATOM_ENCODER_MODE_DVI; +		}  		break;  	case DRM_MODE_CONNECTOR_eDP:  		return ATOM_ENCODER_MODE_DP; @@ -1295,7 +1318,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t  			}  			if (is_dp)  				args.v5.ucLaneNum = dp_lane_count; -			else if (radeon_encoder->pixel_clock > 165000) +			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))  				args.v5.ucLaneNum = 8;  			else  				args.v5.ucLaneNum = 4; @@ -1614,10 +1637,16 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)  	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);  	struct radeon_connector *radeon_connector = NULL;  	struct radeon_connector_atom_dig *radeon_dig_connector = NULL; +	bool travis_quirk = false;  	if (connector) {  		radeon_connector = to_radeon_connector(connector);  		radeon_dig_connector = radeon_connector->con_priv; +		if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == +		     ENCODER_OBJECT_ID_TRAVIS) && +		    (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && +		    !ASIC_IS_DCE5(rdev)) +			travis_quirk = true;  	}  	switch (mode) { @@ -1638,25 +1667,13 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)  					atombios_external_encoder_setup(encoder, ext_encoder,  									EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);  			} -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);  		} else if (ASIC_IS_DCE4(rdev)) {  			/* setup and enable the encoder */  			atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); -			/* enable the transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);  		} else {  			/* setup and enable the encoder and transmitter */  			atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0);  			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); -			/* some dce3.x boards have a bug in their transmitter control table. -			 * ACTION_ENABLE_OUTPUT can probably be dropped since ACTION_ENABLE -			 * does the same thing and more. -			 */ -			if ((rdev->family != CHIP_RV710) && (rdev->family != CHIP_RV730) && -			    (rdev->family != CHIP_RS880)) -				atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);  		}  		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {  			if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { @@ -1664,73 +1681,56 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)  							     ATOM_TRANSMITTER_ACTION_POWER_ON);  				radeon_dig_connector->edp_on = true;  			} +		} +		/* enable the transmitter */ +		atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); +		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { +			/* DP_SET_POWER_D0 is set in radeon_dp_link_train */  			radeon_dp_link_train(encoder, connector);  			if (ASIC_IS_DCE4(rdev))  				atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);  		}  		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); +			atombios_dig_transmitter_setup(encoder, +						       ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); +		if (ext_encoder) +			atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);  		break;  	case DRM_MODE_DPMS_STANDBY:  	case DRM_MODE_DPMS_SUSPEND:  	case DRM_MODE_DPMS_OFF: -		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { -			/* disable the transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); -		} else if (ASIC_IS_DCE4(rdev)) { +		if (ASIC_IS_DCE4(rdev)) { +			if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) +				atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); +		} +		if (ext_encoder) +			atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); +		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) +			atombios_dig_transmitter_setup(encoder, +						       ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); + +		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && +		    connector && !travis_quirk) +			radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); +		if (ASIC_IS_DCE4(rdev)) {  			/* disable the transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); +			atombios_dig_transmitter_setup(encoder, +						       ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);  		} else {  			/* disable the encoder and transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); +			atombios_dig_transmitter_setup(encoder, +						       ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);  			atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);  		}  		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { -			if (ASIC_IS_DCE4(rdev)) -				atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); +			if (travis_quirk) +				radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3);  			if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {  				atombios_set_edp_panel_power(connector,  							     ATOM_TRANSMITTER_ACTION_POWER_OFF);  				radeon_dig_connector->edp_on = false;  			}  		} -		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); -		break; -	} -} - -static void -radeon_atom_encoder_dpms_ext(struct drm_encoder *encoder, -			     struct drm_encoder *ext_encoder, -			     int mode) -{ -	struct drm_device *dev = encoder->dev; -	struct radeon_device *rdev = dev->dev_private; - -	switch (mode) { -	case DRM_MODE_DPMS_ON: -	default: -		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) { -			atombios_external_encoder_setup(encoder, ext_encoder, -							EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT); -			atombios_external_encoder_setup(encoder, ext_encoder, -							EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF); -		} else -			atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); -		break; -	case DRM_MODE_DPMS_STANDBY: -	case DRM_MODE_DPMS_SUSPEND: -	case DRM_MODE_DPMS_OFF: -		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) { -			atombios_external_encoder_setup(encoder, ext_encoder, -							EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING); -			atombios_external_encoder_setup(encoder, ext_encoder, -							EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT); -		} else -			atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE);  		break;  	}  } @@ -1741,7 +1741,6 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)  	struct drm_device *dev = encoder->dev;  	struct radeon_device *rdev = dev->dev_private;  	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); -	struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder);  	DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",  		  radeon_encoder->encoder_id, mode, radeon_encoder->devices, @@ -1801,9 +1800,6 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)  		return;  	} -	if (ext_encoder) -		radeon_atom_encoder_dpms_ext(encoder, ext_encoder, mode); -  	radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);  } @@ -1892,8 +1888,11 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)  					args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;  				else  					args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); -			} else +			} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { +				args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; +			} else {  				args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); +			}  			switch (radeon_encoder->encoder_id) {  			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:  			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: @@ -2392,6 +2391,15 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)  	/* this is needed for the pll/ss setup to work correctly in some cases */  	atombios_set_encoder_crtc_source(encoder); +	/* set up the FMT blocks */ +	if (ASIC_IS_DCE8(rdev)) +		dce8_program_fmt(encoder); +	else if (ASIC_IS_DCE4(rdev)) +		dce4_program_fmt(encoder); +	else if (ASIC_IS_DCE3(rdev)) +		dce3_program_fmt(encoder); +	else if (ASIC_IS_AVIVO(rdev)) +		avivo_program_fmt(encoder);  }  static void radeon_atom_encoder_commit(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/radeon/atombios_i2c.c b/drivers/gpu/drm/radeon/atombios_i2c.c index deaf98cdca3..9c570fb15b8 100644 --- a/drivers/gpu/drm/radeon/atombios_i2c.c +++ b/drivers/gpu/drm/radeon/atombios_i2c.c @@ -27,8 +27,6 @@  #include "radeon.h"  #include "atom.h" -extern void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le); -  #define TARGET_HW_I2C_CLOCK 50  /* these are a limitation of ProcessI2cChannelTransaction not the hw */ @@ -44,25 +42,35 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,  	PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION args;  	int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction);  	unsigned char *base; -	u16 out; +	u16 out = cpu_to_le16(0); +	int r = 0;  	memset(&args, 0, sizeof(args)); +	mutex_lock(&chan->mutex); +  	base = (unsigned char *)rdev->mode_info.atom_context->scratch;  	if (flags & HW_I2C_WRITE) {  		if (num > ATOM_MAX_HW_I2C_WRITE) {  			DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 3)\n", num); -			return -EINVAL; +			r = -EINVAL; +			goto done;  		} -		args.ucRegIndex = buf[0]; -		if (num > 1) -			memcpy(&out, &buf[1], num - 1); +		if (buf == NULL) +			args.ucRegIndex = 0; +		else +			args.ucRegIndex = buf[0]; +		if (num) +			num--; +		if (num) +			memcpy(&out, &buf[1], num);  		args.lpI2CDataOut = cpu_to_le16(out);  	} else {  		if (num > ATOM_MAX_HW_I2C_READ) {  			DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num); -			return -EINVAL; +			r = -EINVAL; +			goto done;  		}  		args.ucRegIndex = 0;  		args.lpI2CDataOut = 0; @@ -79,13 +87,17 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,  	/* error */  	if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {  		DRM_DEBUG_KMS("hw_i2c error\n"); -		return -EIO; +		r = -EIO; +		goto done;  	}  	if (!(flags & HW_I2C_WRITE))  		radeon_atom_copy_swap(buf, base, num, false); -	return 0; +done: +	mutex_unlock(&chan->mutex); + +	return r;  }  int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap, @@ -94,14 +106,14 @@ int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,  	struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);  	struct i2c_msg *p;  	int i, remaining, current_count, buffer_offset, max_bytes, ret; -	u8 buf = 0, flags; +	u8 flags;  	/* check for bus probe */  	p = &msgs[0];  	if ((num == 1) && (p->len == 0)) {  		ret = radeon_process_i2c_ch(i2c,  					    p->addr, HW_I2C_WRITE, -					    &buf, 1); +					    NULL, 0);  		if (ret)  			return ret;  		else diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index b162e98a295..f81d7ca134d 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -29,6 +29,7 @@  #include "cypress_dpm.h"  #include "btc_dpm.h"  #include "atom.h" +#include <linux/seq_file.h>  #define MC_CG_ARB_FREQ_F0           0x0a  #define MC_CG_ARB_FREQ_F1           0x0b @@ -49,6 +50,7 @@ struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);  struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);  struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev); +extern int ni_mc_load_microcode(struct radeon_device *rdev);  //********* BARTS **************//  static const u32 barts_cgcg_cgls_default[] = @@ -1930,7 +1932,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,  			}  			j++; -			if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) +			if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)  				return -EINVAL;  			tmp = RREG32(MC_PMG_CMD_MRS); @@ -1945,7 +1947,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,  			}  			j++; -			if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) +			if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)  				return -EINVAL;  			break;  		case MC_SEQ_RESERVE_M >> 2: @@ -1959,7 +1961,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,  			}  			j++; -			if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) +			if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)  				return -EINVAL;  			break;  		default: @@ -2510,21 +2512,6 @@ int btc_dpm_enable(struct radeon_device *rdev)  	if (eg_pi->ls_clock_gating)  		btc_ls_clock_gating_enable(rdev, true); -	if (rdev->irq.installed && -	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { -		PPSMC_Result result; - -		ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); -		if (ret) -			return ret; -		rdev->irq.dpm_thermal = true; -		radeon_irq_set(rdev); -		result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); - -		if (result != PPSMC_Result_OK) -			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); -	} -  	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);  	btc_init_stutter_mode(rdev); @@ -2576,7 +2563,11 @@ void btc_dpm_disable(struct radeon_device *rdev)  void btc_dpm_setup_asic(struct radeon_device *rdev)  {  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); +	int r; +	r = ni_mc_load_microcode(rdev); +	if (r) +		DRM_ERROR("Failed to load MC firmware!\n");  	rv770_get_memory_type(rdev);  	rv740_read_clock_registers(rdev);  	btc_read_arb_registers(rdev); @@ -2610,6 +2601,10 @@ int btc_dpm_init(struct radeon_device *rdev)  	pi->min_vddc_in_table = 0;  	pi->max_vddc_in_table = 0; +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = rv7xx_parse_power_table(rdev);  	if (ret)  		return ret; @@ -2766,6 +2761,37 @@ void btc_dpm_fini(struct radeon_device *rdev)  	r600_free_extended_power_table(rdev);  } +void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, +						     struct seq_file *m) +{ +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); +	struct radeon_ps *rps = &eg_pi->current_rps; +	struct rv7xx_ps *ps = rv770_get_ps(rps); +	struct rv7xx_pl *pl; +	u32 current_index = +		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> +		CURRENT_PROFILE_INDEX_SHIFT; + +	if (current_index > 2) { +		seq_printf(m, "invalid dpm profile %d\n", current_index); +	} else { +		if (current_index == 0) +			pl = &ps->low; +		else if (current_index == 1) +			pl = &ps->medium; +		else /* current_index == 2 */ +			pl = &ps->high; +		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk); +		if (rdev->family >= CHIP_CEDAR) { +			seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n", +				   current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci); +		} else { +			seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u\n", +				   current_index, pl->sclk, pl->mclk, pl->vddc); +		} +	} +} +  u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low)  {  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); diff --git a/drivers/gpu/drm/radeon/btcd.h b/drivers/gpu/drm/radeon/btcd.h index 29e32de7e02..9c65be2d55a 100644 --- a/drivers/gpu/drm/radeon/btcd.h +++ b/drivers/gpu/drm/radeon/btcd.h @@ -44,6 +44,10 @@  #       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)  #       define AC_DC_SW                                 (1 << 24) +#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x66c +#       define CURRENT_PROFILE_INDEX_MASK                 (0xf << 4) +#       define CURRENT_PROFILE_INDEX_SHIFT                4 +  #define	CG_BIF_REQ_AND_RSP				0x7f4  #define		CG_CLIENT_REQ(x)			((x) << 0)  #define		CG_CLIENT_REQ_MASK			(0xff << 0) diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index 51e947a97ed..584090ac3eb 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -21,8 +21,10 @@   *   */ +#include <linux/firmware.h>  #include "drmP.h"  #include "radeon.h" +#include "radeon_ucode.h"  #include "cikd.h"  #include "r600_dpm.h"  #include "ci_dpm.h" @@ -40,6 +42,20 @@  #define VOLTAGE_VID_OFFSET_SCALE1    625  #define VOLTAGE_VID_OFFSET_SCALE2    100 +static const struct ci_pt_defaults defaults_hawaii_xt = +{ +	1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000, +	{ 0x84,  0x0,   0x0,   0x7F,  0x0,   0x0,   0x5A,  0x60,  0x51,  0x8E,  0x79,  0x6B,  0x5F,  0x90,  0x79  }, +	{ 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC } +}; + +static const struct ci_pt_defaults defaults_hawaii_pro = +{ +	1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062, +	{ 0x93,  0x0,   0x0,   0x97,  0x0,   0x0,   0x6B,  0x60,  0x51,  0x95,  0x79,  0x6B,  0x5F,  0x90,  0x79  }, +	{ 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC } +}; +  static const struct ci_pt_defaults defaults_bonaire_xt =  {  	1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000, @@ -157,6 +173,7 @@ extern void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,  						     struct atom_voltage_table *voltage_table);  extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev);  extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev); +extern int ci_mc_load_microcode(struct radeon_device *rdev);  extern void cik_update_cg(struct radeon_device *rdev,  			  u32 block, bool enable); @@ -187,21 +204,38 @@ static void ci_initialize_powertune_defaults(struct radeon_device *rdev)  	struct ci_power_info *pi = ci_get_pi(rdev);  	switch (rdev->pdev->device) { -        case 0x6650: -        case 0x6658: -        case 0x665C: -        default: +	case 0x6649: +	case 0x6650: +	case 0x6651: +	case 0x6658: +	case 0x665C: +	case 0x665D: +	default:  		pi->powertune_defaults = &defaults_bonaire_xt;  		break; -        case 0x6651: -        case 0x665D: -		pi->powertune_defaults = &defaults_bonaire_pro; -		break; -        case 0x6640: +	case 0x6640: +	case 0x6641: +	case 0x6646: +	case 0x6647:  		pi->powertune_defaults = &defaults_saturn_xt;  		break; -        case 0x6641: -		pi->powertune_defaults = &defaults_saturn_pro; +	case 0x67B8: +	case 0x67B0: +		pi->powertune_defaults = &defaults_hawaii_xt; +		break; +	case 0x67BA: +	case 0x67B1: +		pi->powertune_defaults = &defaults_hawaii_pro; +		break; +	case 0x67A0: +	case 0x67A1: +	case 0x67A2: +	case 0x67A8: +	case 0x67A9: +	case 0x67AA: +	case 0x67B9: +	case 0x67BE: +		pi->powertune_defaults = &defaults_bonaire_xt;  		break;  	} @@ -717,6 +751,14 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,  	u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;  	int i; +	if (rps->vce_active) { +		rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; +		rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk; +	} else { +		rps->evclk = 0; +		rps->ecclk = 0; +	} +  	if ((rdev->pm.dpm.new_active_crtc_count > 1) ||  	    ci_dpm_vblank_too_short(rdev))  		disable_mclk_switching = true; @@ -775,6 +817,13 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,  		sclk = ps->performance_levels[0].sclk;  	} +	if (rps->vce_active) { +		if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk) +			sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk; +		if (mclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk) +			mclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk; +	} +  	ps->performance_levels[0].sclk = sclk;  	ps->performance_levels[0].mclk = mclk; @@ -1130,7 +1179,7 @@ static int ci_stop_dpm(struct radeon_device *rdev)  	tmp &= ~GLOBAL_PWRMGT_EN;  	WREG32_SMC(GENERAL_PWRMGT, tmp); -	tmp = RREG32(SCLK_PWRMGT_CNTL); +	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);  	tmp &= ~DYNAMIC_PM_EN;  	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp); @@ -3439,7 +3488,6 @@ static int ci_enable_uvd_dpm(struct radeon_device *rdev, bool enable)  		0 : -EINVAL;  } -#if 0  static int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable)  {  	struct ci_power_info *pi = ci_get_pi(rdev); @@ -3472,6 +3520,7 @@ static int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable)  		0 : -EINVAL;  } +#if 0  static int ci_enable_samu_dpm(struct radeon_device *rdev, bool enable)  {  	struct ci_power_info *pi = ci_get_pi(rdev); @@ -3558,7 +3607,6 @@ static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate)  	return ci_enable_uvd_dpm(rdev, !gate);  } -#if 0  static u8 ci_get_vce_boot_level(struct radeon_device *rdev)  {  	u8 i; @@ -3579,15 +3627,15 @@ static int ci_update_vce_dpm(struct radeon_device *rdev,  			     struct radeon_ps *radeon_current_state)  {  	struct ci_power_info *pi = ci_get_pi(rdev); -	bool new_vce_clock_non_zero = (radeon_new_state->evclk != 0); -	bool old_vce_clock_non_zero = (radeon_current_state->evclk != 0);  	int ret = 0;  	u32 tmp; -	if (new_vce_clock_non_zero != old_vce_clock_non_zero) { -		if (new_vce_clock_non_zero) { -			pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(rdev); +	if (radeon_current_state->evclk != radeon_new_state->evclk) { +		if (radeon_new_state->evclk) { +			/* turn the clocks on when encoding */ +			cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false); +			pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(rdev);  			tmp = RREG32_SMC(DPM_TABLE_475);  			tmp &= ~VceBootLevel_MASK;  			tmp |= VceBootLevel(pi->smc_state_table.VceBootLevel); @@ -3595,12 +3643,16 @@ static int ci_update_vce_dpm(struct radeon_device *rdev,  			ret = ci_enable_vce_dpm(rdev, true);  		} else { +			/* turn the clocks off when not encoding */ +			cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true); +  			ret = ci_enable_vce_dpm(rdev, false);  		}  	}  	return ret;  } +#if 0  static int ci_update_samu_dpm(struct radeon_device *rdev, bool gate)  {  	return ci_enable_samu_dpm(rdev, gate); @@ -4473,8 +4525,8 @@ static void ci_get_memory_type(struct radeon_device *rdev)  } -void ci_update_current_ps(struct radeon_device *rdev, -			  struct radeon_ps *rps) +static void ci_update_current_ps(struct radeon_device *rdev, +				 struct radeon_ps *rps)  {  	struct ci_ps *new_ps = ci_get_ps(rps);  	struct ci_power_info *pi = ci_get_pi(rdev); @@ -4484,8 +4536,8 @@ void ci_update_current_ps(struct radeon_device *rdev,  	pi->current_rps.ps_priv = &pi->current_ps;  } -void ci_update_requested_ps(struct radeon_device *rdev, -			    struct radeon_ps *rps) +static void ci_update_requested_ps(struct radeon_device *rdev, +				   struct radeon_ps *rps)  {  	struct ci_ps *new_ps = ci_get_ps(rps);  	struct ci_power_info *pi = ci_get_pi(rdev); @@ -4519,6 +4571,11 @@ void ci_dpm_post_set_power_state(struct radeon_device *rdev)  void ci_dpm_setup_asic(struct radeon_device *rdev)  { +	int r; + +	r = ci_mc_load_microcode(rdev); +	if (r) +		DRM_ERROR("Failed to load MC firmware!\n");  	ci_read_clock_registers(rdev);  	ci_get_memory_type(rdev);  	ci_enable_acpi_power_management(rdev); @@ -4531,13 +4588,6 @@ int ci_dpm_enable(struct radeon_device *rdev)  	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;  	int ret; -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_MC | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_UVD | -			     RADEON_CG_BLOCK_HDP), false); -  	if (ci_is_smc_running(rdev))  		return -EINVAL;  	if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) { @@ -4635,6 +4685,18 @@ int ci_dpm_enable(struct radeon_device *rdev)  		DRM_ERROR("ci_enable_power_containment failed\n");  		return ret;  	} + +	ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); + +	ci_update_current_ps(rdev, boot_ps); + +	return 0; +} + +int ci_dpm_late_enable(struct radeon_device *rdev) +{ +	int ret; +  	if (rdev->irq.installed &&  	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {  #if 0 @@ -4655,19 +4717,8 @@ int ci_dpm_enable(struct radeon_device *rdev)  #endif  	} -	ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); -  	ci_dpm_powergate_uvd(rdev, true); -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_MC | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_UVD | -			     RADEON_CG_BLOCK_HDP), true); - -	ci_update_current_ps(rdev, boot_ps); -  	return 0;  } @@ -4676,12 +4727,6 @@ void ci_dpm_disable(struct radeon_device *rdev)  	struct ci_power_info *pi = ci_get_pi(rdev);  	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_MC | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_UVD | -			     RADEON_CG_BLOCK_HDP), false); -  	ci_dpm_powergate_uvd(rdev, false);  	if (!ci_is_smc_running(rdev)) @@ -4712,13 +4757,6 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)  	struct radeon_ps *old_ps = &pi->current_rps;  	int ret; -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_MC | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_UVD | -			     RADEON_CG_BLOCK_HDP), false); -  	ci_find_dpm_states_clocks_in_dpm_table(rdev, new_ps);  	if (pi->pcie_performance_request)  		ci_request_link_speed_change_before_state_change(rdev, new_ps, old_ps); @@ -4737,13 +4775,13 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)  		DRM_ERROR("ci_generate_dpm_level_enable_mask failed\n");  		return ret;  	} -#if 0 +  	ret = ci_update_vce_dpm(rdev, new_ps, old_ps);  	if (ret) {  		DRM_ERROR("ci_update_vce_dpm failed\n");  		return ret;  	} -#endif +  	ret = ci_update_sclk_t(rdev);  	if (ret) {  		DRM_ERROR("ci_update_sclk_t failed\n"); @@ -4774,13 +4812,6 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)  	if (pi->pcie_performance_request)  		ci_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps); -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_MC | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_UVD | -			     RADEON_CG_BLOCK_HDP), true); -  	return 0;  } @@ -4951,9 +4982,6 @@ static int ci_parse_power_table(struct radeon_device *rdev)  	if (!rdev->pm.dpm.ps)  		return -ENOMEM;  	power_state_offset = (u8 *)state_array->states; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < state_array->ucNumEntries; i++) {  		u8 *idx;  		power_state = (union pplib_power_state *)power_state_offset; @@ -4990,11 +5018,26 @@ static int ci_parse_power_table(struct radeon_device *rdev)  		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;  	}  	rdev->pm.dpm.num_ps = state_array->ucNumEntries; + +	/* fill in the vce power states */ +	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) { +		u32 sclk, mclk; +		clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx; +		clock_info = (union pplib_clock_info *) +			&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; +		sclk = le16_to_cpu(clock_info->ci.usEngineClockLow); +		sclk |= clock_info->ci.ucEngineClockHigh << 16; +		mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow); +		mclk |= clock_info->ci.ucMemoryClockHigh << 16; +		rdev->pm.dpm.vce_states[i].sclk = sclk; +		rdev->pm.dpm.vce_states[i].mclk = mclk; +	} +  	return 0;  } -int ci_get_vbios_boot_values(struct radeon_device *rdev, -			     struct ci_vbios_boot_state *boot_state) +static int ci_get_vbios_boot_values(struct radeon_device *rdev, +				    struct ci_vbios_boot_state *boot_state)  {  	struct radeon_mode_info *mode_info = &rdev->mode_info;  	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); @@ -5069,17 +5112,25 @@ int ci_dpm_init(struct radeon_device *rdev)  		ci_dpm_fini(rdev);  		return ret;  	} -	ret = ci_parse_power_table(rdev); + +	ret = r600_get_platform_caps(rdev);  	if (ret) {  		ci_dpm_fini(rdev);  		return ret;  	} +  	ret = r600_parse_extended_power_table(rdev);  	if (ret) {  		ci_dpm_fini(rdev);  		return ret;  	} +	ret = ci_parse_power_table(rdev); +	if (ret) { +		ci_dpm_fini(rdev); +		return ret; +	} +          pi->dll_default_on = false;          pi->sram_end = SMC_RAM_END; @@ -5098,6 +5149,12 @@ int ci_dpm_init(struct radeon_device *rdev)  	pi->mclk_dpm_key_disabled = 0;  	pi->pcie_dpm_key_disabled = 0; +	/* mclk dpm is unstable on some R7 260X cards with the old mc ucode */ +	if ((rdev->pdev->device == 0x6658) && +	    (rdev->mc_fw->size == (BONAIRE_MC_UCODE_SIZE * 4))) { +		pi->mclk_dpm_key_disabled = 1; +	} +  	pi->caps_sclk_ds = true;  	pi->mclk_strobe_mode_threshold = 40000; @@ -5112,6 +5169,7 @@ int ci_dpm_init(struct radeon_device *rdev)  	pi->caps_sclk_throttle_low_notification = false;  	pi->caps_uvd_dpm = true; +	pi->caps_vce_dpm = true;          ci_get_leakage_voltages(rdev);          ci_patch_dependency_tables_with_leakage(rdev); @@ -5142,9 +5200,15 @@ int ci_dpm_init(struct radeon_device *rdev)  	rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;  	rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL; -	pi->thermal_temp_setting.temperature_low = 99500; -	pi->thermal_temp_setting.temperature_high = 100000; -	pi->thermal_temp_setting.temperature_shutdown = 104000; +	if (rdev->family == CHIP_HAWAII) { +		pi->thermal_temp_setting.temperature_low = 94500; +		pi->thermal_temp_setting.temperature_high = 95000; +		pi->thermal_temp_setting.temperature_shutdown = 104000; +	} else { +		pi->thermal_temp_setting.temperature_low = 99500; +		pi->thermal_temp_setting.temperature_high = 100000; +		pi->thermal_temp_setting.temperature_shutdown = 104000; +	}  	pi->uvd_enabled = false; diff --git a/drivers/gpu/drm/radeon/ci_smc.c b/drivers/gpu/drm/radeon/ci_smc.c index 252e10a41cf..8debc9d4736 100644 --- a/drivers/gpu/drm/radeon/ci_smc.c +++ b/drivers/gpu/drm/radeon/ci_smc.c @@ -28,6 +28,7 @@  #include "cikd.h"  #include "ppsmc.h"  #include "radeon_ucode.h" +#include "ci_dpm.h"  static int ci_set_smc_sram_address(struct radeon_device *rdev,  				   u32 smc_address, u32 limit) @@ -217,6 +218,10 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)  		ucode_start_address = BONAIRE_SMC_UCODE_START;  		ucode_size = BONAIRE_SMC_UCODE_SIZE;  		break; +	case CHIP_HAWAII: +		ucode_start_address = HAWAII_SMC_UCODE_START; +		ucode_size = HAWAII_SMC_UCODE_SIZE; +		break;  	default:  		DRM_ERROR("unknown asic in smc ucode loader\n");  		BUG(); diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index d02fd1c045d..c0ea66192fe 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -38,9 +38,19 @@ MODULE_FIRMWARE("radeon/BONAIRE_me.bin");  MODULE_FIRMWARE("radeon/BONAIRE_ce.bin");  MODULE_FIRMWARE("radeon/BONAIRE_mec.bin");  MODULE_FIRMWARE("radeon/BONAIRE_mc.bin"); +MODULE_FIRMWARE("radeon/BONAIRE_mc2.bin");  MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin");  MODULE_FIRMWARE("radeon/BONAIRE_sdma.bin");  MODULE_FIRMWARE("radeon/BONAIRE_smc.bin"); +MODULE_FIRMWARE("radeon/HAWAII_pfp.bin"); +MODULE_FIRMWARE("radeon/HAWAII_me.bin"); +MODULE_FIRMWARE("radeon/HAWAII_ce.bin"); +MODULE_FIRMWARE("radeon/HAWAII_mec.bin"); +MODULE_FIRMWARE("radeon/HAWAII_mc.bin"); +MODULE_FIRMWARE("radeon/HAWAII_mc2.bin"); +MODULE_FIRMWARE("radeon/HAWAII_rlc.bin"); +MODULE_FIRMWARE("radeon/HAWAII_sdma.bin"); +MODULE_FIRMWARE("radeon/HAWAII_smc.bin");  MODULE_FIRMWARE("radeon/KAVERI_pfp.bin");  MODULE_FIRMWARE("radeon/KAVERI_me.bin");  MODULE_FIRMWARE("radeon/KAVERI_ce.bin"); @@ -53,6 +63,12 @@ MODULE_FIRMWARE("radeon/KABINI_ce.bin");  MODULE_FIRMWARE("radeon/KABINI_mec.bin");  MODULE_FIRMWARE("radeon/KABINI_rlc.bin");  MODULE_FIRMWARE("radeon/KABINI_sdma.bin"); +MODULE_FIRMWARE("radeon/MULLINS_pfp.bin"); +MODULE_FIRMWARE("radeon/MULLINS_me.bin"); +MODULE_FIRMWARE("radeon/MULLINS_ce.bin"); +MODULE_FIRMWARE("radeon/MULLINS_mec.bin"); +MODULE_FIRMWARE("radeon/MULLINS_rlc.bin"); +MODULE_FIRMWARE("radeon/MULLINS_sdma.bin");  extern int r600_ih_ring_alloc(struct radeon_device *rdev);  extern void r600_ih_ring_fini(struct radeon_device *rdev); @@ -64,19 +80,18 @@ extern int sumo_rlc_init(struct radeon_device *rdev);  extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);  extern void si_rlc_reset(struct radeon_device *rdev);  extern void si_init_uvd_internal_cg(struct radeon_device *rdev); +static u32 cik_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh);  extern int cik_sdma_resume(struct radeon_device *rdev);  extern void cik_sdma_enable(struct radeon_device *rdev, bool enable);  extern void cik_sdma_fini(struct radeon_device *rdev); -extern void cik_sdma_vm_set_page(struct radeon_device *rdev, -				 struct radeon_ib *ib, -				 uint64_t pe, -				 uint64_t addr, unsigned count, -				 uint32_t incr, uint32_t flags); +extern void vce_v2_0_enable_mgcg(struct radeon_device *rdev, bool enable);  static void cik_rlc_stop(struct radeon_device *rdev);  static void cik_pcie_gen3_enable(struct radeon_device *rdev);  static void cik_program_aspm(struct radeon_device *rdev);  static void cik_init_pg(struct radeon_device *rdev);  static void cik_init_cg(struct radeon_device *rdev); +static void cik_fini_pg(struct radeon_device *rdev); +static void cik_fini_cg(struct radeon_device *rdev);  static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev,  					  bool enable); @@ -1090,7 +1105,7 @@ static const u32 spectre_golden_registers[] =  	0x8a14, 0xf000003f, 0x00000007,  	0x8b24, 0xffffffff, 0x00ffffff,  	0x28350, 0x3f3f3fff, 0x00000082, -	0x28355, 0x0000003f, 0x00000000, +	0x28354, 0x0000003f, 0x00000000,  	0x3e78, 0x00000001, 0x00000002,  	0x913c, 0xffff03df, 0x00000004,  	0xc768, 0x00000008, 0x00000008, @@ -1300,6 +1315,208 @@ static const u32 kalindi_mgcg_cgcg_init[] =  	0xd80c, 0xff000ff0, 0x00000100  }; +static const u32 hawaii_golden_spm_registers[] = +{ +	0x30800, 0xe0ffffff, 0xe0000000 +}; + +static const u32 hawaii_golden_common_registers[] = +{ +	0x30800, 0xffffffff, 0xe0000000, +	0x28350, 0xffffffff, 0x3a00161a, +	0x28354, 0xffffffff, 0x0000002e, +	0x9a10, 0xffffffff, 0x00018208, +	0x98f8, 0xffffffff, 0x12011003 +}; + +static const u32 hawaii_golden_registers[] = +{ +	0x3354, 0x00000333, 0x00000333, +	0x9a10, 0x00010000, 0x00058208, +	0x9830, 0xffffffff, 0x00000000, +	0x9834, 0xf00fffff, 0x00000400, +	0x9838, 0x0002021c, 0x00020200, +	0xc78, 0x00000080, 0x00000000, +	0x5bb0, 0x000000f0, 0x00000070, +	0x5bc0, 0xf0311fff, 0x80300000, +	0x350c, 0x00810000, 0x408af000, +	0x7030, 0x31000111, 0x00000011, +	0x2f48, 0x73773777, 0x12010001, +	0x2120, 0x0000007f, 0x0000001b, +	0x21dc, 0x00007fb6, 0x00002191, +	0x3628, 0x0000003f, 0x0000000a, +	0x362c, 0x0000003f, 0x0000000a, +	0x2ae4, 0x00073ffe, 0x000022a2, +	0x240c, 0x000007ff, 0x00000000, +	0x8bf0, 0x00002001, 0x00000001, +	0x8b24, 0xffffffff, 0x00ffffff, +	0x30a04, 0x0000ff0f, 0x00000000, +	0x28a4c, 0x07ffffff, 0x06000000, +	0x3e78, 0x00000001, 0x00000002, +	0xc768, 0x00000008, 0x00000008, +	0xc770, 0x00000f00, 0x00000800, +	0xc774, 0x00000f00, 0x00000800, +	0xc798, 0x00ffffff, 0x00ff7fbf, +	0xc79c, 0x00ffffff, 0x00ff7faf, +	0x8c00, 0x000000ff, 0x00000800, +	0xe40, 0x00001fff, 0x00001fff, +	0x9060, 0x0000007f, 0x00000020, +	0x9508, 0x00010000, 0x00010000, +	0xae00, 0x00100000, 0x000ff07c, +	0xac14, 0x000003ff, 0x0000000f, +	0xac10, 0xffffffff, 0x7564fdec, +	0xac0c, 0xffffffff, 0x3120b9a8, +	0xac08, 0x20000000, 0x0f9c0000 +}; + +static const u32 hawaii_mgcg_cgcg_init[] = +{ +	0xc420, 0xffffffff, 0xfffffffd, +	0x30800, 0xffffffff, 0xe0000000, +	0x3c2a0, 0xffffffff, 0x00000100, +	0x3c208, 0xffffffff, 0x00000100, +	0x3c2c0, 0xffffffff, 0x00000100, +	0x3c2c8, 0xffffffff, 0x00000100, +	0x3c2c4, 0xffffffff, 0x00000100, +	0x55e4, 0xffffffff, 0x00200100, +	0x3c280, 0xffffffff, 0x00000100, +	0x3c214, 0xffffffff, 0x06000100, +	0x3c220, 0xffffffff, 0x00000100, +	0x3c218, 0xffffffff, 0x06000100, +	0x3c204, 0xffffffff, 0x00000100, +	0x3c2e0, 0xffffffff, 0x00000100, +	0x3c224, 0xffffffff, 0x00000100, +	0x3c200, 0xffffffff, 0x00000100, +	0x3c230, 0xffffffff, 0x00000100, +	0x3c234, 0xffffffff, 0x00000100, +	0x3c250, 0xffffffff, 0x00000100, +	0x3c254, 0xffffffff, 0x00000100, +	0x3c258, 0xffffffff, 0x00000100, +	0x3c25c, 0xffffffff, 0x00000100, +	0x3c260, 0xffffffff, 0x00000100, +	0x3c27c, 0xffffffff, 0x00000100, +	0x3c278, 0xffffffff, 0x00000100, +	0x3c210, 0xffffffff, 0x06000100, +	0x3c290, 0xffffffff, 0x00000100, +	0x3c274, 0xffffffff, 0x00000100, +	0x3c2b4, 0xffffffff, 0x00000100, +	0x3c2b0, 0xffffffff, 0x00000100, +	0x3c270, 0xffffffff, 0x00000100, +	0x30800, 0xffffffff, 0xe0000000, +	0x3c020, 0xffffffff, 0x00010000, +	0x3c024, 0xffffffff, 0x00030002, +	0x3c028, 0xffffffff, 0x00040007, +	0x3c02c, 0xffffffff, 0x00060005, +	0x3c030, 0xffffffff, 0x00090008, +	0x3c034, 0xffffffff, 0x00010000, +	0x3c038, 0xffffffff, 0x00030002, +	0x3c03c, 0xffffffff, 0x00040007, +	0x3c040, 0xffffffff, 0x00060005, +	0x3c044, 0xffffffff, 0x00090008, +	0x3c048, 0xffffffff, 0x00010000, +	0x3c04c, 0xffffffff, 0x00030002, +	0x3c050, 0xffffffff, 0x00040007, +	0x3c054, 0xffffffff, 0x00060005, +	0x3c058, 0xffffffff, 0x00090008, +	0x3c05c, 0xffffffff, 0x00010000, +	0x3c060, 0xffffffff, 0x00030002, +	0x3c064, 0xffffffff, 0x00040007, +	0x3c068, 0xffffffff, 0x00060005, +	0x3c06c, 0xffffffff, 0x00090008, +	0x3c070, 0xffffffff, 0x00010000, +	0x3c074, 0xffffffff, 0x00030002, +	0x3c078, 0xffffffff, 0x00040007, +	0x3c07c, 0xffffffff, 0x00060005, +	0x3c080, 0xffffffff, 0x00090008, +	0x3c084, 0xffffffff, 0x00010000, +	0x3c088, 0xffffffff, 0x00030002, +	0x3c08c, 0xffffffff, 0x00040007, +	0x3c090, 0xffffffff, 0x00060005, +	0x3c094, 0xffffffff, 0x00090008, +	0x3c098, 0xffffffff, 0x00010000, +	0x3c09c, 0xffffffff, 0x00030002, +	0x3c0a0, 0xffffffff, 0x00040007, +	0x3c0a4, 0xffffffff, 0x00060005, +	0x3c0a8, 0xffffffff, 0x00090008, +	0x3c0ac, 0xffffffff, 0x00010000, +	0x3c0b0, 0xffffffff, 0x00030002, +	0x3c0b4, 0xffffffff, 0x00040007, +	0x3c0b8, 0xffffffff, 0x00060005, +	0x3c0bc, 0xffffffff, 0x00090008, +	0x3c0c0, 0xffffffff, 0x00010000, +	0x3c0c4, 0xffffffff, 0x00030002, +	0x3c0c8, 0xffffffff, 0x00040007, +	0x3c0cc, 0xffffffff, 0x00060005, +	0x3c0d0, 0xffffffff, 0x00090008, +	0x3c0d4, 0xffffffff, 0x00010000, +	0x3c0d8, 0xffffffff, 0x00030002, +	0x3c0dc, 0xffffffff, 0x00040007, +	0x3c0e0, 0xffffffff, 0x00060005, +	0x3c0e4, 0xffffffff, 0x00090008, +	0x3c0e8, 0xffffffff, 0x00010000, +	0x3c0ec, 0xffffffff, 0x00030002, +	0x3c0f0, 0xffffffff, 0x00040007, +	0x3c0f4, 0xffffffff, 0x00060005, +	0x3c0f8, 0xffffffff, 0x00090008, +	0xc318, 0xffffffff, 0x00020200, +	0x3350, 0xffffffff, 0x00000200, +	0x15c0, 0xffffffff, 0x00000400, +	0x55e8, 0xffffffff, 0x00000000, +	0x2f50, 0xffffffff, 0x00000902, +	0x3c000, 0xffffffff, 0x96940200, +	0x8708, 0xffffffff, 0x00900100, +	0xc424, 0xffffffff, 0x0020003f, +	0x38, 0xffffffff, 0x0140001c, +	0x3c, 0x000f0000, 0x000f0000, +	0x220, 0xffffffff, 0xc060000c, +	0x224, 0xc0000fff, 0x00000100, +	0xf90, 0xffffffff, 0x00000100, +	0xf98, 0x00000101, 0x00000000, +	0x20a8, 0xffffffff, 0x00000104, +	0x55e4, 0xff000fff, 0x00000100, +	0x30cc, 0xc0000fff, 0x00000104, +	0xc1e4, 0x00000001, 0x00000001, +	0xd00c, 0xff000ff0, 0x00000100, +	0xd80c, 0xff000ff0, 0x00000100 +}; + +static const u32 godavari_golden_registers[] = +{ +	0x55e4, 0xff607fff, 0xfc000100, +	0x6ed8, 0x00010101, 0x00010000, +	0x9830, 0xffffffff, 0x00000000, +	0x98302, 0xf00fffff, 0x00000400, +	0x6130, 0xffffffff, 0x00010000, +	0x5bb0, 0x000000f0, 0x00000070, +	0x5bc0, 0xf0311fff, 0x80300000, +	0x98f8, 0x73773777, 0x12010001, +	0x98fc, 0xffffffff, 0x00000010, +	0x8030, 0x00001f0f, 0x0000100a, +	0x2f48, 0x73773777, 0x12010001, +	0x2408, 0x000fffff, 0x000c007f, +	0x8a14, 0xf000003f, 0x00000007, +	0x8b24, 0xffffffff, 0x00ff0fff, +	0x30a04, 0x0000ff0f, 0x00000000, +	0x28a4c, 0x07ffffff, 0x06000000, +	0x4d8, 0x00000fff, 0x00000100, +	0xd014, 0x00010000, 0x00810001, +	0xd814, 0x00010000, 0x00810001, +	0x3e78, 0x00000001, 0x00000002, +	0xc768, 0x00000008, 0x00000008, +	0xc770, 0x00000f00, 0x00000800, +	0xc774, 0x00000f00, 0x00000800, +	0xc798, 0x00ffffff, 0x00ff7fbf, +	0xc79c, 0x00ffffff, 0x00ff7faf, +	0x8c00, 0x000000ff, 0x00000001, +	0x214f8, 0x01ff01ff, 0x00000002, +	0x21498, 0x007ff800, 0x00200000, +	0x2015c, 0xffffffff, 0x00000f40, +	0x88c4, 0x001f3ae3, 0x00000082, +	0x88d4, 0x0000001f, 0x00000010, +	0x30934, 0xffffffff, 0x00000000 +}; + +  static void cik_init_golden_registers(struct radeon_device *rdev)  {  	switch (rdev->family) { @@ -1331,6 +1548,20 @@ static void cik_init_golden_registers(struct radeon_device *rdev)  						 kalindi_golden_spm_registers,  						 (const u32)ARRAY_SIZE(kalindi_golden_spm_registers));  		break; +	case CHIP_MULLINS: +		radeon_program_register_sequence(rdev, +						 kalindi_mgcg_cgcg_init, +						 (const u32)ARRAY_SIZE(kalindi_mgcg_cgcg_init)); +		radeon_program_register_sequence(rdev, +						 godavari_golden_registers, +						 (const u32)ARRAY_SIZE(godavari_golden_registers)); +		radeon_program_register_sequence(rdev, +						 kalindi_golden_common_registers, +						 (const u32)ARRAY_SIZE(kalindi_golden_common_registers)); +		radeon_program_register_sequence(rdev, +						 kalindi_golden_spm_registers, +						 (const u32)ARRAY_SIZE(kalindi_golden_spm_registers)); +		break;  	case CHIP_KAVERI:  		radeon_program_register_sequence(rdev,  						 spectre_mgcg_cgcg_init, @@ -1345,6 +1576,20 @@ static void cik_init_golden_registers(struct radeon_device *rdev)  						 spectre_golden_spm_registers,  						 (const u32)ARRAY_SIZE(spectre_golden_spm_registers));  		break; +	case CHIP_HAWAII: +		radeon_program_register_sequence(rdev, +						 hawaii_mgcg_cgcg_init, +						 (const u32)ARRAY_SIZE(hawaii_mgcg_cgcg_init)); +		radeon_program_register_sequence(rdev, +						 hawaii_golden_registers, +						 (const u32)ARRAY_SIZE(hawaii_golden_registers)); +		radeon_program_register_sequence(rdev, +						 hawaii_golden_common_registers, +						 (const u32)ARRAY_SIZE(hawaii_golden_common_registers)); +		radeon_program_register_sequence(rdev, +						 hawaii_golden_spm_registers, +						 (const u32)ARRAY_SIZE(hawaii_golden_spm_registers)); +		break;  	default:  		break;  	} @@ -1376,17 +1621,17 @@ u32 cik_get_xclk(struct radeon_device *rdev)   * cik_mm_rdoorbell - read a doorbell dword   *   * @rdev: radeon_device pointer - * @offset: byte offset into the aperture + * @index: doorbell index   *   * Returns the value in the doorbell aperture at the - * requested offset (CIK). + * requested doorbell index (CIK).   */ -u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset) +u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 index)  { -	if (offset < rdev->doorbell.size) { -		return readl(((void __iomem *)rdev->doorbell.ptr) + offset); +	if (index < rdev->doorbell.num_doorbells) { +		return readl(rdev->doorbell.ptr + index);  	} else { -		DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset); +		DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index);  		return 0;  	}  } @@ -1395,18 +1640,18 @@ u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)   * cik_mm_wdoorbell - write a doorbell dword   *   * @rdev: radeon_device pointer - * @offset: byte offset into the aperture + * @index: doorbell index   * @v: value to write   *   * Writes @v to the doorbell aperture at the - * requested offset (CIK). + * requested doorbell index (CIK).   */ -void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v) +void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v)  { -	if (offset < rdev->doorbell.size) { -		writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset); +	if (index < rdev->doorbell.num_doorbells) { +		writel(v, rdev->doorbell.ptr + index);  	} else { -		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset); +		DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);  	}  } @@ -1452,6 +1697,35 @@ static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =  	{0x0000009f, 0x00b48000}  }; +#define HAWAII_IO_MC_REGS_SIZE 22 + +static const u32 hawaii_io_mc_regs[HAWAII_IO_MC_REGS_SIZE][2] = +{ +	{0x0000007d, 0x40000000}, +	{0x0000007e, 0x40180304}, +	{0x0000007f, 0x0000ff00}, +	{0x00000081, 0x00000000}, +	{0x00000083, 0x00000800}, +	{0x00000086, 0x00000000}, +	{0x00000087, 0x00000100}, +	{0x00000088, 0x00020100}, +	{0x00000089, 0x00000000}, +	{0x0000008b, 0x00040000}, +	{0x0000008c, 0x00000100}, +	{0x0000008e, 0xff010000}, +	{0x00000090, 0xffffefff}, +	{0x00000091, 0xfff3efff}, +	{0x00000092, 0xfff3efbf}, +	{0x00000093, 0xf7ffffff}, +	{0x00000094, 0xffffff7f}, +	{0x00000095, 0x00000fff}, +	{0x00000096, 0x00116fff}, +	{0x00000097, 0x60010000}, +	{0x00000098, 0x10010000}, +	{0x0000009f, 0x00c79000} +}; + +  /**   * cik_srbm_select - select specific register instances   * @@ -1484,23 +1758,29 @@ static void cik_srbm_select(struct radeon_device *rdev,   * Load the GDDR MC ucode into the hw (CIK).   * Returns 0 on success, error on failure.   */ -static int ci_mc_load_microcode(struct radeon_device *rdev) +int ci_mc_load_microcode(struct radeon_device *rdev)  {  	const __be32 *fw_data;  	u32 running, blackout = 0;  	u32 *io_mc_regs; -	int i, ucode_size, regs_size; +	int i, regs_size, ucode_size;  	if (!rdev->mc_fw)  		return -EINVAL; +	ucode_size = rdev->mc_fw->size / 4; +  	switch (rdev->family) {  	case CHIP_BONAIRE: -	default:  		io_mc_regs = (u32 *)&bonaire_io_mc_regs; -		ucode_size = CIK_MC_UCODE_SIZE;  		regs_size = BONAIRE_IO_MC_REGS_SIZE;  		break; +	case CHIP_HAWAII: +		io_mc_regs = (u32 *)&hawaii_io_mc_regs; +		regs_size = HAWAII_IO_MC_REGS_SIZE; +		break; +	default: +		return -EINVAL;  	}  	running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; @@ -1562,8 +1842,8 @@ static int cik_init_microcode(struct radeon_device *rdev)  {  	const char *chip_name;  	size_t pfp_req_size, me_req_size, ce_req_size, -		mec_req_size, rlc_req_size, mc_req_size, -		sdma_req_size, smc_req_size; +		mec_req_size, rlc_req_size, mc_req_size = 0, +		sdma_req_size, smc_req_size = 0, mc2_req_size = 0;  	char fw_name[30];  	int err; @@ -1577,10 +1857,23 @@ static int cik_init_microcode(struct radeon_device *rdev)  		ce_req_size = CIK_CE_UCODE_SIZE * 4;  		mec_req_size = CIK_MEC_UCODE_SIZE * 4;  		rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4; -		mc_req_size = CIK_MC_UCODE_SIZE * 4; +		mc_req_size = BONAIRE_MC_UCODE_SIZE * 4; +		mc2_req_size = BONAIRE_MC2_UCODE_SIZE * 4;  		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;  		smc_req_size = ALIGN(BONAIRE_SMC_UCODE_SIZE, 4);  		break; +	case CHIP_HAWAII: +		chip_name = "HAWAII"; +		pfp_req_size = CIK_PFP_UCODE_SIZE * 4; +		me_req_size = CIK_ME_UCODE_SIZE * 4; +		ce_req_size = CIK_CE_UCODE_SIZE * 4; +		mec_req_size = CIK_MEC_UCODE_SIZE * 4; +		rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4; +		mc_req_size = HAWAII_MC_UCODE_SIZE * 4; +		mc2_req_size = HAWAII_MC2_UCODE_SIZE * 4; +		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; +		smc_req_size = ALIGN(HAWAII_SMC_UCODE_SIZE, 4); +		break;  	case CHIP_KAVERI:  		chip_name = "KAVERI";  		pfp_req_size = CIK_PFP_UCODE_SIZE * 4; @@ -1599,6 +1892,15 @@ static int cik_init_microcode(struct radeon_device *rdev)  		rlc_req_size = KB_RLC_UCODE_SIZE * 4;  		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;  		break; +	case CHIP_MULLINS: +		chip_name = "MULLINS"; +		pfp_req_size = CIK_PFP_UCODE_SIZE * 4; +		me_req_size = CIK_ME_UCODE_SIZE * 4; +		ce_req_size = CIK_CE_UCODE_SIZE * 4; +		mec_req_size = CIK_MEC_UCODE_SIZE * 4; +		rlc_req_size = ML_RLC_UCODE_SIZE * 4; +		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; +		break;  	default: BUG();  	} @@ -1673,16 +1975,22 @@ static int cik_init_microcode(struct radeon_device *rdev)  	/* No SMC, MC ucode on APUs */  	if (!(rdev->flags & RADEON_IS_IGP)) { -		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); +		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name);  		err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); -		if (err) -			goto out; -		if (rdev->mc_fw->size != mc_req_size) { +		if (err) { +			snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); +			err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); +			if (err) +				goto out; +		} +		if ((rdev->mc_fw->size != mc_req_size) && +		    (rdev->mc_fw->size != mc2_req_size)){  			printk(KERN_ERR  			       "cik_mc: Bogus length %zu in firmware \"%s\"\n",  			       rdev->mc_fw->size, fw_name);  			err = -EINVAL;  		} +		DRM_INFO("%s: %zu bytes\n", fw_name, rdev->mc_fw->size);  		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);  		err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); @@ -1692,6 +2000,7 @@ static int cik_init_microcode(struct radeon_device *rdev)  			       fw_name);  			release_firmware(rdev->smc_fw);  			rdev->smc_fw = NULL; +			err = 0;  		} else if (rdev->smc_fw->size != smc_req_size) {  			printk(KERN_ERR  			       "cik_smc: Bogus length %zu in firmware \"%s\"\n", @@ -1760,9 +2069,232 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  	num_pipe_configs = rdev->config.cik.max_tile_pipes;  	if (num_pipe_configs > 8) -		num_pipe_configs = 8; /* ??? */ +		num_pipe_configs = 16; -	if (num_pipe_configs == 8) { +	if (num_pipe_configs == 16) { +		for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { +			switch (reg_offset) { +			case 0: +				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); +				break; +			case 1: +				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); +				break; +			case 2: +				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); +				break; +			case 3: +				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); +				break; +			case 4: +				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 TILE_SPLIT(split_equal_to_row_size)); +				break; +			case 5: +				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); +				break; +			case 6: +				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); +				break; +			case 7: +				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 TILE_SPLIT(split_equal_to_row_size)); +				break; +			case 8: +				gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16)); +				break; +			case 9: +				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); +				break; +			case 10: +				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			case 11: +				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			case 12: +				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			case 13: +				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); +				break; +			case 14: +				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			case 16: +				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			case 17: +				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			case 27: +				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); +				break; +			case 28: +				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			case 29: +				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			case 30: +				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | +						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | +						 SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); +				break; +			default: +				gb_tile_moden = 0; +				break; +			} +			rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden; +			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); +		} +		for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) { +			switch (reg_offset) { +			case 0: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | +						 NUM_BANKS(ADDR_SURF_16_BANK)); +				break; +			case 1: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | +						 NUM_BANKS(ADDR_SURF_16_BANK)); +				break; +			case 2: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_16_BANK)); +				break; +			case 3: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_16_BANK)); +				break; +			case 4: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_8_BANK)); +				break; +			case 5: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_4_BANK)); +				break; +			case 6: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_2_BANK)); +				break; +			case 8: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | +						 NUM_BANKS(ADDR_SURF_16_BANK)); +				break; +			case 9: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | +						 NUM_BANKS(ADDR_SURF_16_BANK)); +				break; +			case 10: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_16_BANK)); +				break; +			case 11: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_8_BANK)); +				break; +			case 12: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_4_BANK)); +				break; +			case 13: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_2_BANK)); +				break; +			case 14: +				gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | +						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | +						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | +						 NUM_BANKS(ADDR_SURF_2_BANK)); +				break; +			default: +				gb_tile_moden = 0; +				break; +			} +			rdev->config.cik.macrotile_mode_array[reg_offset] = gb_tile_moden; +			WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden); +		} +	} else if (num_pipe_configs == 8) {  		for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {  			switch (reg_offset) {  			case 0: @@ -1797,6 +2329,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				break;  			case 5:  				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |  						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));  				break;  			case 6: @@ -1817,6 +2350,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				break;  			case 9:  				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |  						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));  				break;  			case 10: @@ -1839,6 +2373,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				break;  			case 13:  				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |  						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));  				break;  			case 14: @@ -1861,6 +2396,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				break;  			case 27:  				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |  						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));  				break;  			case 28: @@ -1978,6 +2514,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				gb_tile_moden = 0;  				break;  			} +			rdev->config.cik.macrotile_mode_array[reg_offset] = gb_tile_moden;  			WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);  		}  	} else if (num_pipe_configs == 4) { @@ -2016,6 +2553,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  					break;  				case 5:  					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |  							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));  					break;  				case 6: @@ -2036,6 +2574,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  					break;  				case 9:  					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |  							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));  					break;  				case 10: @@ -2058,6 +2597,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  					break;  				case 13:  					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |  							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));  					break;  				case 14: @@ -2080,6 +2620,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  					break;  				case 27:  					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +							 PIPE_CONFIG(ADDR_SURF_P4_16x16) |  							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));  					break;  				case 28: @@ -2142,6 +2683,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  					break;  				case 5:  					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |  							 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));  					break;  				case 6: @@ -2162,6 +2704,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  					break;  				case 9:  					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |  							 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));  					break;  				case 10: @@ -2184,6 +2727,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  					break;  				case 13:  					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |  							 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));  					break;  				case 14: @@ -2206,6 +2750,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  					break;  				case 27:  					gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +							 PIPE_CONFIG(ADDR_SURF_P4_8x16) |  							 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));  					break;  				case 28: @@ -2324,6 +2869,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				gb_tile_moden = 0;  				break;  			} +			rdev->config.cik.macrotile_mode_array[reg_offset] = gb_tile_moden;  			WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);  		}  	} else if (num_pipe_configs == 2) { @@ -2361,6 +2907,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				break;  			case 5:  				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P2) |  						 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));  				break;  			case 6: @@ -2376,11 +2923,13 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  						 TILE_SPLIT(split_equal_to_row_size));  				break;  			case 8: -				gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED); +				gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | +						PIPE_CONFIG(ADDR_SURF_P2);  				break;  			case 9:  				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | -						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); +						 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P2));  				break;  			case 10:  				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | @@ -2402,6 +2951,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				break;  			case 13:  				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | +						 PIPE_CONFIG(ADDR_SURF_P2) |  						 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));  				break;  			case 14: @@ -2424,7 +2974,8 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				break;  			case 27:  				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | -						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); +						 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | +						 PIPE_CONFIG(ADDR_SURF_P2));  				break;  			case 28:  				gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | @@ -2541,6 +3092,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)  				gb_tile_moden = 0;  				break;  			} +			rdev->config.cik.macrotile_mode_array[reg_offset] = gb_tile_moden;  			WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);  		}  	} else @@ -2594,7 +3146,7 @@ static u32 cik_create_bitmask(u32 bit_width)  }  /** - * cik_select_se_sh - select which SE, SH to address + * cik_get_rb_disabled - computes the mask of disabled RBs   *   * @rdev: radeon_device pointer   * @max_rb_num: max RBs (render backends) for the asic @@ -2605,7 +3157,7 @@ static u32 cik_create_bitmask(u32 bit_width)   * Returns the disabled RB bitmask.   */  static u32 cik_get_rb_disabled(struct radeon_device *rdev, -			      u32 max_rb_num, u32 se_num, +			      u32 max_rb_num_per_se,  			      u32 sh_per_se)  {  	u32 data, mask; @@ -2619,7 +3171,7 @@ static u32 cik_get_rb_disabled(struct radeon_device *rdev,  	data >>= BACKEND_DISABLE_SHIFT; -	mask = cik_create_bitmask(max_rb_num / se_num / sh_per_se); +	mask = cik_create_bitmask(max_rb_num_per_se / sh_per_se);  	return data & mask;  } @@ -2636,7 +3188,7 @@ static u32 cik_get_rb_disabled(struct radeon_device *rdev,   */  static void cik_setup_rb(struct radeon_device *rdev,  			 u32 se_num, u32 sh_per_se, -			 u32 max_rb_num) +			 u32 max_rb_num_per_se)  {  	int i, j;  	u32 data, mask; @@ -2646,24 +3198,35 @@ static void cik_setup_rb(struct radeon_device *rdev,  	for (i = 0; i < se_num; i++) {  		for (j = 0; j < sh_per_se; j++) {  			cik_select_se_sh(rdev, i, j); -			data = cik_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se); -			disabled_rbs |= data << ((i * sh_per_se + j) * CIK_RB_BITMAP_WIDTH_PER_SH); +			data = cik_get_rb_disabled(rdev, max_rb_num_per_se, sh_per_se); +			if (rdev->family == CHIP_HAWAII) +				disabled_rbs |= data << ((i * sh_per_se + j) * HAWAII_RB_BITMAP_WIDTH_PER_SH); +			else +				disabled_rbs |= data << ((i * sh_per_se + j) * CIK_RB_BITMAP_WIDTH_PER_SH);  		}  	}  	cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);  	mask = 1; -	for (i = 0; i < max_rb_num; i++) { +	for (i = 0; i < max_rb_num_per_se * se_num; i++) {  		if (!(disabled_rbs & mask))  			enabled_rbs |= mask;  		mask <<= 1;  	} +	rdev->config.cik.backend_enable_mask = enabled_rbs; +  	for (i = 0; i < se_num; i++) {  		cik_select_se_sh(rdev, i, 0xffffffff);  		data = 0;  		for (j = 0; j < sh_per_se; j++) {  			switch (enabled_rbs & 3) { +			case 0: +				if (j == 0) +					data |= PKR_MAP(RASTER_CONFIG_RB_MAP_3); +				else +					data |= PKR_MAP(RASTER_CONFIG_RB_MAP_0); +				break;  			case 1:  				data |= (RASTER_CONFIG_RB_MAP_0 << (i * sh_per_se + j) * 2);  				break; @@ -2696,7 +3259,7 @@ static void cik_gpu_init(struct radeon_device *rdev)  	u32 mc_shared_chmap, mc_arb_ramcfg;  	u32 hdp_host_path_cntl;  	u32 tmp; -	int i, j; +	int i, j, k;  	switch (rdev->family) {  	case CHIP_BONAIRE: @@ -2716,6 +3279,23 @@ static void cik_gpu_init(struct radeon_device *rdev)  		rdev->config.cik.sc_earlyz_tile_fifo_size = 0x130;  		gb_addr_config = BONAIRE_GB_ADDR_CONFIG_GOLDEN;  		break; +	case CHIP_HAWAII: +		rdev->config.cik.max_shader_engines = 4; +		rdev->config.cik.max_tile_pipes = 16; +		rdev->config.cik.max_cu_per_sh = 11; +		rdev->config.cik.max_sh_per_se = 1; +		rdev->config.cik.max_backends_per_se = 4; +		rdev->config.cik.max_texture_channel_caches = 16; +		rdev->config.cik.max_gprs = 256; +		rdev->config.cik.max_gs_threads = 32; +		rdev->config.cik.max_hw_contexts = 8; + +		rdev->config.cik.sc_prim_fifo_size_frontend = 0x20; +		rdev->config.cik.sc_prim_fifo_size_backend = 0x100; +		rdev->config.cik.sc_hiz_tile_fifo_size = 0x30; +		rdev->config.cik.sc_earlyz_tile_fifo_size = 0x130; +		gb_addr_config = HAWAII_GB_ADDR_CONFIG_GOLDEN; +		break;  	case CHIP_KAVERI:  		rdev->config.cik.max_shader_engines = 1;  		rdev->config.cik.max_tile_pipes = 4; @@ -2760,6 +3340,7 @@ static void cik_gpu_init(struct radeon_device *rdev)  		gb_addr_config = BONAIRE_GB_ADDR_CONFIG_GOLDEN;  		break;  	case CHIP_KABINI: +	case CHIP_MULLINS:  	default:  		rdev->config.cik.max_shader_engines = 1;  		rdev->config.cik.max_tile_pipes = 2; @@ -2867,6 +3448,15 @@ static void cik_gpu_init(struct radeon_device *rdev)  		     rdev->config.cik.max_sh_per_se,  		     rdev->config.cik.max_backends_per_se); +	for (i = 0; i < rdev->config.cik.max_shader_engines; i++) { +		for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) { +			for (k = 0; k < rdev->config.cik.max_cu_per_sh; k++) { +				rdev->config.cik.active_cus += +					hweight32(cik_get_cu_active_bitmap(rdev, i, j)); +			} +		} +	} +  	/* set HW defaults for 3D engine */  	WREG32(CP_MEQ_THRESHOLDS, MEQ1_START(0x30) | MEQ2_START(0x60)); @@ -3007,6 +3597,51 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)  }  /** + * cik_hdp_flush_cp_ring_emit - emit an hdp flush on the cp + * + * @rdev: radeon_device pointer + * @ridx: radeon ring index + * + * Emits an hdp flush on the cp. + */ +static void cik_hdp_flush_cp_ring_emit(struct radeon_device *rdev, +				       int ridx) +{ +	struct radeon_ring *ring = &rdev->ring[ridx]; +	u32 ref_and_mask; + +	switch (ring->idx) { +	case CAYMAN_RING_TYPE_CP1_INDEX: +	case CAYMAN_RING_TYPE_CP2_INDEX: +	default: +		switch (ring->me) { +		case 0: +			ref_and_mask = CP2 << ring->pipe; +			break; +		case 1: +			ref_and_mask = CP6 << ring->pipe; +			break; +		default: +			return; +		} +		break; +	case RADEON_RING_TYPE_GFX_INDEX: +		ref_and_mask = CP0; +		break; +	} + +	radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); +	radeon_ring_write(ring, (WAIT_REG_MEM_OPERATION(1) | /* write, wait, write */ +				 WAIT_REG_MEM_FUNCTION(3) |  /* == */ +				 WAIT_REG_MEM_ENGINE(1)));   /* pfp */ +	radeon_ring_write(ring, GPU_HDP_FLUSH_REQ >> 2); +	radeon_ring_write(ring, GPU_HDP_FLUSH_DONE >> 2); +	radeon_ring_write(ring, ref_and_mask); +	radeon_ring_write(ring, ref_and_mask); +	radeon_ring_write(ring, 0x20); /* poll interval */ +} + +/**   * cik_fence_gfx_ring_emit - emit a fence on the gfx ring   *   * @rdev: radeon_device pointer @@ -3032,15 +3667,7 @@ void cik_fence_gfx_ring_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, fence->seq);  	radeon_ring_write(ring, 0);  	/* HDP flush */ -	/* We should be using the new WAIT_REG_MEM special op packet here -	 * but it causes the CP to hang -	 */ -	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); -	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | -				 WRITE_DATA_DST_SEL(0))); -	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); -	radeon_ring_write(ring, 0); -	radeon_ring_write(ring, 0); +	cik_hdp_flush_cp_ring_emit(rdev, fence->ring);  }  /** @@ -3070,18 +3697,10 @@ void cik_fence_compute_ring_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, fence->seq);  	radeon_ring_write(ring, 0);  	/* HDP flush */ -	/* We should be using the new WAIT_REG_MEM special op packet here -	 * but it causes the CP to hang -	 */ -	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); -	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | -				 WRITE_DATA_DST_SEL(0))); -	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); -	radeon_ring_write(ring, 0); -	radeon_ring_write(ring, 0); +	cik_hdp_flush_cp_ring_emit(rdev, fence->ring);  } -void cik_semaphore_ring_emit(struct radeon_device *rdev, +bool cik_semaphore_ring_emit(struct radeon_device *rdev,  			     struct radeon_ring *ring,  			     struct radeon_semaphore *semaphore,  			     bool emit_wait) @@ -3090,8 +3709,85 @@ void cik_semaphore_ring_emit(struct radeon_device *rdev,  	unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;  	radeon_ring_write(ring, PACKET3(PACKET3_MEM_SEMAPHORE, 1)); -	radeon_ring_write(ring, addr & 0xffffffff); +	radeon_ring_write(ring, lower_32_bits(addr));  	radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel); + +	return true; +} + +/** + * cik_copy_cpdma - copy pages using the CP DMA engine + * + * @rdev: radeon_device pointer + * @src_offset: src GPU address + * @dst_offset: dst GPU address + * @num_gpu_pages: number of GPU pages to xfer + * @fence: radeon fence object + * + * Copy GPU paging using the CP DMA engine (CIK+). + * Used by the radeon ttm implementation to move pages if + * registered as the asic copy callback. + */ +int cik_copy_cpdma(struct radeon_device *rdev, +		   uint64_t src_offset, uint64_t dst_offset, +		   unsigned num_gpu_pages, +		   struct radeon_fence **fence) +{ +	struct radeon_semaphore *sem = NULL; +	int ring_index = rdev->asic->copy.blit_ring_index; +	struct radeon_ring *ring = &rdev->ring[ring_index]; +	u32 size_in_bytes, cur_size_in_bytes, control; +	int i, num_loops; +	int r = 0; + +	r = radeon_semaphore_create(rdev, &sem); +	if (r) { +		DRM_ERROR("radeon: moving bo (%d).\n", r); +		return r; +	} + +	size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT); +	num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff); +	r = radeon_ring_lock(rdev, ring, num_loops * 7 + 18); +	if (r) { +		DRM_ERROR("radeon: moving bo (%d).\n", r); +		radeon_semaphore_free(rdev, &sem, NULL); +		return r; +	} + +	radeon_semaphore_sync_to(sem, *fence); +	radeon_semaphore_sync_rings(rdev, sem, ring->idx); + +	for (i = 0; i < num_loops; i++) { +		cur_size_in_bytes = size_in_bytes; +		if (cur_size_in_bytes > 0x1fffff) +			cur_size_in_bytes = 0x1fffff; +		size_in_bytes -= cur_size_in_bytes; +		control = 0; +		if (size_in_bytes == 0) +			control |= PACKET3_DMA_DATA_CP_SYNC; +		radeon_ring_write(ring, PACKET3(PACKET3_DMA_DATA, 5)); +		radeon_ring_write(ring, control); +		radeon_ring_write(ring, lower_32_bits(src_offset)); +		radeon_ring_write(ring, upper_32_bits(src_offset)); +		radeon_ring_write(ring, lower_32_bits(dst_offset)); +		radeon_ring_write(ring, upper_32_bits(dst_offset)); +		radeon_ring_write(ring, cur_size_in_bytes); +		src_offset += cur_size_in_bytes; +		dst_offset += cur_size_in_bytes; +	} + +	r = radeon_fence_emit(rdev, fence, ring->idx); +	if (r) { +		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL); +		return r; +	} + +	radeon_ring_unlock_commit(rdev, ring); +	radeon_semaphore_free(rdev, &sem, *fence); + +	return r;  }  /* @@ -3133,7 +3829,7 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)  			radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));  			radeon_ring_write(ring, WRITE_DATA_DST_SEL(1));  			radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); -			radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff); +			radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr));  			radeon_ring_write(ring, next_rptr);  		} @@ -3180,6 +3876,7 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)  	r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);  	if (r) {  		DRM_ERROR("radeon: failed to get ib (%d).\n", r); +		radeon_scratch_free(rdev, scratch);  		return r;  	}  	ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); @@ -3196,6 +3893,8 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)  	r = radeon_fence_wait(ib.fence, false);  	if (r) {  		DRM_ERROR("radeon: fence wait failed (%d).\n", r); +		radeon_scratch_free(rdev, scratch); +		radeon_ib_free(rdev, &ib);  		return r;  	}  	for (i = 0; i < rdev->usec_timeout; i++) { @@ -3252,6 +3951,8 @@ static void cik_cp_gfx_enable(struct radeon_device *rdev, bool enable)  	if (enable)  		WREG32(CP_ME_CNTL, 0);  	else { +		if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +			radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);  		WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));  		rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;  	} @@ -3397,7 +4098,8 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)  	int r;  	WREG32(CP_SEM_WAIT_TIMER, 0x0); -	WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0); +	if (rdev->family != CHIP_HAWAII) +		WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0);  	/* Set the write pointer delay */  	WREG32(CP_RB_WPTR_DELAY, 0); @@ -3439,8 +4141,6 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)  	WREG32(CP_RB0_BASE, rb_addr);  	WREG32(CP_RB0_BASE_HI, upper_32_bits(rb_addr)); -	ring->rptr = RREG32(CP_RB0_RPTR); -  	/* start the ring */  	cik_cp_gfx_start(rdev);  	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = true; @@ -3449,18 +4149,50 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)  		rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;  		return r;  	} + +	if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); +  	return 0;  } -u32 cik_compute_ring_get_rptr(struct radeon_device *rdev, -			      struct radeon_ring *ring) +u32 cik_gfx_get_rptr(struct radeon_device *rdev, +		     struct radeon_ring *ring)  {  	u32 rptr; +	if (rdev->wb.enabled) +		rptr = rdev->wb.wb[ring->rptr_offs/4]; +	else +		rptr = RREG32(CP_RB0_RPTR); + +	return rptr; +} + +u32 cik_gfx_get_wptr(struct radeon_device *rdev, +		     struct radeon_ring *ring) +{ +	u32 wptr; + +	wptr = RREG32(CP_RB0_WPTR); + +	return wptr; +} + +void cik_gfx_set_wptr(struct radeon_device *rdev, +		      struct radeon_ring *ring) +{ +	WREG32(CP_RB0_WPTR, ring->wptr); +	(void)RREG32(CP_RB0_WPTR); +} +u32 cik_compute_get_rptr(struct radeon_device *rdev, +			 struct radeon_ring *ring) +{ +	u32 rptr;  	if (rdev->wb.enabled) { -		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); +		rptr = rdev->wb.wb[ring->rptr_offs/4];  	} else {  		mutex_lock(&rdev->srbm_mutex);  		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); @@ -3472,13 +4204,14 @@ u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,  	return rptr;  } -u32 cik_compute_ring_get_wptr(struct radeon_device *rdev, -			      struct radeon_ring *ring) +u32 cik_compute_get_wptr(struct radeon_device *rdev, +			 struct radeon_ring *ring)  {  	u32 wptr;  	if (rdev->wb.enabled) { -		wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]); +		/* XXX check if swapping is necessary on BE */ +		wptr = rdev->wb.wb[ring->wptr_offs/4];  	} else {  		mutex_lock(&rdev->srbm_mutex);  		cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); @@ -3490,11 +4223,12 @@ u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,  	return wptr;  } -void cik_compute_ring_set_wptr(struct radeon_device *rdev, -			       struct radeon_ring *ring) +void cik_compute_set_wptr(struct radeon_device *rdev, +			  struct radeon_ring *ring)  { -	rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(ring->wptr); -	WDOORBELL32(ring->doorbell_offset, ring->wptr); +	/* XXX check if swapping is necessary on BE */ +	rdev->wb.wb[ring->wptr_offs/4] = ring->wptr; +	WDOORBELL32(ring->doorbell_index, ring->wptr);  }  /** @@ -3509,8 +4243,11 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable)  {  	if (enable)  		WREG32(CP_MEC_CNTL, 0); -	else +	else {  		WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT)); +		rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false; +		rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false; +	}  	udelay(50);  } @@ -3835,10 +4572,6 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)  			return r;  		} -		/* doorbell offset */ -		rdev->ring[idx].doorbell_offset = -			(rdev->ring[idx].doorbell_page_num * PAGE_SIZE) + 0; -  		/* init the mqd struct */  		memset(buf, 0, sizeof(struct bonaire_mqd)); @@ -3950,7 +4683,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)  				RREG32(CP_HQD_PQ_DOORBELL_CONTROL);  			mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_OFFSET_MASK;  			mqd->queue_state.cp_hqd_pq_doorbell_control |= -				DOORBELL_OFFSET(rdev->ring[idx].doorbell_offset / 4); +				DOORBELL_OFFSET(rdev->ring[idx].doorbell_index);  			mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;  			mqd->queue_state.cp_hqd_pq_doorbell_control &=  				~(DOORBELL_SOURCE | DOORBELL_HIT); @@ -3965,8 +4698,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)  		rdev->ring[idx].wptr = 0;  		mqd->queue_state.cp_hqd_pq_wptr = rdev->ring[idx].wptr;  		WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr); -		rdev->ring[idx].rptr = RREG32(CP_HQD_PQ_RPTR); -		mqd->queue_state.cp_hqd_pq_rptr = rdev->ring[idx].rptr; +		mqd->queue_state.cp_hqd_pq_rptr = RREG32(CP_HQD_PQ_RPTR);  		/* set the vmid for the queue */  		mqd->queue_state.cp_hqd_vmid = 0; @@ -4185,6 +4917,10 @@ static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)  	dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",  		 RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); +	/* disable CG/PG */ +	cik_fini_pg(rdev); +	cik_fini_cg(rdev); +  	/* stop the rlc */  	cik_rlc_stop(rdev); @@ -4287,6 +5023,160 @@ static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)  	cik_print_gpu_status_regs(rdev);  } +struct kv_reset_save_regs { +	u32 gmcon_reng_execute; +	u32 gmcon_misc; +	u32 gmcon_misc3; +}; + +static void kv_save_regs_for_reset(struct radeon_device *rdev, +				   struct kv_reset_save_regs *save) +{ +	save->gmcon_reng_execute = RREG32(GMCON_RENG_EXECUTE); +	save->gmcon_misc = RREG32(GMCON_MISC); +	save->gmcon_misc3 = RREG32(GMCON_MISC3); + +	WREG32(GMCON_RENG_EXECUTE, save->gmcon_reng_execute & ~RENG_EXECUTE_ON_PWR_UP); +	WREG32(GMCON_MISC, save->gmcon_misc & ~(RENG_EXECUTE_ON_REG_UPDATE | +						STCTRL_STUTTER_EN)); +} + +static void kv_restore_regs_for_reset(struct radeon_device *rdev, +				      struct kv_reset_save_regs *save) +{ +	int i; + +	WREG32(GMCON_PGFSM_WRITE, 0); +	WREG32(GMCON_PGFSM_CONFIG, 0x200010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0); +	WREG32(GMCON_PGFSM_CONFIG, 0x300010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0x210000); +	WREG32(GMCON_PGFSM_CONFIG, 0xa00010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0x21003); +	WREG32(GMCON_PGFSM_CONFIG, 0xb00010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0x2b00); +	WREG32(GMCON_PGFSM_CONFIG, 0xc00010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0); +	WREG32(GMCON_PGFSM_CONFIG, 0xd00010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0x420000); +	WREG32(GMCON_PGFSM_CONFIG, 0x100010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0x120202); +	WREG32(GMCON_PGFSM_CONFIG, 0x500010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0x3e3e36); +	WREG32(GMCON_PGFSM_CONFIG, 0x600010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0x373f3e); +	WREG32(GMCON_PGFSM_CONFIG, 0x700010ff); + +	for (i = 0; i < 5; i++) +		WREG32(GMCON_PGFSM_WRITE, 0); + +	WREG32(GMCON_PGFSM_WRITE, 0x3e1332); +	WREG32(GMCON_PGFSM_CONFIG, 0xe00010ff); + +	WREG32(GMCON_MISC3, save->gmcon_misc3); +	WREG32(GMCON_MISC, save->gmcon_misc); +	WREG32(GMCON_RENG_EXECUTE, save->gmcon_reng_execute); +} + +static void cik_gpu_pci_config_reset(struct radeon_device *rdev) +{ +	struct evergreen_mc_save save; +	struct kv_reset_save_regs kv_save = { 0 }; +	u32 tmp, i; + +	dev_info(rdev->dev, "GPU pci config reset\n"); + +	/* disable dpm? */ + +	/* disable cg/pg */ +	cik_fini_pg(rdev); +	cik_fini_cg(rdev); + +	/* Disable GFX parsing/prefetching */ +	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); + +	/* Disable MEC parsing/prefetching */ +	WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT); + +	/* sdma0 */ +	tmp = RREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET); +	tmp |= SDMA_HALT; +	WREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET, tmp); +	/* sdma1 */ +	tmp = RREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET); +	tmp |= SDMA_HALT; +	WREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET, tmp); +	/* XXX other engines? */ + +	/* halt the rlc, disable cp internal ints */ +	cik_rlc_stop(rdev); + +	udelay(50); + +	/* disable mem access */ +	evergreen_mc_stop(rdev, &save); +	if (evergreen_mc_wait_for_idle(rdev)) { +		dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); +	} + +	if (rdev->flags & RADEON_IS_IGP) +		kv_save_regs_for_reset(rdev, &kv_save); + +	/* disable BM */ +	pci_clear_master(rdev->pdev); +	/* reset */ +	radeon_pci_config_reset(rdev); + +	udelay(100); + +	/* wait for asic to come out of reset */ +	for (i = 0; i < rdev->usec_timeout; i++) { +		if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) +			break; +		udelay(1); +	} + +	/* does asic init need to be run first??? */ +	if (rdev->flags & RADEON_IS_IGP) +		kv_restore_regs_for_reset(rdev, &kv_save); +} +  /**   * cik_asic_reset - soft reset GPU   * @@ -4305,10 +5195,17 @@ int cik_asic_reset(struct radeon_device *rdev)  	if (reset_mask)  		r600_set_bios_scratch_engine_hung(rdev, true); +	/* try soft reset */  	cik_gpu_soft_reset(rdev, reset_mask);  	reset_mask = cik_gpu_check_soft_reset(rdev); +	/* try pci config reset */ +	if (reset_mask && radeon_hard_reset) +		cik_gpu_pci_config_reset(rdev); + +	reset_mask = cik_gpu_check_soft_reset(rdev); +  	if (!reset_mask)  		r600_set_bios_scratch_engine_hung(rdev, false); @@ -4331,11 +5228,9 @@ bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	if (!(reset_mask & (RADEON_RESET_GFX |  			    RADEON_RESET_COMPUTE |  			    RADEON_RESET_CP))) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force CP activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -4512,6 +5407,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)  	WREG32(MC_VM_MX_L1_TLB_CNTL,  	       (0xA << 7) |  	       ENABLE_L1_TLB | +	       ENABLE_L1_FRAGMENT_PROCESSING |  	       SYSTEM_ACCESS_MODE_NOT_IN_SYS |  	       ENABLE_ADVANCED_DRIVER_MODEL |  	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU); @@ -4524,7 +5420,8 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)  	       CONTEXT1_IDENTITY_ACCESS_MODE(1));  	WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);  	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY | -	       L2_CACHE_BIGK_FRAGMENT_SIZE(6)); +	       BANK_SELECT(4) | +	       L2_CACHE_BIGK_FRAGMENT_SIZE(4));  	/* setup context0 */  	WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);  	WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12); @@ -4560,6 +5457,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)  	       (u32)(rdev->dummy_page.addr >> 12));  	WREG32(VM_CONTEXT1_CNTL2, 4);  	WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) | +				PAGE_TABLE_BLOCK_SIZE(radeon_vm_block_size - 9) |  				RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |  				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |  				DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT | @@ -4573,20 +5471,6 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)  				WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT |  				WRITE_PROTECTION_FAULT_ENABLE_DEFAULT); -	/* TC cache setup ??? */ -	WREG32(TC_CFG_L1_LOAD_POLICY0, 0); -	WREG32(TC_CFG_L1_LOAD_POLICY1, 0); -	WREG32(TC_CFG_L1_STORE_POLICY, 0); - -	WREG32(TC_CFG_L2_LOAD_POLICY0, 0); -	WREG32(TC_CFG_L2_LOAD_POLICY1, 0); -	WREG32(TC_CFG_L2_STORE_POLICY0, 0); -	WREG32(TC_CFG_L2_STORE_POLICY1, 0); -	WREG32(TC_CFG_L2_ATOMIC_POLICY, 0); - -	WREG32(TC_CFG_L1_VOLATILE, 0); -	WREG32(TC_CFG_L2_VOLATILE, 0); -  	if (rdev->family == CHIP_KAVERI) {  		u32 tmp = RREG32(CHUB_CONTROL);  		tmp &= ~BYPASS_VM; @@ -4730,12 +5614,17 @@ void cik_vm_fini(struct radeon_device *rdev)  static void cik_vm_decode_fault(struct radeon_device *rdev,  				u32 status, u32 addr, u32 mc_client)  { -	u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; +	u32 mc_id;  	u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT;  	u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT;  	char block[5] = { mc_client >> 24, (mc_client >> 16) & 0xff,  		(mc_client >> 8) & 0xff, mc_client & 0xff, 0 }; +	if (rdev->family == CHIP_HAWAII) +		mc_id = (status & HAWAII_MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; +	else +		mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; +  	printk("VM fault (0x%02x, vmid %d) at page %u, %s from '%s' (0x%08x) (%d)\n",  	       protections, vmid, addr,  	       (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", @@ -4797,16 +5686,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)  	radeon_ring_write(ring, VMID(0));  	/* HDP flush */ -	/* We should be using the WAIT_REG_MEM packet here like in -	 * cik_fence_ring_emit(), but it causes the CP to hang in this -	 * context... -	 */ -	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); -	radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | -				 WRITE_DATA_DST_SEL(0))); -	radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); -	radeon_ring_write(ring, 0); -	radeon_ring_write(ring, 0); +	cik_hdp_flush_cp_ring_emit(rdev, ridx);  	/* bits 0-15 are the VM contexts0-15 */  	radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); @@ -4824,62 +5704,6 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)  	}  } -/** - * cik_vm_set_page - update the page tables using sDMA - * - * @rdev: radeon_device pointer - * @ib: indirect buffer to fill with commands - * @pe: addr of the page entry - * @addr: dst addr to write into pe - * @count: number of page entries to update - * @incr: increase next addr by incr bytes - * @flags: access flags - * - * Update the page tables using CP or sDMA (CIK). - */ -void cik_vm_set_page(struct radeon_device *rdev, -		     struct radeon_ib *ib, -		     uint64_t pe, -		     uint64_t addr, unsigned count, -		     uint32_t incr, uint32_t flags) -{ -	uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); -	uint64_t value; -	unsigned ndw; - -	if (rdev->asic->vm.pt_ring_index == RADEON_RING_TYPE_GFX_INDEX) { -		/* CP */ -		while (count) { -			ndw = 2 + count * 2; -			if (ndw > 0x3FFE) -				ndw = 0x3FFE; - -			ib->ptr[ib->length_dw++] = PACKET3(PACKET3_WRITE_DATA, ndw); -			ib->ptr[ib->length_dw++] = (WRITE_DATA_ENGINE_SEL(0) | -						    WRITE_DATA_DST_SEL(1)); -			ib->ptr[ib->length_dw++] = pe; -			ib->ptr[ib->length_dw++] = upper_32_bits(pe); -			for (; ndw > 2; ndw -= 2, --count, pe += 8) { -				if (flags & RADEON_VM_PAGE_SYSTEM) { -					value = radeon_vm_map_gart(rdev, addr); -					value &= 0xFFFFFFFFFFFFF000ULL; -				} else if (flags & RADEON_VM_PAGE_VALID) { -					value = addr; -				} else { -					value = 0; -				} -				addr += incr; -				value |= r600_flags; -				ib->ptr[ib->length_dw++] = value; -				ib->ptr[ib->length_dw++] = upper_32_bits(value); -			} -		} -	} else { -		/* DMA */ -		cik_sdma_vm_set_page(rdev, ib, pe, addr, count, incr, flags); -	} -} -  /*   * RLC   * The RLC is a multi-purpose microengine that handles a @@ -5048,6 +5872,7 @@ static int cik_rlc_resume(struct radeon_device *rdev)  	switch (rdev->family) {  	case CHIP_BONAIRE: +	case CHIP_HAWAII:  	default:  		size = BONAIRE_RLC_UCODE_SIZE;  		break; @@ -5057,6 +5882,9 @@ static int cik_rlc_resume(struct radeon_device *rdev)  	case CHIP_KABINI:  		size = KB_RLC_UCODE_SIZE;  		break; +	case CHIP_MULLINS: +		size = ML_RLC_UCODE_SIZE; +		break;  	}  	cik_rlc_stop(rdev); @@ -5428,6 +6256,10 @@ void cik_update_cg(struct radeon_device *rdev,  		cik_enable_hdp_mgcg(rdev, enable);  		cik_enable_hdp_ls(rdev, enable);  	} + +	if (block & RADEON_CG_BLOCK_VCE) { +		vce_v2_0_enable_mgcg(rdev, enable); +	}  }  static void cik_init_cg(struct radeon_device *rdev) @@ -5546,7 +6378,7 @@ void cik_init_cp_pg_table(struct radeon_device *rdev)  		}  		for (i = 0; i < CP_ME_TABLE_SIZE; i ++) { -			dst_ptr[bo_offset + i] = be32_to_cpu(fw_data[table_offset + i]); +			dst_ptr[bo_offset + i] = cpu_to_le32(be32_to_cpu(fw_data[table_offset + i]));  		}  		bo_offset += CP_ME_TABLE_SIZE;  	} @@ -5768,52 +6600,58 @@ void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer)  	if (buffer == NULL)  		return; -	buffer[count++] = PACKET3(PACKET3_PREAMBLE_CNTL, 0); -	buffer[count++] = PACKET3_PREAMBLE_BEGIN_CLEAR_STATE; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0)); +	buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_BEGIN_CLEAR_STATE); -	buffer[count++] = PACKET3(PACKET3_CONTEXT_CONTROL, 1); -	buffer[count++] = 0x80000000; -	buffer[count++] = 0x80000000; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_CONTEXT_CONTROL, 1)); +	buffer[count++] = cpu_to_le32(0x80000000); +	buffer[count++] = cpu_to_le32(0x80000000);  	for (sect = rdev->rlc.cs_data; sect->section != NULL; ++sect) {  		for (ext = sect->section; ext->extent != NULL; ++ext) {  			if (sect->id == SECT_CONTEXT) { -				buffer[count++] = PACKET3(PACKET3_SET_CONTEXT_REG, ext->reg_count); -				buffer[count++] = ext->reg_index - 0xa000; +				buffer[count++] = +					cpu_to_le32(PACKET3(PACKET3_SET_CONTEXT_REG, ext->reg_count)); +				buffer[count++] = cpu_to_le32(ext->reg_index - 0xa000);  				for (i = 0; i < ext->reg_count; i++) -					buffer[count++] = ext->extent[i]; +					buffer[count++] = cpu_to_le32(ext->extent[i]);  			} else {  				return;  			}  		}  	} -	buffer[count++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); -	buffer[count++] = PA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_SET_CONTEXT_REG, 2)); +	buffer[count++] = cpu_to_le32(PA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START);  	switch (rdev->family) {  	case CHIP_BONAIRE: -		buffer[count++] = 0x16000012; -		buffer[count++] = 0x00000000; +		buffer[count++] = cpu_to_le32(0x16000012); +		buffer[count++] = cpu_to_le32(0x00000000);  		break;  	case CHIP_KAVERI: -		buffer[count++] = 0x00000000; /* XXX */ -		buffer[count++] = 0x00000000; +		buffer[count++] = cpu_to_le32(0x00000000); /* XXX */ +		buffer[count++] = cpu_to_le32(0x00000000);  		break;  	case CHIP_KABINI: -		buffer[count++] = 0x00000000; /* XXX */ -		buffer[count++] = 0x00000000; +	case CHIP_MULLINS: +		buffer[count++] = cpu_to_le32(0x00000000); /* XXX */ +		buffer[count++] = cpu_to_le32(0x00000000); +		break; +	case CHIP_HAWAII: +		buffer[count++] = cpu_to_le32(0x3a00161a); +		buffer[count++] = cpu_to_le32(0x0000002e);  		break;  	default: -		buffer[count++] = 0x00000000; -		buffer[count++] = 0x00000000; +		buffer[count++] = cpu_to_le32(0x00000000); +		buffer[count++] = cpu_to_le32(0x00000000);  		break;  	} -	buffer[count++] = PACKET3(PACKET3_PREAMBLE_CNTL, 0); -	buffer[count++] = PACKET3_PREAMBLE_END_CLEAR_STATE; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0)); +	buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_END_CLEAR_STATE); -	buffer[count++] = PACKET3(PACKET3_CLEAR_STATE, 0); -	buffer[count++] = 0; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_CLEAR_STATE, 0)); +	buffer[count++] = cpu_to_le32(0);  }  static void cik_init_pg(struct radeon_device *rdev) @@ -5941,6 +6779,19 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev)  		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);  		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);  	} +	/* pflip */ +	if (rdev->num_crtc >= 2) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); +	} +	if (rdev->num_crtc >= 4) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); +	} +	if (rdev->num_crtc >= 6) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); +	}  	/* dac hotplug */  	WREG32(DAC_AUTODETECT_INT_CONTROL, 0); @@ -6297,6 +7148,25 @@ int cik_irq_set(struct radeon_device *rdev)  		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);  	} +	if (rdev->num_crtc >= 2) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +	} +	if (rdev->num_crtc >= 4) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +	} +	if (rdev->num_crtc >= 6) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +	} +  	WREG32(DC_HPD1_INT_CONTROL, hpd1);  	WREG32(DC_HPD2_INT_CONTROL, hpd2);  	WREG32(DC_HPD3_INT_CONTROL, hpd3); @@ -6333,6 +7203,29 @@ static inline void cik_irq_ack(struct radeon_device *rdev)  	rdev->irq.stat_regs.cik.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);  	rdev->irq.stat_regs.cik.disp_int_cont6 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE6); +	rdev->irq.stat_regs.cik.d1grph_int = RREG32(GRPH_INT_STATUS + +		EVERGREEN_CRTC0_REGISTER_OFFSET); +	rdev->irq.stat_regs.cik.d2grph_int = RREG32(GRPH_INT_STATUS + +		EVERGREEN_CRTC1_REGISTER_OFFSET); +	if (rdev->num_crtc >= 4) { +		rdev->irq.stat_regs.cik.d3grph_int = RREG32(GRPH_INT_STATUS + +			EVERGREEN_CRTC2_REGISTER_OFFSET); +		rdev->irq.stat_regs.cik.d4grph_int = RREG32(GRPH_INT_STATUS + +			EVERGREEN_CRTC3_REGISTER_OFFSET); +	} +	if (rdev->num_crtc >= 6) { +		rdev->irq.stat_regs.cik.d5grph_int = RREG32(GRPH_INT_STATUS + +			EVERGREEN_CRTC4_REGISTER_OFFSET); +		rdev->irq.stat_regs.cik.d6grph_int = RREG32(GRPH_INT_STATUS + +			EVERGREEN_CRTC5_REGISTER_OFFSET); +	} + +	if (rdev->irq.stat_regs.cik.d1grph_int & GRPH_PFLIP_INT_OCCURRED) +		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_CLEAR); +	if (rdev->irq.stat_regs.cik.d2grph_int & GRPH_PFLIP_INT_OCCURRED) +		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_CLEAR);  	if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT)  		WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);  	if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) @@ -6343,6 +7236,12 @@ static inline void cik_irq_ack(struct radeon_device *rdev)  		WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);  	if (rdev->num_crtc >= 4) { +		if (rdev->irq.stat_regs.cik.d3grph_int & GRPH_PFLIP_INT_OCCURRED) +			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, +			       GRPH_PFLIP_INT_CLEAR); +		if (rdev->irq.stat_regs.cik.d4grph_int & GRPH_PFLIP_INT_OCCURRED) +			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, +			       GRPH_PFLIP_INT_CLEAR);  		if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)  			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);  		if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) @@ -6354,6 +7253,12 @@ static inline void cik_irq_ack(struct radeon_device *rdev)  	}  	if (rdev->num_crtc >= 6) { +		if (rdev->irq.stat_regs.cik.d5grph_int & GRPH_PFLIP_INT_OCCURRED) +			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, +			       GRPH_PFLIP_INT_CLEAR); +		if (rdev->irq.stat_regs.cik.d6grph_int & GRPH_PFLIP_INT_OCCURRED) +			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, +			       GRPH_PFLIP_INT_CLEAR);  		if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)  			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);  		if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) @@ -6472,6 +7377,7 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev)  		tmp = RREG32(IH_RB_CNTL);  		tmp |= IH_WPTR_OVERFLOW_CLEAR;  		WREG32(IH_RB_CNTL, tmp); +		wptr &= ~RB_OVERFLOW;  	}  	return (wptr & rdev->ih.ptr_mask);  } @@ -6559,7 +7465,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[0])) -						radeon_crtc_handle_flip(rdev, 0); +						radeon_crtc_handle_vblank(rdev, 0);  					rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D1 vblank\n");  				} @@ -6585,7 +7491,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[1])) -						radeon_crtc_handle_flip(rdev, 1); +						radeon_crtc_handle_vblank(rdev, 1);  					rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D2 vblank\n");  				} @@ -6611,7 +7517,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[2])) -						radeon_crtc_handle_flip(rdev, 2); +						radeon_crtc_handle_vblank(rdev, 2);  					rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D3 vblank\n");  				} @@ -6637,7 +7543,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[3])) -						radeon_crtc_handle_flip(rdev, 3); +						radeon_crtc_handle_vblank(rdev, 3);  					rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D4 vblank\n");  				} @@ -6663,7 +7569,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[4])) -						radeon_crtc_handle_flip(rdev, 4); +						radeon_crtc_handle_vblank(rdev, 4);  					rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D5 vblank\n");  				} @@ -6689,7 +7595,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[5])) -						radeon_crtc_handle_flip(rdev, 5); +						radeon_crtc_handle_vblank(rdev, 5);  					rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D6 vblank\n");  				} @@ -6705,6 +7611,15 @@ restart_ih:  				break;  			}  			break; +		case 8: /* D1 page flip */ +		case 10: /* D2 page flip */ +		case 12: /* D3 page flip */ +		case 14: /* D4 page flip */ +		case 16: /* D5 page flip */ +		case 18: /* D6 page flip */ +			DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); +			radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); +			break;  		case 42: /* HPD hotplug */  			switch (src_data) {  			case 0: @@ -6763,14 +7678,30 @@ restart_ih:  			addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);  			status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS);  			mc_client = RREG32(VM_CONTEXT1_PROTECTION_FAULT_MCCLIENT); +			/* reset addr and status */ +			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); +			if (addr == 0x0 && status == 0x0) +				break;  			dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);  			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",  				addr);  			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",  				status);  			cik_vm_decode_fault(rdev, status, addr, mc_client); -			/* reset addr and status */ -			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); +			break; +		case 167: /* VCE */ +			DRM_DEBUG("IH: VCE int: 0x%08x\n", src_data); +			switch (src_data) { +			case 0: +				radeon_fence_process(rdev, TN_RING_TYPE_VCE1_INDEX); +				break; +			case 1: +				radeon_fence_process(rdev, TN_RING_TYPE_VCE2_INDEX); +				break; +			default: +				DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); +				break; +			}  			break;  		case 176: /* GFX RB CP_INT */  		case 177: /* GFX IB CP_INT */ @@ -6983,26 +7914,7 @@ static int cik_startup(struct radeon_device *rdev)  	cik_mc_program(rdev); -	if (rdev->flags & RADEON_IS_IGP) { -		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || -		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) { -			r = cik_init_microcode(rdev); -			if (r) { -				DRM_ERROR("Failed to load firmware!\n"); -				return r; -			} -		} -	} else { -		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || -		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw || -		    !rdev->mc_fw) { -			r = cik_init_microcode(rdev); -			if (r) { -				DRM_ERROR("Failed to load firmware!\n"); -				return r; -			} -		} - +	if (!(rdev->flags & RADEON_IS_IGP) && !rdev->pm.dpm_enabled) {  		r = ci_mc_load_microcode(rdev);  		if (r) {  			DRM_ERROR("Failed to load MC firmware!\n"); @@ -7090,6 +8002,22 @@ static int cik_startup(struct radeon_device *rdev)  	if (r)  		rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; +	r = radeon_vce_resume(rdev); +	if (!r) { +		r = vce_v2_0_resume(rdev); +		if (!r) +			r = radeon_fence_driver_start_ring(rdev, +							   TN_RING_TYPE_VCE1_INDEX); +		if (!r) +			r = radeon_fence_driver_start_ring(rdev, +							   TN_RING_TYPE_VCE2_INDEX); +	} +	if (r) { +		dev_err(rdev->dev, "VCE init error (%d).\n", r); +		rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0; +		rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0; +	} +  	/* Enable IRQ */  	if (!rdev->irq.installed) {  		r = radeon_irq_kms_init(rdev); @@ -7107,8 +8035,7 @@ static int cik_startup(struct radeon_device *rdev)  	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, -			     CP_RB0_RPTR, CP_RB0_WPTR, -			     RADEON_CP_PACKET2); +			     PACKET3(PACKET3_NOP, 0x3FFF));  	if (r)  		return r; @@ -7116,7 +8043,6 @@ static int cik_startup(struct radeon_device *rdev)  	/* type-2 packets are deprecated on MEC, use type-3 instead */  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET, -			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,  			     PACKET3(PACKET3_NOP, 0x3FFF));  	if (r)  		return r; @@ -7128,7 +8054,6 @@ static int cik_startup(struct radeon_device *rdev)  	/* type-2 packets are deprecated on MEC, use type-3 instead */  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET, -			     CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,  			     PACKET3(PACKET3_NOP, 0x3FFF));  	if (r)  		return r; @@ -7140,16 +8065,12 @@ static int cik_startup(struct radeon_device *rdev)  	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, -			     SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET, -			     SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,  			     SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));  	if (r)  		return r;  	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET, -			     SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET, -			     SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,  			     SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));  	if (r)  		return r; @@ -7165,7 +8086,6 @@ static int cik_startup(struct radeon_device *rdev)  	ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];  	if (ring->ring_size) {  		r = radeon_ring_init(rdev, ring, ring->ring_size, 0, -				     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,  				     RADEON_CP_PACKET2);  		if (!r)  			r = uvd_v1_0_init(rdev); @@ -7173,6 +8093,23 @@ static int cik_startup(struct radeon_device *rdev)  			DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);  	} +	r = -ENOENT; + +	ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; +	if (ring->ring_size) +		r = radeon_ring_init(rdev, ring, ring->ring_size, 0, +				     VCE_CMD_NO_OP); + +	ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; +	if (ring->ring_size) +		r = radeon_ring_init(rdev, ring, ring->ring_size, 0, +				     VCE_CMD_NO_OP); + +	if (!r) +		r = vce_v1_0_init(rdev); +	else if (r != -ENOENT) +		DRM_ERROR("radeon: failed initializing VCE (%d).\n", r); +  	r = radeon_ib_pool_init(rdev);  	if (r) {  		dev_err(rdev->dev, "IB initialization failed (%d).\n", r); @@ -7211,6 +8148,9 @@ int cik_resume(struct radeon_device *rdev)  	/* init golden registers */  	cik_init_golden_registers(rdev); +	if (rdev->pm.pm_method == PM_METHOD_DPM) +		radeon_pm_resume(rdev); +  	rdev->accel_working = true;  	r = cik_startup(rdev);  	if (r) { @@ -7234,12 +8174,14 @@ int cik_resume(struct radeon_device *rdev)   */  int cik_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	dce6_audio_fini(rdev);  	radeon_vm_manager_fini(rdev);  	cik_cp_enable(rdev, false);  	cik_sdma_enable(rdev, false);  	uvd_v1_0_fini(rdev);  	radeon_uvd_suspend(rdev); +	radeon_vce_suspend(rdev);  	cik_fini_pg(rdev);  	cik_fini_cg(rdev);  	cik_irq_suspend(rdev); @@ -7315,6 +8257,30 @@ int cik_init(struct radeon_device *rdev)  	if (r)  		return r; +	if (rdev->flags & RADEON_IS_IGP) { +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || +		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) { +			r = cik_init_microcode(rdev); +			if (r) { +				DRM_ERROR("Failed to load firmware!\n"); +				return r; +			} +		} +	} else { +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || +		    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw || +		    !rdev->mc_fw) { +			r = cik_init_microcode(rdev); +			if (r) { +				DRM_ERROR("Failed to load firmware!\n"); +				return r; +			} +		} +	} + +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];  	ring->ring_obj = NULL;  	r600_ring_init(rdev, ring, 1024 * 1024); @@ -7322,14 +8288,14 @@ int cik_init(struct radeon_device *rdev)  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];  	ring->ring_obj = NULL;  	r600_ring_init(rdev, ring, 1024 * 1024); -	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num); +	r = radeon_doorbell_get(rdev, &ring->doorbell_index);  	if (r)  		return r;  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];  	ring->ring_obj = NULL;  	r600_ring_init(rdev, ring, 1024 * 1024); -	r = radeon_doorbell_get(rdev, &ring->doorbell_page_num); +	r = radeon_doorbell_get(rdev, &ring->doorbell_index);  	if (r)  		return r; @@ -7348,6 +8314,17 @@ int cik_init(struct radeon_device *rdev)  		r600_ring_init(rdev, ring, 4096);  	} +	r = radeon_vce_init(rdev); +	if (!r) { +		ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; +		ring->ring_obj = NULL; +		r600_ring_init(rdev, ring, 4096); + +		ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; +		ring->ring_obj = NULL; +		r600_ring_init(rdev, ring, 4096); +	} +  	rdev->ih.ring_obj = NULL;  	r600_ih_ring_init(rdev, 64 * 1024); @@ -7395,6 +8372,7 @@ int cik_init(struct radeon_device *rdev)   */  void cik_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	cik_cp_fini(rdev);  	cik_sdma_fini(rdev);  	cik_fini_pg(rdev); @@ -7408,6 +8386,7 @@ void cik_fini(struct radeon_device *rdev)  	radeon_irq_kms_fini(rdev);  	uvd_v1_0_fini(rdev);  	radeon_uvd_fini(rdev); +	radeon_vce_fini(rdev);  	cik_pcie_gart_fini(rdev);  	r600_vram_scratch_fini(rdev);  	radeon_gem_fini(rdev); @@ -7418,6 +8397,70 @@ void cik_fini(struct radeon_device *rdev)  	rdev->bios = NULL;  } +void dce8_program_fmt(struct drm_encoder *encoder) +{ +	struct drm_device *dev = encoder->dev; +	struct radeon_device *rdev = dev->dev_private; +	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); +	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); +	int bpc = 0; +	u32 tmp = 0; +	enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE; + +	if (connector) { +		struct radeon_connector *radeon_connector = to_radeon_connector(connector); +		bpc = radeon_get_monitor_bpc(connector); +		dither = radeon_connector->dither; +	} + +	/* LVDS/eDP FMT is set up by atom */ +	if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT) +		return; + +	/* not needed for analog */ +	if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) || +	    (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2)) +		return; + +	if (bpc == 0) +		return; + +	switch (bpc) { +	case 6: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE | +				FMT_SPATIAL_DITHER_EN | FMT_SPATIAL_DITHER_DEPTH(0)); +		else +			tmp |= (FMT_TRUNCATE_EN | FMT_TRUNCATE_DEPTH(0)); +		break; +	case 8: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE | +				FMT_RGB_RANDOM_ENABLE | +				FMT_SPATIAL_DITHER_EN | FMT_SPATIAL_DITHER_DEPTH(1)); +		else +			tmp |= (FMT_TRUNCATE_EN | FMT_TRUNCATE_DEPTH(1)); +		break; +	case 10: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE | +				FMT_RGB_RANDOM_ENABLE | +				FMT_SPATIAL_DITHER_EN | FMT_SPATIAL_DITHER_DEPTH(2)); +		else +			tmp |= (FMT_TRUNCATE_EN | FMT_TRUNCATE_DEPTH(2)); +		break; +	default: +		/* not needed */ +		break; +	} + +	WREG32(FMT_BIT_DEPTH_CONTROL + radeon_crtc->crtc_offset, tmp); +} +  /* display watermark setup */  /**   * dce8_line_buffer_adjust - Set up the line buffer @@ -8082,6 +9125,41 @@ int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)  	return r;  } +int cik_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk) +{ +	int r, i; +	struct atom_clock_dividers dividers; +	u32 tmp; + +	r = radeon_atom_get_clock_dividers(rdev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, +					   ecclk, false, ÷rs); +	if (r) +		return r; + +	for (i = 0; i < 100; i++) { +		if (RREG32_SMC(CG_ECLK_STATUS) & ECLK_STATUS) +			break; +		mdelay(10); +	} +	if (i == 100) +		return -ETIMEDOUT; + +	tmp = RREG32_SMC(CG_ECLK_CNTL); +	tmp &= ~(ECLK_DIR_CNTL_EN|ECLK_DIVIDER_MASK); +	tmp |= dividers.post_divider; +	WREG32_SMC(CG_ECLK_CNTL, tmp); + +	for (i = 0; i < 100; i++) { +		if (RREG32_SMC(CG_ECLK_STATUS) & ECLK_STATUS) +			break; +		mdelay(10); +	} +	if (i == 100) +		return -ETIMEDOUT; + +	return 0; +} +  static void cik_pcie_gen3_enable(struct radeon_device *rdev)  {  	struct pci_dev *root = rdev->pdev->bus->self; diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index b6286068e11..8e9d0f1d858 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -25,6 +25,7 @@  #include <drm/drmP.h>  #include "radeon.h"  #include "radeon_asic.h" +#include "radeon_trace.h"  #include "cikd.h"  /* sdma */ @@ -51,6 +52,75 @@ u32 cik_gpu_check_soft_reset(struct radeon_device *rdev);   */  /** + * cik_sdma_get_rptr - get the current read pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Get the current rptr from the hardware (CIK+). + */ +uint32_t cik_sdma_get_rptr(struct radeon_device *rdev, +			   struct radeon_ring *ring) +{ +	u32 rptr, reg; + +	if (rdev->wb.enabled) { +		rptr = rdev->wb.wb[ring->rptr_offs/4]; +	} else { +		if (ring->idx == R600_RING_TYPE_DMA_INDEX) +			reg = SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET; +		else +			reg = SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET; + +		rptr = RREG32(reg); +	} + +	return (rptr & 0x3fffc) >> 2; +} + +/** + * cik_sdma_get_wptr - get the current write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Get the current wptr from the hardware (CIK+). + */ +uint32_t cik_sdma_get_wptr(struct radeon_device *rdev, +			   struct radeon_ring *ring) +{ +	u32 reg; + +	if (ring->idx == R600_RING_TYPE_DMA_INDEX) +		reg = SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET; +	else +		reg = SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET; + +	return (RREG32(reg) & 0x3fffc) >> 2; +} + +/** + * cik_sdma_set_wptr - commit the write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Write the wptr back to the hardware (CIK+). + */ +void cik_sdma_set_wptr(struct radeon_device *rdev, +		       struct radeon_ring *ring) +{ +	u32 reg; + +	if (ring->idx == R600_RING_TYPE_DMA_INDEX) +		reg = SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET; +	else +		reg = SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET; + +	WREG32(reg, (ring->wptr << 2) & 0x3fffc); +} + +/**   * cik_sdma_ring_ib_execute - Schedule an IB on the DMA engine   *   * @rdev: radeon_device pointer @@ -71,7 +141,7 @@ void cik_sdma_ring_ib_execute(struct radeon_device *rdev,  		next_rptr += 4;  		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));  		radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); -		radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff); +		radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr));  		radeon_ring_write(ring, 1); /* number of DWs to follow */  		radeon_ring_write(ring, next_rptr);  	} @@ -81,12 +151,41 @@ void cik_sdma_ring_ib_execute(struct radeon_device *rdev,  		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));  	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_INDIRECT_BUFFER, 0, extra_bits));  	radeon_ring_write(ring, ib->gpu_addr & 0xffffffe0); /* base must be 32 byte aligned */ -	radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xffffffff); +	radeon_ring_write(ring, upper_32_bits(ib->gpu_addr));  	radeon_ring_write(ring, ib->length_dw);  }  /** + * cik_sdma_hdp_flush_ring_emit - emit an hdp flush on the DMA ring + * + * @rdev: radeon_device pointer + * @ridx: radeon ring index + * + * Emit an hdp flush packet on the requested DMA ring. + */ +static void cik_sdma_hdp_flush_ring_emit(struct radeon_device *rdev, +					 int ridx) +{ +	struct radeon_ring *ring = &rdev->ring[ridx]; +	u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) | +			  SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */ +	u32 ref_and_mask; + +	if (ridx == R600_RING_TYPE_DMA_INDEX) +		ref_and_mask = SDMA0; +	else +		ref_and_mask = SDMA1; + +	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits)); +	radeon_ring_write(ring, GPU_HDP_FLUSH_DONE); +	radeon_ring_write(ring, GPU_HDP_FLUSH_REQ); +	radeon_ring_write(ring, ref_and_mask); /* reference */ +	radeon_ring_write(ring, ref_and_mask); /* mask */ +	radeon_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */ +} + +/**   * cik_sdma_fence_ring_emit - emit a fence on the DMA ring   *   * @rdev: radeon_device pointer @@ -101,29 +200,16 @@ void cik_sdma_fence_ring_emit(struct radeon_device *rdev,  {  	struct radeon_ring *ring = &rdev->ring[fence->ring];  	u64 addr = rdev->fence_drv[fence->ring].gpu_addr; -	u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) | -			  SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */ -	u32 ref_and_mask; - -	if (fence->ring == R600_RING_TYPE_DMA_INDEX) -		ref_and_mask = SDMA0; -	else -		ref_and_mask = SDMA1;  	/* write the fence */  	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_FENCE, 0, 0)); -	radeon_ring_write(ring, addr & 0xffffffff); -	radeon_ring_write(ring, upper_32_bits(addr) & 0xffffffff); +	radeon_ring_write(ring, lower_32_bits(addr)); +	radeon_ring_write(ring, upper_32_bits(addr));  	radeon_ring_write(ring, fence->seq);  	/* generate an interrupt */  	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_TRAP, 0, 0));  	/* flush HDP */ -	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits)); -	radeon_ring_write(ring, GPU_HDP_FLUSH_DONE); -	radeon_ring_write(ring, GPU_HDP_FLUSH_REQ); -	radeon_ring_write(ring, ref_and_mask); /* REFERENCE */ -	radeon_ring_write(ring, ref_and_mask); /* MASK */ -	radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */ +	cik_sdma_hdp_flush_ring_emit(rdev, fence->ring);  }  /** @@ -137,7 +223,7 @@ void cik_sdma_fence_ring_emit(struct radeon_device *rdev,   * Add a DMA semaphore packet to the ring wait on or signal   * other rings (CIK).   */ -void cik_sdma_semaphore_ring_emit(struct radeon_device *rdev, +bool cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,  				  struct radeon_ring *ring,  				  struct radeon_semaphore *semaphore,  				  bool emit_wait) @@ -147,7 +233,9 @@ void cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SEMAPHORE, 0, extra_bits));  	radeon_ring_write(ring, addr & 0xfffffff8); -	radeon_ring_write(ring, upper_32_bits(addr) & 0xffffffff); +	radeon_ring_write(ring, upper_32_bits(addr)); + +	return true;  }  /** @@ -162,7 +250,9 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev)  	u32 rb_cntl, reg_offset;  	int i; -	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); +	if ((rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) || +	    (rdev->asic->copy.copy_ring_index == CAYMAN_RING_TYPE_DMA1_INDEX)) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);  	for (i = 0; i < 2; i++) {  		if (i == 0) @@ -174,6 +264,8 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev)  		WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);  		WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);  	} +	rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; +	rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false;  }  /** @@ -201,6 +293,11 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable)  	u32 me_cntl, reg_offset;  	int i; +	if (enable == false) { +		cik_sdma_gfx_stop(rdev); +		cik_sdma_rlc_stop(rdev); +	} +  	for (i = 0; i < 2; i++) {  		if (i == 0)  			reg_offset = SDMA0_REGISTER_OFFSET; @@ -272,8 +369,6 @@ static int cik_sdma_gfx_resume(struct radeon_device *rdev)  		ring->wptr = 0;  		WREG32(SDMA0_GFX_RB_WPTR + reg_offset, ring->wptr << 2); -		ring->rptr = RREG32(SDMA0_GFX_RB_RPTR + reg_offset) >> 2; -  		/* enable DMA RB */  		WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl | SDMA_RB_ENABLE); @@ -293,7 +388,9 @@ static int cik_sdma_gfx_resume(struct radeon_device *rdev)  		}  	} -	radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); +	if ((rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) || +	    (rdev->asic->copy.copy_ring_index == CAYMAN_RING_TYPE_DMA1_INDEX)) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);  	return 0;  } @@ -328,10 +425,6 @@ static int cik_sdma_load_microcode(struct radeon_device *rdev)  	if (!rdev->sdma_fw)  		return -EINVAL; -	/* stop the gfx rings and rlc compute queues */ -	cik_sdma_gfx_stop(rdev); -	cik_sdma_rlc_stop(rdev); -  	/* halt the MEs */  	cik_sdma_enable(rdev, false); @@ -400,9 +493,6 @@ int cik_sdma_resume(struct radeon_device *rdev)   */  void cik_sdma_fini(struct radeon_device *rdev)  { -	/* stop the gfx rings and rlc compute queues */ -	cik_sdma_gfx_stop(rdev); -	cik_sdma_rlc_stop(rdev);  	/* halt the MEs */  	cik_sdma_enable(rdev, false);  	radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]); @@ -450,13 +540,8 @@ int cik_copy_dma(struct radeon_device *rdev,  		return r;  	} -	if (radeon_fence_need_sync(*fence, ring->idx)) { -		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, -					    ring->idx); -		radeon_fence_note_sync(*fence, ring->idx); -	} else { -		radeon_semaphore_free(rdev, &sem, NULL); -	} +	radeon_semaphore_sync_to(sem, *fence); +	radeon_semaphore_sync_rings(rdev, sem, ring->idx);  	for (i = 0; i < num_loops; i++) {  		cur_size_in_bytes = size_in_bytes; @@ -466,10 +551,10 @@ int cik_copy_dma(struct radeon_device *rdev,  		radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0));  		radeon_ring_write(ring, cur_size_in_bytes);  		radeon_ring_write(ring, 0); /* src/dst endian swap */ -		radeon_ring_write(ring, src_offset & 0xffffffff); -		radeon_ring_write(ring, upper_32_bits(src_offset) & 0xffffffff); -		radeon_ring_write(ring, dst_offset & 0xfffffffc); -		radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xffffffff); +		radeon_ring_write(ring, lower_32_bits(src_offset)); +		radeon_ring_write(ring, upper_32_bits(src_offset)); +		radeon_ring_write(ring, lower_32_bits(dst_offset)); +		radeon_ring_write(ring, upper_32_bits(dst_offset));  		src_offset += cur_size_in_bytes;  		dst_offset += cur_size_in_bytes;  	} @@ -477,6 +562,7 @@ int cik_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} @@ -512,14 +598,14 @@ int cik_sdma_ring_test(struct radeon_device *rdev,  	tmp = 0xCAFEDEAD;  	writel(tmp, ptr); -	r = radeon_ring_lock(rdev, ring, 4); +	r = radeon_ring_lock(rdev, ring, 5);  	if (r) {  		DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r);  		return r;  	}  	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));  	radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc); -	radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xffffffff); +	radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr));  	radeon_ring_write(ring, 1); /* number of DWs to follow */  	radeon_ring_write(ring, 0xDEADBEEF);  	radeon_ring_unlock_commit(rdev, ring); @@ -574,7 +660,7 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)  	ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);  	ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc; -	ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xffffffff; +	ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr);  	ib.ptr[3] = 1;  	ib.ptr[4] = 0xDEADBEEF;  	ib.length_dw = 5; @@ -626,11 +712,9 @@ bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  		mask = RADEON_RESET_DMA1;  	if (!(reset_mask & mask)) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force ring activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -653,11 +737,31 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev,  			  uint64_t addr, unsigned count,  			  uint32_t incr, uint32_t flags)  { -	uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);  	uint64_t value;  	unsigned ndw; -	if (flags & RADEON_VM_PAGE_SYSTEM) { +	trace_radeon_vm_set_page(pe, addr, count, incr, flags); + +	if (flags == R600_PTE_GART) { +		uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8; +		while (count) { +			unsigned bytes = count * 8; +			if (bytes > 0x1FFFF8) +				bytes = 0x1FFFF8; + +			ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_WRITE_SUB_OPCODE_LINEAR, 0); +			ib->ptr[ib->length_dw++] = bytes; +			ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ +			ib->ptr[ib->length_dw++] = lower_32_bits(src); +			ib->ptr[ib->length_dw++] = upper_32_bits(src); +			ib->ptr[ib->length_dw++] = lower_32_bits(pe); +			ib->ptr[ib->length_dw++] = upper_32_bits(pe); + +			pe += bytes; +			src += bytes; +			count -= bytes / 8; +		} +	} else if (flags & R600_PTE_SYSTEM) {  		while (count) {  			ndw = count * 2;  			if (ndw > 0xFFFFE) @@ -669,16 +773,10 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev,  			ib->ptr[ib->length_dw++] = upper_32_bits(pe);  			ib->ptr[ib->length_dw++] = ndw;  			for (; ndw > 0; ndw -= 2, --count, pe += 8) { -				if (flags & RADEON_VM_PAGE_SYSTEM) { -					value = radeon_vm_map_gart(rdev, addr); -					value &= 0xFFFFFFFFFFFFF000ULL; -				} else if (flags & RADEON_VM_PAGE_VALID) { -					value = addr; -				} else { -					value = 0; -				} +				value = radeon_vm_map_gart(rdev, addr); +				value &= 0xFFFFFFFFFFFFF000ULL;  				addr += incr; -				value |= r600_flags; +				value |= flags;  				ib->ptr[ib->length_dw++] = value;  				ib->ptr[ib->length_dw++] = upper_32_bits(value);  			} @@ -689,7 +787,7 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev,  			if (ndw > 0x7FFFF)  				ndw = 0x7FFFF; -			if (flags & RADEON_VM_PAGE_VALID) +			if (flags & R600_PTE_VALID)  				value = addr;  			else  				value = 0; @@ -697,7 +795,7 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev,  			ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0);  			ib->ptr[ib->length_dw++] = pe; /* dst addr */  			ib->ptr[ib->length_dw++] = upper_32_bits(pe); -			ib->ptr[ib->length_dw++] = r600_flags; /* mask */ +			ib->ptr[ib->length_dw++] = flags; /* mask */  			ib->ptr[ib->length_dw++] = 0;  			ib->ptr[ib->length_dw++] = value; /* value */  			ib->ptr[ib->length_dw++] = upper_32_bits(value); @@ -724,18 +822,10 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev,  void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)  {  	struct radeon_ring *ring = &rdev->ring[ridx]; -	u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) | -			  SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */ -	u32 ref_and_mask;  	if (vm == NULL)  		return; -	if (ridx == R600_RING_TYPE_DMA_INDEX) -		ref_and_mask = SDMA0; -	else -		ref_and_mask = SDMA1; -  	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); @@ -770,12 +860,7 @@ void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm  	radeon_ring_write(ring, VMID(0));  	/* flush HDP */ -	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits)); -	radeon_ring_write(ring, GPU_HDP_FLUSH_DONE); -	radeon_ring_write(ring, GPU_HDP_FLUSH_REQ); -	radeon_ring_write(ring, ref_and_mask); /* REFERENCE */ -	radeon_ring_write(ring, ref_and_mask); /* MASK */ -	radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */ +	cik_sdma_hdp_flush_ring_emit(rdev, ridx);  	/* flush TLB */  	radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 203d2a09a1f..0c6e1b55d96 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -25,8 +25,10 @@  #define CIK_H  #define BONAIRE_GB_ADDR_CONFIG_GOLDEN        0x12010001 +#define HAWAII_GB_ADDR_CONFIG_GOLDEN         0x12011003 -#define CIK_RB_BITMAP_WIDTH_PER_SH  2 +#define CIK_RB_BITMAP_WIDTH_PER_SH     2 +#define HAWAII_RB_BITMAP_WIDTH_PER_SH  4  /* DIDT IND registers */  #define DIDT_SQ_CTRL0                                     0x0 @@ -201,6 +203,12 @@  #define		CTF_TEMP_MASK				0x0003fe00  #define		CTF_TEMP_SHIFT				9 +#define CG_ECLK_CNTL                                    0xC05000AC +#       define ECLK_DIVIDER_MASK                        0x7f +#       define ECLK_DIR_CNTL_EN                         (1 << 8) +#define CG_ECLK_STATUS                                  0xC05000B0 +#       define ECLK_STATUS                              (1 << 0) +  #define	CG_SPLL_FUNC_CNTL				0xC0500140  #define		SPLL_RESET				(1 << 0)  #define		SPLL_PWRON				(1 << 1) @@ -474,6 +482,7 @@  #define		READ_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 16)  #define		WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 18)  #define		WRITE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 19) +#define		PAGE_TABLE_BLOCK_SIZE(x)			(((x) & 0xF) << 24)  #define VM_CONTEXT1_CNTL				0x1414  #define VM_CONTEXT0_CNTL2				0x1430  #define VM_CONTEXT1_CNTL2				0x1434 @@ -499,6 +508,7 @@  		 * bit 4: write  		 */  #define		MEMORY_CLIENT_ID_MASK			(0xff << 12) +#define		HAWAII_MEMORY_CLIENT_ID_MASK		(0x1ff << 12)  #define		MEMORY_CLIENT_ID_SHIFT			12  #define		MEMORY_CLIENT_RW_MASK			(1 << 24)  #define		MEMORY_CLIENT_RW_SHIFT			24 @@ -721,6 +731,17 @@  #define ATC_MISC_CG           				0x3350 +#define GMCON_RENG_EXECUTE				0x3508 +#define 	RENG_EXECUTE_ON_PWR_UP			(1 << 0) +#define GMCON_MISC					0x350c +#define 	RENG_EXECUTE_ON_REG_UPDATE		(1 << 11) +#define 	STCTRL_STUTTER_EN			(1 << 16) + +#define GMCON_PGFSM_CONFIG				0x3538 +#define GMCON_PGFSM_WRITE				0x353c +#define GMCON_PGFSM_READ				0x3540 +#define GMCON_MISC3					0x3544 +  #define MC_SEQ_CNTL_3                                     0x3600  #       define CAC_EN                                     (1 << 31)  #define MC_SEQ_G5PDX_CTRL                                 0x3604 @@ -868,6 +889,15 @@  #       define DC_HPD6_RX_INTERRUPT                     (1 << 18)  #define DISP_INTERRUPT_STATUS_CONTINUE6                 0x6780 +/* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */ +#define GRPH_INT_STATUS                                 0x6858 +#       define GRPH_PFLIP_INT_OCCURRED                  (1 << 0) +#       define GRPH_PFLIP_INT_CLEAR                     (1 << 8) +/* 0x685c, 0x745c, 0x1005c, 0x10c5c, 0x1185c, 0x1245c */ +#define GRPH_INT_CONTROL                                0x685c +#       define GRPH_PFLIP_INT_MASK                      (1 << 0) +#       define GRPH_PFLIP_INT_TYPE                      (1 << 8) +  #define	DAC_AUTODETECT_INT_CONTROL			0x67c8  #define DC_HPD1_INT_STATUS                              0x601c @@ -906,6 +936,39 @@  #define DPG_PIPE_STUTTER_CONTROL                          0x6cd4  #       define STUTTER_ENABLE                             (1 << 0) +/* DCE8 FMT blocks */ +#define FMT_DYNAMIC_EXP_CNTL                 0x6fb4 +#       define FMT_DYNAMIC_EXP_EN            (1 << 0) +#       define FMT_DYNAMIC_EXP_MODE          (1 << 4) +        /* 0 = 10bit -> 12bit, 1 = 8bit -> 12bit */ +#define FMT_CONTROL                          0x6fb8 +#       define FMT_PIXEL_ENCODING            (1 << 16) +        /* 0 = RGB 4:4:4 or YCbCr 4:4:4, 1 = YCbCr 4:2:2 */ +#define FMT_BIT_DEPTH_CONTROL                0x6fc8 +#       define FMT_TRUNCATE_EN               (1 << 0) +#       define FMT_TRUNCATE_MODE             (1 << 1) +#       define FMT_TRUNCATE_DEPTH(x)         ((x) << 4) /* 0 - 18bpp, 1 - 24bpp, 2 - 30bpp */ +#       define FMT_SPATIAL_DITHER_EN         (1 << 8) +#       define FMT_SPATIAL_DITHER_MODE(x)    ((x) << 9) +#       define FMT_SPATIAL_DITHER_DEPTH(x)   ((x) << 11) /* 0 - 18bpp, 1 - 24bpp, 2 - 30bpp */ +#       define FMT_FRAME_RANDOM_ENABLE       (1 << 13) +#       define FMT_RGB_RANDOM_ENABLE         (1 << 14) +#       define FMT_HIGHPASS_RANDOM_ENABLE    (1 << 15) +#       define FMT_TEMPORAL_DITHER_EN        (1 << 16) +#       define FMT_TEMPORAL_DITHER_DEPTH(x)  ((x) << 17) /* 0 - 18bpp, 1 - 24bpp, 2 - 30bpp */ +#       define FMT_TEMPORAL_DITHER_OFFSET(x) ((x) << 21) +#       define FMT_TEMPORAL_LEVEL            (1 << 24) +#       define FMT_TEMPORAL_DITHER_RESET     (1 << 25) +#       define FMT_25FRC_SEL(x)              ((x) << 26) +#       define FMT_50FRC_SEL(x)              ((x) << 28) +#       define FMT_75FRC_SEL(x)              ((x) << 30) +#define FMT_CLAMP_CONTROL                    0x6fe4 +#       define FMT_CLAMP_DATA_EN             (1 << 0) +#       define FMT_CLAMP_COLOR_FORMAT(x)     ((x) << 16) +#       define FMT_CLAMP_6BPC                0 +#       define FMT_CLAMP_8BPC                1 +#       define FMT_CLAMP_10BPC               2 +  #define	GRBM_CNTL					0x8000  #define		GRBM_READ_TIMEOUT(x)				((x) << 0) @@ -1129,6 +1192,8 @@  #              define	ADDR_SURF_P8_32x32_16x16		12  #              define	ADDR_SURF_P8_32x32_16x32		13  #              define	ADDR_SURF_P8_32x64_32x32		14 +#              define	ADDR_SURF_P16_32x32_8x16		16 +#              define	ADDR_SURF_P16_32x32_16x16		17  #       define TILE_SPLIT(x)					((x) << 11)  #              define	ADDR_SURF_TILE_SPLIT_64B		0  #              define	ADDR_SURF_TILE_SPLIT_128B		1 @@ -1422,6 +1487,7 @@  #       define RASTER_CONFIG_RB_MAP_1                   1  #       define RASTER_CONFIG_RB_MAP_2                   2  #       define RASTER_CONFIG_RB_MAP_3                   3 +#define		PKR_MAP(x)				((x) << 8)  #define VGT_EVENT_INITIATOR                             0x28a90  #       define SAMPLE_STREAMOUTSTATS1                   (1 << 0) @@ -1686,12 +1752,12 @@  #define		EOP_TC_WB_ACTION_EN                     (1 << 15) /* L2 */  #define		EOP_TCL1_ACTION_EN                      (1 << 16)  #define		EOP_TC_ACTION_EN                        (1 << 17) /* L2 */ +#define		EOP_TCL2_VOLATILE                       (1 << 24)  #define		EOP_CACHE_POLICY(x)                     ((x) << 25)                  /* 0 - LRU  		 * 1 - Stream  		 * 2 - Bypass  		 */ -#define		EOP_TCL2_VOLATILE                       (1 << 27)  #define		DATA_SEL(x)                             ((x) << 29)                  /* 0 - discard  		 * 1 - send low 32bit data @@ -1714,6 +1780,68 @@  #              define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE     (2 << 28)  #              define PACKET3_PREAMBLE_END_CLEAR_STATE       (3 << 28)  #define	PACKET3_DMA_DATA				0x50 +/* 1. header + * 2. CONTROL + * 3. SRC_ADDR_LO or DATA [31:0] + * 4. SRC_ADDR_HI [31:0] + * 5. DST_ADDR_LO [31:0] + * 6. DST_ADDR_HI [7:0] + * 7. COMMAND [30:21] | BYTE_COUNT [20:0] + */ +/* CONTROL */ +#              define PACKET3_DMA_DATA_ENGINE(x)     ((x) << 0) +                /* 0 - ME +		 * 1 - PFP +		 */ +#              define PACKET3_DMA_DATA_SRC_CACHE_POLICY(x) ((x) << 13) +                /* 0 - LRU +		 * 1 - Stream +		 * 2 - Bypass +		 */ +#              define PACKET3_DMA_DATA_SRC_VOLATILE (1 << 15) +#              define PACKET3_DMA_DATA_DST_SEL(x)  ((x) << 20) +                /* 0 - DST_ADDR using DAS +		 * 1 - GDS +		 * 3 - DST_ADDR using L2 +		 */ +#              define PACKET3_DMA_DATA_DST_CACHE_POLICY(x) ((x) << 25) +                /* 0 - LRU +		 * 1 - Stream +		 * 2 - Bypass +		 */ +#              define PACKET3_DMA_DATA_DST_VOLATILE (1 << 27) +#              define PACKET3_DMA_DATA_SRC_SEL(x)  ((x) << 29) +                /* 0 - SRC_ADDR using SAS +		 * 1 - GDS +		 * 2 - DATA +		 * 3 - SRC_ADDR using L2 +		 */ +#              define PACKET3_DMA_DATA_CP_SYNC     (1 << 31) +/* COMMAND */ +#              define PACKET3_DMA_DATA_DIS_WC      (1 << 21) +#              define PACKET3_DMA_DATA_CMD_SRC_SWAP(x) ((x) << 22) +                /* 0 - none +		 * 1 - 8 in 16 +		 * 2 - 8 in 32 +		 * 3 - 8 in 64 +		 */ +#              define PACKET3_DMA_DATA_CMD_DST_SWAP(x) ((x) << 24) +                /* 0 - none +		 * 1 - 8 in 16 +		 * 2 - 8 in 32 +		 * 3 - 8 in 64 +		 */ +#              define PACKET3_DMA_DATA_CMD_SAS     (1 << 26) +                /* 0 - memory +		 * 1 - register +		 */ +#              define PACKET3_DMA_DATA_CMD_DAS     (1 << 27) +                /* 0 - memory +		 * 1 - register +		 */ +#              define PACKET3_DMA_DATA_CMD_SAIC    (1 << 28) +#              define PACKET3_DMA_DATA_CMD_DAIC    (1 << 29) +#              define PACKET3_DMA_DATA_CMD_RAW_WAIT  (1 << 30)  #define	PACKET3_AQUIRE_MEM				0x58  #define	PACKET3_REWIND					0x59  #define	PACKET3_LOAD_UCONFIG_REG			0x5E @@ -1898,4 +2026,47 @@  /* UVD CTX indirect */  #define	UVD_CGC_MEM_CTRL				0xC0 +/* VCE */ + +#define VCE_VCPU_CACHE_OFFSET0		0x20024 +#define VCE_VCPU_CACHE_SIZE0		0x20028 +#define VCE_VCPU_CACHE_OFFSET1		0x2002c +#define VCE_VCPU_CACHE_SIZE1		0x20030 +#define VCE_VCPU_CACHE_OFFSET2		0x20034 +#define VCE_VCPU_CACHE_SIZE2		0x20038 +#define VCE_RB_RPTR2			0x20178 +#define VCE_RB_WPTR2			0x2017c +#define VCE_RB_RPTR			0x2018c +#define VCE_RB_WPTR			0x20190 +#define VCE_CLOCK_GATING_A		0x202f8 +#	define CGC_CLK_GATE_DLY_TIMER_MASK	(0xf << 0) +#	define CGC_CLK_GATE_DLY_TIMER(x)	((x) << 0) +#	define CGC_CLK_GATER_OFF_DLY_TIMER_MASK	(0xff << 4) +#	define CGC_CLK_GATER_OFF_DLY_TIMER(x)	((x) << 4) +#	define CGC_UENC_WAIT_AWAKE	(1 << 18) +#define VCE_CLOCK_GATING_B		0x202fc +#define VCE_CGTT_CLK_OVERRIDE		0x207a0 +#define VCE_UENC_CLOCK_GATING		0x207bc +#	define CLOCK_ON_DELAY_MASK	(0xf << 0) +#	define CLOCK_ON_DELAY(x)	((x) << 0) +#	define CLOCK_OFF_DELAY_MASK	(0xff << 4) +#	define CLOCK_OFF_DELAY(x)	((x) << 4) +#define VCE_UENC_REG_CLOCK_GATING	0x207c0 +#define VCE_SYS_INT_EN			0x21300 +#	define VCE_SYS_INT_TRAP_INTERRUPT_EN	(1 << 3) +#define VCE_LMI_CTRL2			0x21474 +#define VCE_LMI_CTRL			0x21498 +#define VCE_LMI_VM_CTRL			0x214a0 +#define VCE_LMI_SWAP_CNTL		0x214b4 +#define VCE_LMI_SWAP_CNTL1		0x214b8 +#define VCE_LMI_CACHE_CTRL		0x214f4 + +#define VCE_CMD_NO_OP		0x00000000 +#define VCE_CMD_END		0x00000001 +#define VCE_CMD_IB		0x00000002 +#define VCE_CMD_FENCE		0x00000003 +#define VCE_CMD_TRAP		0x00000004 +#define VCE_CMD_IB_AUTO		0x00000005 +#define VCE_CMD_SEMAPHORE	0x00000006 +  #endif diff --git a/drivers/gpu/drm/radeon/clearstate_cayman.h b/drivers/gpu/drm/radeon/clearstate_cayman.h index aa908c55a51..e48a14037b7 100644 --- a/drivers/gpu/drm/radeon/clearstate_cayman.h +++ b/drivers/gpu/drm/radeon/clearstate_cayman.h @@ -1050,7 +1050,7 @@ static const struct cs_extent_def SECT_CONTEXT_defs[] =      {SECT_CONTEXT_def_5, 0x0000a29e, 5 },      {SECT_CONTEXT_def_6, 0x0000a2a5, 56 },      {SECT_CONTEXT_def_7, 0x0000a2de, 290 }, -    { 0, 0, 0 } +    { NULL, 0, 0 }  };  static const u32 SECT_CLEAR_def_1[] =  { @@ -1061,7 +1061,7 @@ static const u32 SECT_CLEAR_def_1[] =  static const struct cs_extent_def SECT_CLEAR_defs[] =  {      {SECT_CLEAR_def_1, 0x0000ffc0, 3 }, -    { 0, 0, 0 } +    { NULL, 0, 0 }  };  static const u32 SECT_CTRLCONST_def_1[] =  { @@ -1071,11 +1071,11 @@ static const u32 SECT_CTRLCONST_def_1[] =  static const struct cs_extent_def SECT_CTRLCONST_defs[] =  {      {SECT_CTRLCONST_def_1, 0x0000f3fc, 2 }, -    { 0, 0, 0 } +    { NULL, 0, 0 }  };  static const struct cs_section_def cayman_cs_data[] = {      { SECT_CONTEXT_defs, SECT_CONTEXT },      { SECT_CLEAR_defs, SECT_CLEAR },      { SECT_CTRLCONST_defs, SECT_CTRLCONST }, -    { 0, SECT_NONE } +    { NULL, SECT_NONE }  }; diff --git a/drivers/gpu/drm/radeon/clearstate_ci.h b/drivers/gpu/drm/radeon/clearstate_ci.h index c3982f9475f..f55d06664e3 100644 --- a/drivers/gpu/drm/radeon/clearstate_ci.h +++ b/drivers/gpu/drm/radeon/clearstate_ci.h @@ -936,9 +936,9 @@ static const struct cs_extent_def ci_SECT_CONTEXT_defs[] =      {ci_SECT_CONTEXT_def_5, 0x0000a2a0, 2 },      {ci_SECT_CONTEXT_def_6, 0x0000a2a3, 1 },      {ci_SECT_CONTEXT_def_7, 0x0000a2a5, 233 }, -    { 0, 0, 0 } +    { NULL, 0, 0 }  };  static const struct cs_section_def ci_cs_data[] = {      { ci_SECT_CONTEXT_defs, SECT_CONTEXT }, -    { 0, SECT_NONE } +    { NULL, SECT_NONE }  }; diff --git a/drivers/gpu/drm/radeon/clearstate_si.h b/drivers/gpu/drm/radeon/clearstate_si.h index b994cb2a35a..66e39cdb5cb 100644 --- a/drivers/gpu/drm/radeon/clearstate_si.h +++ b/drivers/gpu/drm/radeon/clearstate_si.h @@ -933,9 +933,9 @@ static const struct cs_extent_def si_SECT_CONTEXT_defs[] =      {si_SECT_CONTEXT_def_5, 0x0000a2a1, 1 },      {si_SECT_CONTEXT_def_6, 0x0000a2a3, 1 },      {si_SECT_CONTEXT_def_7, 0x0000a2a5, 233 }, -    { 0, 0, 0 } +    { NULL, 0, 0 }  };  static const struct cs_section_def si_cs_data[] = {      { si_SECT_CONTEXT_defs, SECT_CONTEXT }, -    { 0, SECT_NONE } +    { NULL, SECT_NONE }  }; diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c index 91bb470de0a..47d31e91575 100644 --- a/drivers/gpu/drm/radeon/cypress_dpm.c +++ b/drivers/gpu/drm/radeon/cypress_dpm.c @@ -299,7 +299,9 @@ void cypress_program_response_times(struct radeon_device *rdev)  static int cypress_pcie_performance_request(struct radeon_device *rdev,  					    u8 perf_req, bool advertise)  { +#if defined(CONFIG_ACPI)  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); +#endif  	u32 tmp;  	udelay(10); @@ -1549,7 +1551,7 @@ int cypress_populate_smc_voltage_tables(struct radeon_device *rdev,  		table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDCI] = 0;  		table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDCI] = -			cpu_to_be32(eg_pi->vddc_voltage_table.mask_low); +			cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);  	}  	return 0; @@ -1903,21 +1905,6 @@ int cypress_dpm_enable(struct radeon_device *rdev)  	if (pi->mg_clock_gating)  		cypress_mg_clock_gating_enable(rdev, true); -	if (rdev->irq.installed && -	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { -		PPSMC_Result result; - -		ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); -		if (ret) -			return ret; -		rdev->irq.dpm_thermal = true; -		radeon_irq_set(rdev); -		result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); - -		if (result != PPSMC_Result_OK) -			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); -	} -  	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);  	return 0; @@ -2049,6 +2036,10 @@ int cypress_dpm_init(struct radeon_device *rdev)  	pi->min_vddc_in_table = 0;  	pi->max_vddc_in_table = 0; +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = rv7xx_parse_power_table(rdev);  	if (ret)  		return ret; diff --git a/drivers/gpu/drm/radeon/dce3_1_afmt.c b/drivers/gpu/drm/radeon/dce3_1_afmt.c new file mode 100644 index 00000000000..51800e340a5 --- /dev/null +++ b/drivers/gpu/drm/radeon/dce3_1_afmt.c @@ -0,0 +1,244 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * Copyright 2014 Rafał Miłecki + * + * 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. + */ +#include <linux/hdmi.h> +#include <drm/drmP.h> +#include "radeon.h" +#include "radeon_asic.h" +#include "r600d.h" + +static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) +{ +	struct radeon_device *rdev = encoder->dev->dev_private; +	struct drm_connector *connector; +	struct radeon_connector *radeon_connector = NULL; +	u32 tmp; +	u8 *sadb; +	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_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); +		return; +	} + +	/* program the speaker allocation */ +	tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); +	tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); +	/* set HDMI mode */ +	tmp |= HDMI_CONNECTION; +	if (sad_count) +		tmp |= SPEAKER_ALLOCATION(sadb[0]); +	else +		tmp |= SPEAKER_ALLOCATION(5); /* stereo */ +	WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); + +	kfree(sadb); +} + +static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder) +{ +	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; + +	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 }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD }, +		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP }, +		{ 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; +		int max_channels = -1; +		int j; + +		for (j = 0; j < sad_count; j++) { +			struct cea_sad *sad = &sads[j]; + +			if (sad->format == eld_reg_to_type[i][1]) { +				if (sad->channels > max_channels) { +					value = MAX_CHANNELS(sad->channels) | +						DESCRIPTOR_BYTE_2(sad->byte2) | +						SUPPORTED_FREQUENCIES(sad->freq); +					max_channels = sad->channels; +				} + +				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) +					stereo_freqs |= sad->freq; +				else +					break; +			} +		} + +		value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); + +		WREG32(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) +{ +	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) +		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, false); + +	r600_audio_set_dto(encoder, mode->clock); + +	WREG32(HDMI0_VBI_PACKET_CONTROL + offset, +	       HDMI0_NULL_SEND); /* send null packets when required */ + +	WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000); + +	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 */ +	} 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 */ +	} + +	if (ASIC_IS_DCE32(rdev)) { +		dce3_2_afmt_write_speaker_allocation(encoder); +		dce3_2_afmt_write_sad_regs(encoder); +	} + +	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; +	} + +	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)); +	r600_hdmi_update_ACR(encoder, mode->clock); + +	/* 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); + +	r600_hdmi_audio_workaround(encoder); + +	/* enable audio after to setting up hw */ +	r600_audio_enable(rdev, dig->afmt->pin, true); +} diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index 85a69d2ea3d..0a65dc7e93e 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c @@ -93,15 +93,60 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder)  	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 = dig->afmt->offset; +	u32 offset; -	if (!dig->afmt->pin) +	if (!dig || !dig->afmt || !dig->afmt->pin)  		return; +	offset = dig->afmt->offset; +  	WREG32(AFMT_AUDIO_SRC_CONTROL + offset,  	       AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));  } +void dce6_afmt_write_latency_fields(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; +	struct drm_connector *connector; +	struct radeon_connector *radeon_connector = NULL; +	u32 tmp = 0, offset; + +	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; +	} + +	if (mode->flags & DRM_MODE_FLAG_INTERLACE) { +		if (connector->latency_present[1]) +			tmp = VIDEO_LIPSYNC(connector->video_latency[1]) | +				AUDIO_LIPSYNC(connector->audio_latency[1]); +		else +			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); +	} else { +		if (connector->latency_present[0]) +			tmp = VIDEO_LIPSYNC(connector->video_latency[0]) | +				AUDIO_LIPSYNC(connector->audio_latency[0]); +		else +			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); +	} +	WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp); +} +  void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)  {  	struct radeon_device *rdev = encoder->dev->dev_private; @@ -113,7 +158,7 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)  	u8 *sadb;  	int sad_count; -	if (!dig->afmt->pin) +	if (!dig || !dig->afmt || !dig->afmt->pin)  		return;  	offset = dig->afmt->pin->offset; @@ -129,7 +174,7 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)  	}  	sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); -	if (sad_count < 0) { +	if (sad_count <= 0) {  		DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);  		return;  	} @@ -174,7 +219,7 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)  		{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },  	}; -	if (!dig->afmt->pin) +	if (!dig || !dig->afmt || !dig->afmt->pin)  		return;  	offset = dig->afmt->pin->offset; @@ -190,7 +235,7 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)  	}  	sad_count = drm_edid_to_sad(radeon_connector->edid, &sads); -	if (sad_count < 0) { +	if (sad_count <= 0) {  		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);  		return;  	} @@ -198,20 +243,30 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)  	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {  		u32 value = 0; +		u8 stereo_freqs = 0; +		int max_channels = -1;  		int j;  		for (j = 0; j < sad_count; j++) {  			struct cea_sad *sad = &sads[j];  			if (sad->format == eld_reg_to_type[i][1]) { -				value = MAX_CHANNELS(sad->channels) | -					DESCRIPTOR_BYTE_2(sad->byte2) | -					SUPPORTED_FREQUENCIES(sad->freq); +				if (sad->channels > max_channels) { +					value = MAX_CHANNELS(sad->channels) | +						DESCRIPTOR_BYTE_2(sad->byte2) | +						SUPPORTED_FREQUENCIES(sad->freq); +					max_channels = sad->channels; +				} +  				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) -					value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq); -				break; +					stereo_freqs |= sad->freq; +				else +					break;  			}  		} + +		value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); +  		WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);  	} @@ -223,13 +278,15 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev)  	return !ASIC_IS_NODCE(rdev);  } -static void dce6_audio_enable(struct radeon_device *rdev, -			      struct r600_audio_pin *pin, -			      bool enable) +void dce6_audio_enable(struct radeon_device *rdev, +		       struct r600_audio_pin *pin, +		       bool enable)  { +	if (!pin) +		return; +  	WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL, -			AUDIO_ENABLED); -	DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id); +			enable ? AUDIO_ENABLED : 0);  }  static const u32 pin_offsets[7] = @@ -252,9 +309,17 @@ int dce6_audio_init(struct radeon_device *rdev)  	rdev->audio.enabled = true; -	if (ASIC_IS_DCE8(rdev)) +	if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */  		rdev->audio.num_pins = 7; -	else +	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;  	for (i = 0; i < rdev->audio.num_pins; i++) { @@ -266,7 +331,8 @@ int dce6_audio_init(struct radeon_device *rdev)  		rdev->audio.pin[i].connected = false;  		rdev->audio.pin[i].offset = pin_offsets[i];  		rdev->audio.pin[i].id = i; -		dce6_audio_enable(rdev, &rdev->audio.pin[i], true); +		/* disable audio.  it will be set up later */ +		dce6_audio_enable(rdev, &rdev->audio.pin[i], false);  	}  	return 0; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 555164e270a..15e4f28015e 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -146,6 +146,7 @@ extern u32 si_get_csb_size(struct radeon_device *rdev);  extern void si_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer);  extern u32 cik_get_csb_size(struct radeon_device *rdev);  extern void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer); +extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);  static const u32 evergreen_golden_registers[] =  { @@ -188,7 +189,7 @@ static const u32 evergreen_golden_registers[] =  	0x8c1c, 0xffffffff, 0x00001010,  	0x28350, 0xffffffff, 0x00000000,  	0xa008, 0xffffffff, 0x00010000, -	0x5cc, 0xffffffff, 0x00000001, +	0x5c4, 0xffffffff, 0x00000001,  	0x9508, 0xffffffff, 0x00000002,  	0x913c, 0x0000000f, 0x0000000a  }; @@ -475,7 +476,7 @@ static const u32 cedar_golden_registers[] =  	0x8c1c, 0xffffffff, 0x00001010,  	0x28350, 0xffffffff, 0x00000000,  	0xa008, 0xffffffff, 0x00010000, -	0x5cc, 0xffffffff, 0x00000001, +	0x5c4, 0xffffffff, 0x00000001,  	0x9508, 0xffffffff, 0x00000002  }; @@ -634,7 +635,7 @@ static const u32 juniper_mgcg_init[] =  static const u32 supersumo_golden_registers[] =  {  	0x5eb4, 0xffffffff, 0x00000002, -	0x5cc, 0xffffffff, 0x00000001, +	0x5c4, 0xffffffff, 0x00000001,  	0x7030, 0xffffffff, 0x00000011,  	0x7c30, 0xffffffff, 0x00000011,  	0x6104, 0x01000300, 0x00000000, @@ -718,7 +719,7 @@ static const u32 sumo_golden_registers[] =  static const u32 wrestler_golden_registers[] =  {  	0x5eb4, 0xffffffff, 0x00000002, -	0x5cc, 0xffffffff, 0x00000001, +	0x5c4, 0xffffffff, 0x00000001,  	0x7030, 0xffffffff, 0x00000011,  	0x7c30, 0xffffffff, 0x00000011,  	0x6104, 0x01000300, 0x00000000, @@ -1174,23 +1175,72 @@ int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)  void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)  { -	u16 ctl, v; -	int err; - -	err = pcie_capability_read_word(rdev->pdev, PCI_EXP_DEVCTL, &ctl); -	if (err) -		return; - -	v = (ctl & PCI_EXP_DEVCTL_READRQ) >> 12; +	int readrq; +	u16 v; +	readrq = pcie_get_readrq(rdev->pdev); +	v = ffs(readrq) - 8;  	/* if bios or OS sets MAX_READ_REQUEST_SIZE to an invalid value, fix it  	 * to avoid hangs or perfomance issues  	 */ -	if ((v == 0) || (v == 6) || (v == 7)) { -		ctl &= ~PCI_EXP_DEVCTL_READRQ; -		ctl |= (2 << 12); -		pcie_capability_write_word(rdev->pdev, PCI_EXP_DEVCTL, ctl); +	if ((v == 0) || (v == 6) || (v == 7)) +		pcie_set_readrq(rdev->pdev, 512); +} + +void dce4_program_fmt(struct drm_encoder *encoder) +{ +	struct drm_device *dev = encoder->dev; +	struct radeon_device *rdev = dev->dev_private; +	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); +	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); +	int bpc = 0; +	u32 tmp = 0; +	enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE; + +	if (connector) { +		struct radeon_connector *radeon_connector = to_radeon_connector(connector); +		bpc = radeon_get_monitor_bpc(connector); +		dither = radeon_connector->dither; +	} + +	/* LVDS/eDP FMT is set up by atom */ +	if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT) +		return; + +	/* not needed for analog */ +	if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) || +	    (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2)) +		return; + +	if (bpc == 0) +		return; + +	switch (bpc) { +	case 6: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE | +				FMT_SPATIAL_DITHER_EN); +		else +			tmp |= FMT_TRUNCATE_EN; +		break; +	case 8: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= (FMT_FRAME_RANDOM_ENABLE | FMT_HIGHPASS_RANDOM_ENABLE | +				FMT_RGB_RANDOM_ENABLE | +				FMT_SPATIAL_DITHER_EN | FMT_SPATIAL_DITHER_DEPTH); +		else +			tmp |= (FMT_TRUNCATE_EN | FMT_TRUNCATE_DEPTH); +		break; +	case 10: +	default: +		/* not needed */ +		break;  	} + +	WREG32(FMT_BIT_DEPTH_CONTROL + radeon_crtc->crtc_offset, tmp);  }  static bool dce4_is_in_vblank(struct radeon_device *rdev, int crtc) @@ -1251,36 +1301,6 @@ void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)  }  /** - * radeon_irq_kms_pflip_irq_get - pre-pageflip callback. - * - * @rdev: radeon_device pointer - * @crtc: crtc to prepare for pageflip on - * - * Pre-pageflip callback (evergreen+). - * Enables the pageflip irq (vblank irq). - */ -void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc) -{ -	/* enable the pflip int */ -	radeon_irq_kms_pflip_irq_get(rdev, crtc); -} - -/** - * evergreen_post_page_flip - pos-pageflip callback. - * - * @rdev: radeon_device pointer - * @crtc: crtc to cleanup pageflip on - * - * Post-pageflip callback (evergreen+). - * Disables the pageflip irq (vblank irq). - */ -void evergreen_post_page_flip(struct radeon_device *rdev, int crtc) -{ -	/* disable the pflip int */ -	radeon_irq_kms_pflip_irq_put(rdev, crtc); -} - -/**   * evergreen_page_flip - pageflip callback.   *   * @rdev: radeon_device pointer @@ -1293,7 +1313,7 @@ void evergreen_post_page_flip(struct radeon_device *rdev, int crtc)   * double buffered update to take place.   * Returns the current update pending status.   */ -u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  {  	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];  	u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset); @@ -1325,9 +1345,23 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  	/* Unlock the lock, so double-buffering can take place inside vblank */  	tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK;  	WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); +} + +/** + * evergreen_page_flip_pending - check if page flip is still pending + * + * @rdev: radeon_device pointer + * @crtc_id: crtc to check + * + * Returns the current update pending status. + */ +bool evergreen_page_flip_pending(struct radeon_device *rdev, int crtc_id) +{ +	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];  	/* Return current update_pending status: */ -	return RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING; +	return !!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & +		EVERGREEN_GRPH_SURFACE_UPDATE_PENDING);  }  /* get temperature in millidegrees */ @@ -1630,7 +1664,7 @@ bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)  	case RADEON_HPD_6:  		if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE)  			connected = true; -			break; +		break;  	default:  		break;  	} @@ -2608,8 +2642,9 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s  	for (i = 0; i < rdev->num_crtc; i++) {  		if (save->crtc_enabled[i]) {  			tmp = RREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i]); -			if ((tmp & 0x3) != 0) { -				tmp &= ~0x3; +			if ((tmp & 0x7) != 3) { +				tmp &= ~0x7; +				tmp |= 0x3;  				WREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i], tmp);  			}  			tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); @@ -2940,8 +2975,6 @@ static int evergreen_cp_resume(struct radeon_device *rdev)  	WREG32(CP_RB_BASE, ring->gpu_addr >> 8);  	WREG32(CP_DEBUG, (1 << 27) | (1 << 28)); -	ring->rptr = RREG32(CP_RB_RPTR); -  	evergreen_cp_start(rdev);  	ring->ready = true;  	r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring); @@ -3131,7 +3164,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)  		rdev->config.evergreen.sx_max_export_size = 256;  		rdev->config.evergreen.sx_max_export_pos_size = 64;  		rdev->config.evergreen.sx_max_export_smx_size = 192; -		rdev->config.evergreen.max_hw_contexts = 8; +		rdev->config.evergreen.max_hw_contexts = 4;  		rdev->config.evergreen.sq_num_cf_insts = 2;  		rdev->config.evergreen.sc_prim_fifo_size = 0x40; @@ -3305,6 +3338,18 @@ static void evergreen_gpu_init(struct radeon_device *rdev)  			disabled_rb_mask &= ~(1 << i);  	} +	for (i = 0; i < rdev->config.evergreen.num_ses; i++) { +		u32 simd_disable_bitmap; + +		WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); +		WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); +		simd_disable_bitmap = (RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffff0000) >> 16; +		simd_disable_bitmap |= 0xffffffff << rdev->config.evergreen.max_simds; +		tmp <<= 16; +		tmp |= simd_disable_bitmap; +	} +	rdev->config.evergreen.active_simds = hweight32(~tmp); +  	WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES);  	WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); @@ -3818,6 +3863,48 @@ static void evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)  	evergreen_print_gpu_status_regs(rdev);  } +void evergreen_gpu_pci_config_reset(struct radeon_device *rdev) +{ +	struct evergreen_mc_save save; +	u32 tmp, i; + +	dev_info(rdev->dev, "GPU pci config reset\n"); + +	/* disable dpm? */ + +	/* Disable CP parsing/prefetching */ +	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); +	udelay(50); +	/* Disable DMA */ +	tmp = RREG32(DMA_RB_CNTL); +	tmp &= ~DMA_RB_ENABLE; +	WREG32(DMA_RB_CNTL, tmp); +	/* XXX other engines? */ + +	/* halt the rlc */ +	r600_rlc_stop(rdev); + +	udelay(50); + +	/* set mclk/sclk to bypass */ +	rv770_set_clk_bypass_mode(rdev); +	/* disable BM */ +	pci_clear_master(rdev->pdev); +	/* disable mem access */ +	evergreen_mc_stop(rdev, &save); +	if (evergreen_mc_wait_for_idle(rdev)) { +		dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); +	} +	/* reset */ +	radeon_pci_config_reset(rdev); +	/* wait for asic to come out of reset */ +	for (i = 0; i < rdev->usec_timeout; i++) { +		if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) +			break; +		udelay(1); +	} +} +  int evergreen_asic_reset(struct radeon_device *rdev)  {  	u32 reset_mask; @@ -3827,10 +3914,17 @@ int evergreen_asic_reset(struct radeon_device *rdev)  	if (reset_mask)  		r600_set_bios_scratch_engine_hung(rdev, true); +	/* try soft reset */  	evergreen_gpu_soft_reset(rdev, reset_mask);  	reset_mask = evergreen_gpu_check_soft_reset(rdev); +	/* try pci config reset */ +	if (reset_mask && radeon_hard_reset) +		evergreen_gpu_pci_config_reset(rdev); + +	reset_mask = evergreen_gpu_check_soft_reset(rdev); +  	if (!reset_mask)  		r600_set_bios_scratch_engine_hung(rdev, false); @@ -3853,11 +3947,9 @@ bool evergreen_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin  	if (!(reset_mask & (RADEON_RESET_GFX |  			    RADEON_RESET_COMPUTE |  			    RADEON_RESET_CP))) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force CP activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -3963,7 +4055,7 @@ int sumo_rlc_init(struct radeon_device *rdev)  		if (rdev->family >= CHIP_TAHITI) {  			/* SI */  			for (i = 0; i < rdev->rlc.reg_list_size; i++) -				dst_ptr[i] = src_ptr[i]; +				dst_ptr[i] = cpu_to_le32(src_ptr[i]);  		} else {  			/* ON/LN/TN */  			/* format: @@ -3977,10 +4069,10 @@ int sumo_rlc_init(struct radeon_device *rdev)  				if (i < dws)  					data |= (src_ptr[i] >> 2) << 16;  				j = (((i - 1) * 3) / 2); -				dst_ptr[j] = data; +				dst_ptr[j] = cpu_to_le32(data);  			}  			j = ((i * 3) / 2); -			dst_ptr[j] = RLC_SAVE_RESTORE_LIST_END_MARKER; +			dst_ptr[j] = cpu_to_le32(RLC_SAVE_RESTORE_LIST_END_MARKER);  		}  		radeon_bo_kunmap(rdev->rlc.save_restore_obj);  		radeon_bo_unreserve(rdev->rlc.save_restore_obj); @@ -4042,40 +4134,40 @@ int sumo_rlc_init(struct radeon_device *rdev)  			cik_get_csb_buffer(rdev, dst_ptr);  		} else if (rdev->family >= CHIP_TAHITI) {  			reg_list_mc_addr = rdev->rlc.clear_state_gpu_addr + 256; -			dst_ptr[0] = upper_32_bits(reg_list_mc_addr); -			dst_ptr[1] = lower_32_bits(reg_list_mc_addr); -			dst_ptr[2] = rdev->rlc.clear_state_size; +			dst_ptr[0] = cpu_to_le32(upper_32_bits(reg_list_mc_addr)); +			dst_ptr[1] = cpu_to_le32(lower_32_bits(reg_list_mc_addr)); +			dst_ptr[2] = cpu_to_le32(rdev->rlc.clear_state_size);  			si_get_csb_buffer(rdev, &dst_ptr[(256/4)]);  		} else {  			reg_list_hdr_blk_index = 0;  			reg_list_mc_addr = rdev->rlc.clear_state_gpu_addr + (reg_list_blk_index * 4);  			data = upper_32_bits(reg_list_mc_addr); -			dst_ptr[reg_list_hdr_blk_index] = data; +			dst_ptr[reg_list_hdr_blk_index] = cpu_to_le32(data);  			reg_list_hdr_blk_index++;  			for (i = 0; cs_data[i].section != NULL; i++) {  				for (j = 0; cs_data[i].section[j].extent != NULL; j++) {  					reg_num = cs_data[i].section[j].reg_count;  					data = reg_list_mc_addr & 0xffffffff; -					dst_ptr[reg_list_hdr_blk_index] = data; +					dst_ptr[reg_list_hdr_blk_index] = cpu_to_le32(data);  					reg_list_hdr_blk_index++;  					data = (cs_data[i].section[j].reg_index * 4) & 0xffffffff; -					dst_ptr[reg_list_hdr_blk_index] = data; +					dst_ptr[reg_list_hdr_blk_index] = cpu_to_le32(data);  					reg_list_hdr_blk_index++;  					data = 0x08000000 | (reg_num * 4); -					dst_ptr[reg_list_hdr_blk_index] = data; +					dst_ptr[reg_list_hdr_blk_index] = cpu_to_le32(data);  					reg_list_hdr_blk_index++;  					for (k = 0; k < reg_num; k++) {  						data = cs_data[i].section[j].extent[k]; -						dst_ptr[reg_list_blk_index + k] = data; +						dst_ptr[reg_list_blk_index + k] = cpu_to_le32(data);  					}  					reg_list_mc_addr += reg_num * 4;  					reg_list_blk_index += reg_num;  				}  			} -			dst_ptr[reg_list_hdr_blk_index] = RLC_CLEAR_STATE_END_MARKER; +			dst_ptr[reg_list_hdr_blk_index] = cpu_to_le32(RLC_CLEAR_STATE_END_MARKER);  		}  		radeon_bo_kunmap(rdev->rlc.clear_state_obj);  		radeon_bo_unreserve(rdev->rlc.clear_state_obj); @@ -4249,8 +4341,8 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)  		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);  	} -	/* only one DAC on DCE6 */ -	if (!ASIC_IS_DCE6(rdev)) +	/* only one DAC on DCE5 */ +	if (!ASIC_IS_DCE5(rdev))  		WREG32(DACA_AUTODETECT_INT_CONTROL, 0);  	WREG32(DACB_AUTODETECT_INT_CONTROL, 0); @@ -4276,7 +4368,6 @@ int evergreen_irq_set(struct radeon_device *rdev)  	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;  	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;  	u32 grbm_int_cntl = 0; -	u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;  	u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;  	u32 dma_cntl, dma_cntl1 = 0;  	u32 thermal_int = 0; @@ -4459,15 +4550,21 @@ int evergreen_irq_set(struct radeon_device *rdev)  		WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);  	} -	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); -	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); +	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, +	       GRPH_PFLIP_INT_MASK); +	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, +	       GRPH_PFLIP_INT_MASK);  	if (rdev->num_crtc >= 4) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	if (rdev->num_crtc >= 6) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	WREG32(DC_HPD1_INT_CONTROL, hpd1); @@ -4659,6 +4756,7 @@ static u32 evergreen_get_ih_wptr(struct radeon_device *rdev)  		tmp = RREG32(IH_RB_CNTL);  		tmp |= IH_WPTR_OVERFLOW_CLEAR;  		WREG32(IH_RB_CNTL, tmp); +		wptr &= ~RB_OVERFLOW;  	}  	return (wptr & rdev->ih.ptr_mask);  } @@ -4710,7 +4808,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[0])) -						radeon_crtc_handle_flip(rdev, 0); +						radeon_crtc_handle_vblank(rdev, 0);  					rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D1 vblank\n");  				} @@ -4736,7 +4834,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[1])) -						radeon_crtc_handle_flip(rdev, 1); +						radeon_crtc_handle_vblank(rdev, 1);  					rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D2 vblank\n");  				} @@ -4762,7 +4860,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[2])) -						radeon_crtc_handle_flip(rdev, 2); +						radeon_crtc_handle_vblank(rdev, 2);  					rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D3 vblank\n");  				} @@ -4788,7 +4886,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[3])) -						radeon_crtc_handle_flip(rdev, 3); +						radeon_crtc_handle_vblank(rdev, 3);  					rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D4 vblank\n");  				} @@ -4814,7 +4912,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[4])) -						radeon_crtc_handle_flip(rdev, 4); +						radeon_crtc_handle_vblank(rdev, 4);  					rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D5 vblank\n");  				} @@ -4840,7 +4938,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[5])) -						radeon_crtc_handle_flip(rdev, 5); +						radeon_crtc_handle_vblank(rdev, 5);  					rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D6 vblank\n");  				} @@ -4856,6 +4954,15 @@ restart_ih:  				break;  			}  			break; +		case 8: /* D1 page flip */ +		case 10: /* D2 page flip */ +		case 12: /* D3 page flip */ +		case 14: /* D4 page flip */ +		case 16: /* D5 page flip */ +		case 18: /* D6 page flip */ +			DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); +			radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); +			break;  		case 42: /* HPD hotplug */  			switch (src_data) {  			case 0: @@ -4961,14 +5068,16 @@ restart_ih:  		case 147:  			addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);  			status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS); +			/* reset addr and status */ +			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); +			if (addr == 0x0 && status == 0x0) +				break;  			dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);  			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",  				addr);  			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",  				status);  			cayman_vm_decode_fault(rdev, status, addr); -			/* reset addr and status */ -			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);  			break;  		case 176: /* CP_INT in ring buffer */  		case 177: /* CP_INT in IB1 */ @@ -5060,27 +5169,12 @@ static int evergreen_startup(struct radeon_device *rdev)  	evergreen_mc_program(rdev); -	if (ASIC_IS_DCE5(rdev)) { -		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { -			r = ni_init_microcode(rdev); -			if (r) { -				DRM_ERROR("Failed to load firmware!\n"); -				return r; -			} -		} +	if (ASIC_IS_DCE5(rdev) && !rdev->pm.dpm_enabled) {  		r = ni_mc_load_microcode(rdev);  		if (r) {  			DRM_ERROR("Failed to load MC firmware!\n");  			return r;  		} -	} else { -		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { -			r = r600_init_microcode(rdev); -			if (r) { -				DRM_ERROR("Failed to load firmware!\n"); -				return r; -			} -		}  	}  	if (rdev->flags & RADEON_IS_AGP) { @@ -5150,14 +5244,12 @@ static int evergreen_startup(struct radeon_device *rdev)  	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, -			     R600_CP_RB_RPTR, R600_CP_RB_WPTR,  			     RADEON_CP_PACKET2);  	if (r)  		return r;  	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, -			     DMA_RB_RPTR, DMA_RB_WPTR,  			     DMA_PACKET(DMA_PACKET_NOP, 0, 0));  	if (r)  		return r; @@ -5175,7 +5267,6 @@ static int evergreen_startup(struct radeon_device *rdev)  	ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];  	if (ring->ring_size) {  		r = radeon_ring_init(rdev, ring, ring->ring_size, 0, -				     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,  				     RADEON_CP_PACKET2);  		if (!r)  			r = uvd_v1_0_init(rdev); @@ -5218,6 +5309,9 @@ int evergreen_resume(struct radeon_device *rdev)  	/* init golden registers */  	evergreen_init_golden_registers(rdev); +	if (rdev->pm.pm_method == PM_METHOD_DPM) +		radeon_pm_resume(rdev); +  	rdev->accel_working = true;  	r = evergreen_startup(rdev);  	if (r) { @@ -5232,6 +5326,7 @@ int evergreen_resume(struct radeon_device *rdev)  int evergreen_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r600_audio_fini(rdev);  	uvd_v1_0_fini(rdev);  	radeon_uvd_suspend(rdev); @@ -5308,6 +5403,27 @@ int evergreen_init(struct radeon_device *rdev)  	if (r)  		return r; +	if (ASIC_IS_DCE5(rdev)) { +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { +			r = ni_init_microcode(rdev); +			if (r) { +				DRM_ERROR("Failed to load firmware!\n"); +				return r; +			} +		} +	} else { +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { +			r = r600_init_microcode(rdev); +			if (r) { +				DRM_ERROR("Failed to load firmware!\n"); +				return r; +			} +		} +	} + +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;  	r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -5360,6 +5476,7 @@ int evergreen_init(struct radeon_device *rdev)  void evergreen_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r600_audio_fini(rdev);  	r700_cp_fini(rdev);  	r600_dma_fini(rdev); @@ -5369,9 +5486,9 @@ void evergreen_fini(struct radeon_device *rdev)  	radeon_wb_fini(rdev);  	radeon_ib_pool_fini(rdev);  	radeon_irq_kms_fini(rdev); -	evergreen_pcie_gart_fini(rdev);  	uvd_v1_0_fini(rdev);  	radeon_uvd_fini(rdev); +	evergreen_pcie_gart_fini(rdev);  	r600_vram_scratch_fini(rdev);  	radeon_gem_fini(rdev);  	radeon_fence_driver_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index eb8ac315f92..5c8b358f9fb 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -967,7 +967,10 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p)  	if (track->cb_dirty) {  		tmp = track->cb_target_mask;  		for (i = 0; i < 8; i++) { -			if ((tmp >> (i * 4)) & 0xF) { +			u32 format = G_028C70_FORMAT(track->cb_color_info[i]); + +			if (format != V_028C70_COLOR_INVALID && +			    (tmp >> (i * 4)) & 0xF) {  				/* at least one component is enabled */  				if (track->cb_color_bo[i] == NULL) {  					dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n", @@ -1162,7 +1165,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  					"0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		break;  	case DB_DEPTH_CONTROL:  		track->db_depth_control = radeon_get_ib_value(p, idx); @@ -1193,12 +1196,12 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			}  			ib[idx] &= ~Z_ARRAY_MODE(0xf);  			track->db_z_info &= ~Z_ARRAY_MODE(0xf); -			ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); -			track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { +			ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags)); +			track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags)); +			if (reloc->tiling_flags & RADEON_TILING_MACRO) {  				unsigned bankw, bankh, mtaspect, tile_split; -				evergreen_tiling_fields(reloc->lobj.tiling_flags, +				evergreen_tiling_fields(reloc->tiling_flags,  							&bankw, &bankh, &mtaspect,  							&tile_split);  				ib[idx] |= DB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); @@ -1234,7 +1237,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		track->db_z_read_offset = radeon_get_ib_value(p, idx); -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->db_z_read_bo = reloc->robj;  		track->db_dirty = true;  		break; @@ -1246,7 +1249,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		track->db_z_write_offset = radeon_get_ib_value(p, idx); -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->db_z_write_bo = reloc->robj;  		track->db_dirty = true;  		break; @@ -1258,7 +1261,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		track->db_s_read_offset = radeon_get_ib_value(p, idx); -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->db_s_read_bo = reloc->robj;  		track->db_dirty = true;  		break; @@ -1270,7 +1273,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		track->db_s_write_offset = radeon_get_ib_value(p, idx); -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->db_s_write_bo = reloc->robj;  		track->db_dirty = true;  		break; @@ -1294,7 +1297,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  		}  		tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;  		track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8; -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->vgt_strmout_bo[tmp] = reloc->robj;  		track->streamout_dirty = true;  		break; @@ -1314,7 +1317,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  					"0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  	case CB_TARGET_MASK:  		track->cb_target_mask = radeon_get_ib_value(p, idx);  		track->cb_dirty = true; @@ -1378,8 +1381,8 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  						"0x%04X\n", reg);  				return -EINVAL;  			} -			ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); -			track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); +			ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags)); +			track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));  		}  		track->cb_dirty = true;  		break; @@ -1396,8 +1399,8 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  						"0x%04X\n", reg);  				return -EINVAL;  			} -			ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); -			track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); +			ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags)); +			track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));  		}  		track->cb_dirty = true;  		break; @@ -1458,10 +1461,10 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { +			if (reloc->tiling_flags & RADEON_TILING_MACRO) {  				unsigned bankw, bankh, mtaspect, tile_split; -				evergreen_tiling_fields(reloc->lobj.tiling_flags, +				evergreen_tiling_fields(reloc->tiling_flags,  							&bankw, &bankh, &mtaspect,  							&tile_split);  				ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); @@ -1486,10 +1489,10 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { +			if (reloc->tiling_flags & RADEON_TILING_MACRO) {  				unsigned bankw, bankh, mtaspect, tile_split; -				evergreen_tiling_fields(reloc->lobj.tiling_flags, +				evergreen_tiling_fields(reloc->tiling_flags,  							&bankw, &bankh, &mtaspect,  							&tile_split);  				ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); @@ -1517,7 +1520,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->cb_color_fmask_bo[tmp] = reloc->robj;  		break;  	case CB_COLOR0_CMASK: @@ -1534,7 +1537,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->cb_color_cmask_bo[tmp] = reloc->robj;  		break;  	case CB_COLOR0_FMASK_SLICE: @@ -1575,7 +1578,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  		}  		tmp = (reg - CB_COLOR0_BASE) / 0x3c;  		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx); -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->cb_color_bo[tmp] = reloc->robj;  		track->cb_dirty = true;  		break; @@ -1591,7 +1594,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  		}  		tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8;  		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx); -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->cb_color_bo[tmp] = reloc->robj;  		track->cb_dirty = true;  		break; @@ -1603,7 +1606,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		track->htile_offset = radeon_get_ib_value(p, idx); -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->htile_bo = reloc->robj;  		track->db_dirty = true;  		break; @@ -1720,7 +1723,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  					"0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		break;  	case SX_MEMORY_EXPORT_BASE:  		if (p->rdev->family >= CHIP_CAYMAN) { @@ -1734,7 +1737,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  					"0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		break;  	case CAYMAN_SX_SCATTER_EXPORT_BASE:  		if (p->rdev->family < CHIP_CAYMAN) { @@ -1748,7 +1751,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  					"0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		break;  	case SX_MISC:  		track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0; @@ -1833,7 +1836,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         (idx_value & 0xfffffff0) +  		         ((u64)(tmp & 0xff) << 32); @@ -1879,7 +1882,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         idx_value +  		         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); @@ -1906,7 +1909,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         idx_value +  		         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); @@ -1934,7 +1937,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         radeon_get_ib_value(p, idx+1) +  		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); @@ -2024,7 +2027,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  			DRM_ERROR("bad DISPATCH_INDIRECT\n");  			return -EINVAL;  		} -		ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); +		ib[idx+0] = idx_value + (u32)(reloc->gpu_offset & 0xffffffff);  		r = evergreen_cs_track_check(p);  		if (r) {  			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); @@ -2046,7 +2049,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  				return -EINVAL;  			} -			offset = reloc->lobj.gpu_offset + +			offset = reloc->gpu_offset +  			         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +  			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); @@ -2103,7 +2106,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  				tmp = radeon_get_ib_value(p, idx) +  					((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); -				offset = reloc->lobj.gpu_offset + tmp; +				offset = reloc->gpu_offset + tmp;  				if ((tmp + size) > radeon_bo_size(reloc->robj)) {  					dev_warn(p->dev, "CP DMA src buffer too small (%llu %lu)\n", @@ -2141,7 +2144,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  				tmp = radeon_get_ib_value(p, idx+2) +  					((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32); -				offset = reloc->lobj.gpu_offset + tmp; +				offset = reloc->gpu_offset + tmp;  				if ((tmp + size) > radeon_bo_size(reloc->robj)) {  					dev_warn(p->dev, "CP DMA dst buffer too small (%llu %lu)\n", @@ -2171,7 +2174,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  				DRM_ERROR("bad SURFACE_SYNC\n");  				return -EINVAL;  			} -			ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +			ib[idx+2] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		}  		break;  	case PACKET3_EVENT_WRITE: @@ -2187,7 +2190,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  				DRM_ERROR("bad EVENT_WRITE\n");  				return -EINVAL;  			} -			offset = reloc->lobj.gpu_offset + +			offset = reloc->gpu_offset +  			         (radeon_get_ib_value(p, idx+1) & 0xfffffff8) +  			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); @@ -2209,7 +2212,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +  		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); @@ -2231,7 +2234,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +  		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); @@ -2299,11 +2302,11 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  				}  				if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {  					ib[idx+1+(i*8)+1] |= -						TEX_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); -					if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { +						TEX_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags)); +					if (reloc->tiling_flags & RADEON_TILING_MACRO) {  						unsigned bankw, bankh, mtaspect, tile_split; -						evergreen_tiling_fields(reloc->lobj.tiling_flags, +						evergreen_tiling_fields(reloc->tiling_flags,  									&bankw, &bankh, &mtaspect,  									&tile_split);  						ib[idx+1+(i*8)+6] |= TEX_TILE_SPLIT(tile_split); @@ -2315,7 +2318,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  					}  				}  				texture = reloc->robj; -				toffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +				toffset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  				/* tex mip base */  				tex_dim = ib[idx+1+(i*8)+0] & 0x7; @@ -2334,7 +2337,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  						DRM_ERROR("bad SET_RESOURCE (tex)\n");  						return -EINVAL;  					} -					moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +					moffset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  					mipmap = reloc->robj;  				} @@ -2361,7 +2364,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  					ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj) - offset;  				} -				offset64 = reloc->lobj.gpu_offset + offset; +				offset64 = reloc->gpu_offset + offset;  				ib[idx+1+(i*8)+0] = offset64;  				ib[idx+1+(i*8)+2] = (ib[idx+1+(i*8)+2] & 0xffffff00) |  						    (upper_32_bits(offset64) & 0xff); @@ -2442,7 +2445,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			offset += reloc->lobj.gpu_offset; +			offset += reloc->gpu_offset;  			ib[idx+1] = offset;  			ib[idx+2] = upper_32_bits(offset) & 0xff;  		} @@ -2461,7 +2464,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			offset += reloc->lobj.gpu_offset; +			offset += reloc->gpu_offset;  			ib[idx+3] = offset;  			ib[idx+4] = upper_32_bits(offset) & 0xff;  		} @@ -2490,7 +2493,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  				  offset + 8, radeon_bo_size(reloc->robj));  			return -EINVAL;  		} -		offset += reloc->lobj.gpu_offset; +		offset += reloc->gpu_offset;  		ib[idx+0] = offset;  		ib[idx+1] = upper_32_bits(offset) & 0xff;  		break; @@ -2515,7 +2518,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			offset += reloc->lobj.gpu_offset; +			offset += reloc->gpu_offset;  			ib[idx+1] = offset;  			ib[idx+2] = upper_32_bits(offset) & 0xff;  		} else { @@ -2539,7 +2542,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			offset += reloc->lobj.gpu_offset; +			offset += reloc->gpu_offset;  			ib[idx+3] = offset;  			ib[idx+4] = upper_32_bits(offset) & 0xff;  		} else { @@ -2714,7 +2717,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  				dst_offset = radeon_get_ib_value(p, idx+1);  				dst_offset <<= 8; -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); +				ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);  				p->idx += count + 7;  				break;  			/* linear */ @@ -2722,8 +2725,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  				dst_offset = radeon_get_ib_value(p, idx+1);  				dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +				ib[idx+2] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;  				p->idx += count + 3;  				break;  			default: @@ -2765,10 +2768,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  							dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));  					return -EINVAL;  				} -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; -				ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +				ib[idx+2] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +				ib[idx+3] += upper_32_bits(dst_reloc->gpu_offset) & 0xff; +				ib[idx+4] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  				p->idx += 5;  				break;  			/* Copy L2T/T2L */ @@ -2778,22 +2781,22 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  					/* tiled src, linear dst */  					src_offset = radeon_get_ib_value(p, idx+1);  					src_offset <<= 8; -					ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); +					ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8);  					dst_offset = radeon_get_ib_value(p, idx + 7);  					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32; -					ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+7] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +					ib[idx+8] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;  				} else {  					/* linear src, tiled dst */  					src_offset = radeon_get_ib_value(p, idx+7);  					src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32; -					ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+7] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +					ib[idx+8] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  					dst_offset = radeon_get_ib_value(p, idx+1);  					dst_offset <<= 8; -					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); +					ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);  				}  				if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {  					dev_warn(p->dev, "DMA L2T, src buffer too small (%llu %lu)\n", @@ -2824,10 +2827,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  							dst_offset + count, radeon_bo_size(dst_reloc->robj));  					return -EINVAL;  				} -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xffffffff); -				ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xffffffff); -				ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; -				ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xffffffff); +				ib[idx+2] += (u32)(src_reloc->gpu_offset & 0xffffffff); +				ib[idx+3] += upper_32_bits(dst_reloc->gpu_offset) & 0xff; +				ib[idx+4] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  				p->idx += 5;  				break;  			/* Copy L2L, partial */ @@ -2837,10 +2840,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  					DRM_ERROR("L2L Partial is cayman only !\n");  					return -EINVAL;  				} -				ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset & 0xffffffff); -				ib[idx+2] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; -				ib[idx+4] += (u32)(dst_reloc->lobj.gpu_offset & 0xffffffff); -				ib[idx+5] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(src_reloc->gpu_offset & 0xffffffff); +				ib[idx+2] += upper_32_bits(src_reloc->gpu_offset) & 0xff; +				ib[idx+4] += (u32)(dst_reloc->gpu_offset & 0xffffffff); +				ib[idx+5] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;  				p->idx += 9;  				break; @@ -2873,12 +2876,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  							dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));  					return -EINVAL;  				} -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+3] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+4] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; -				ib[idx+5] += upper_32_bits(dst2_reloc->lobj.gpu_offset) & 0xff; -				ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +				ib[idx+2] += (u32)(dst2_reloc->gpu_offset & 0xfffffffc); +				ib[idx+3] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +				ib[idx+4] += upper_32_bits(dst_reloc->gpu_offset) & 0xff; +				ib[idx+5] += upper_32_bits(dst2_reloc->gpu_offset) & 0xff; +				ib[idx+6] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  				p->idx += 7;  				break;  			/* Copy L2T Frame to Field */ @@ -2913,10 +2916,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  							dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));  					return -EINVAL;  				} -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); -				ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8); -				ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8); +				ib[idx+2] += (u32)(dst2_reloc->gpu_offset >> 8); +				ib[idx+8] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +				ib[idx+9] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  				p->idx += 10;  				break;  			/* Copy L2T/T2L, partial */ @@ -2929,16 +2932,16 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  				/* detile bit */  				if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) {  					/* tiled src, linear dst */ -					ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); +					ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8); -					ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+7] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +					ib[idx+8] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;  				} else {  					/* linear src, tiled dst */ -					ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+7] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +					ib[idx+8] += upper_32_bits(src_reloc->gpu_offset) & 0xff; -					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); +					ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);  				}  				p->idx += 12;  				break; @@ -2975,10 +2978,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  							dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));  					return -EINVAL;  				} -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); -				ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8); -				ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8); +				ib[idx+2] += (u32)(dst2_reloc->gpu_offset >> 8); +				ib[idx+8] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +				ib[idx+9] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  				p->idx += 10;  				break;  			/* Copy L2T/T2L (tile units) */ @@ -2989,22 +2992,22 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  					/* tiled src, linear dst */  					src_offset = radeon_get_ib_value(p, idx+1);  					src_offset <<= 8; -					ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); +					ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8);  					dst_offset = radeon_get_ib_value(p, idx+7);  					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32; -					ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+7] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +					ib[idx+8] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;  				} else {  					/* linear src, tiled dst */  					src_offset = radeon_get_ib_value(p, idx+7);  					src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32; -					ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+7] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +					ib[idx+8] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  					dst_offset = radeon_get_ib_value(p, idx+1);  					dst_offset <<= 8; -					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); +					ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);  				}  				if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {  					dev_warn(p->dev, "DMA L2T, T2L src buffer too small (%llu %lu)\n", @@ -3025,8 +3028,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  					DRM_ERROR("L2T, T2L Partial is cayman only !\n");  					return -EINVAL;  				} -				ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); -				ib[idx+4] += (u32)(dst_reloc->lobj.gpu_offset >> 8); +				ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8); +				ib[idx+4] += (u32)(dst_reloc->gpu_offset >> 8);  				p->idx += 13;  				break;  			/* Copy L2T broadcast (tile units) */ @@ -3062,10 +3065,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  							dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));  					return -EINVAL;  				} -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); -				ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8); -				ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8); +				ib[idx+2] += (u32)(dst2_reloc->gpu_offset >> 8); +				ib[idx+8] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +				ib[idx+9] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  				p->idx += 10;  				break;  			default: @@ -3086,8 +3089,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)  					 dst_offset, radeon_bo_size(dst_reloc->robj));  				return -EINVAL;  			} -			ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -			ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) << 16) & 0x00ff0000; +			ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +			ib[idx+3] += (upper_32_bits(dst_reloc->gpu_offset) << 16) & 0x00ff0000;  			p->idx += 4;  			break;  		case DMA_PACKET_NOP: diff --git a/drivers/gpu/drm/radeon/evergreen_dma.c b/drivers/gpu/drm/radeon/evergreen_dma.c index 6a0656d00ed..478caefe0fe 100644 --- a/drivers/gpu/drm/radeon/evergreen_dma.c +++ b/drivers/gpu/drm/radeon/evergreen_dma.c @@ -131,13 +131,8 @@ int evergreen_copy_dma(struct radeon_device *rdev,  		return r;  	} -	if (radeon_fence_need_sync(*fence, ring->idx)) { -		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, -					    ring->idx); -		radeon_fence_note_sync(*fence, ring->idx); -	} else { -		radeon_semaphore_free(rdev, &sem, NULL); -	} +	radeon_semaphore_sync_to(sem, *fence); +	radeon_semaphore_sync_rings(rdev, sem, ring->idx);  	for (i = 0; i < num_loops; i++) {  		cur_size_in_dw = size_in_dw; @@ -156,6 +151,7 @@ int evergreen_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} @@ -179,11 +175,9 @@ bool evergreen_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin  	u32 reset_mask = evergreen_gpu_check_soft_reset(rdev);  	if (!(reset_mask & RADEON_RESET_DMA)) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force ring activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index f71ce390aeb..1ec0e6e83f9 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -35,6 +35,8 @@  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);  /*   * update the N and CTS parameters for a given pixel clock rate @@ -58,6 +60,42 @@ static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t cloc  	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) +{ +	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]) | +				AUDIO_LIPSYNC(connector->audio_latency[1]); +		else +			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); +	} else { +		if (connector->latency_present[0]) +			tmp = VIDEO_LIPSYNC(connector->video_latency[0]) | +				AUDIO_LIPSYNC(connector->audio_latency[0]); +		else +			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); +	} +	WREG32(AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp); +} +  static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)  {  	struct radeon_device *rdev = encoder->dev->dev_private; @@ -68,8 +106,10 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)  	int sad_count;  	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { -		if (connector->encoder == encoder) +		if (connector->encoder == encoder) {  			radeon_connector = to_radeon_connector(connector); +			break; +		}  	}  	if (!radeon_connector) { @@ -78,7 +118,7 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)  	}  	sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); -	if (sad_count < 0) { +	if (sad_count <= 0) {  		DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);  		return;  	} @@ -121,8 +161,10 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)  	};  	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { -		if (connector->encoder == encoder) +		if (connector->encoder == encoder) {  			radeon_connector = to_radeon_connector(connector); +			break; +		}  	}  	if (!radeon_connector) { @@ -131,7 +173,7 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)  	}  	sad_count = drm_edid_to_sad(radeon_connector->edid, &sads); -	if (sad_count < 0) { +	if (sad_count <= 0) {  		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);  		return;  	} @@ -139,20 +181,30 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)  	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {  		u32 value = 0; +		u8 stereo_freqs = 0; +		int max_channels = -1;  		int j;  		for (j = 0; j < sad_count; j++) {  			struct cea_sad *sad = &sads[j];  			if (sad->format == eld_reg_to_type[i][1]) { -				value = MAX_CHANNELS(sad->channels) | -					DESCRIPTOR_BYTE_2(sad->byte2) | -					SUPPORTED_FREQUENCIES(sad->freq); +				if (sad->channels > max_channels) { +					value = MAX_CHANNELS(sad->channels) | +						DESCRIPTOR_BYTE_2(sad->byte2) | +						SUPPORTED_FREQUENCIES(sad->freq); +					max_channels = sad->channels; +				} +  				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) -					value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq); -				break; +					stereo_freqs |= sad->freq; +				else +					break;  			}  		} + +		value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); +  		WREG32(eld_reg_to_type[i][0], value);  	} @@ -241,10 +293,13 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	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;  	if (!dig || !dig->afmt)  		return; @@ -254,6 +309,21 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  		return;  	offset = dig->afmt->offset; +	/* 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; +	} + +	/* 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, false); +	} else { +		dig->afmt->pin = r600_audio_get_pin(rdev); +		r600_audio_enable(rdev, dig->afmt->pin, false); +	} +  	evergreen_audio_set_dto(encoder, mode->clock);  	WREG32(HDMI_VBI_PACKET_CONTROL + offset, @@ -261,6 +331,35 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000); +	val = RREG32(HDMI_CONTROL + offset); +	val &= ~HDMI_DEEP_COLOR_ENABLE; +	val &= ~HDMI_DEEP_COLOR_DEPTH_MASK; + +	switch (bpc) { +		case 0: +		case 6: +		case 8: +		case 16: +		default: +			DRM_DEBUG("%s: Disabling hdmi deep color for %d bpc.\n", +					 connector->name, bpc); +			break; +		case 10: +			val |= HDMI_DEEP_COLOR_ENABLE; +			val |= HDMI_DEEP_COLOR_DEPTH(HDMI_30BIT_DEEP_COLOR); +			DRM_DEBUG("%s: Enabling hdmi deep color 30 for 10 bpc.\n", +					 connector->name); +			break; +		case 12: +			val |= HDMI_DEEP_COLOR_ENABLE; +			val |= HDMI_DEEP_COLOR_DEPTH(HDMI_36BIT_DEEP_COLOR); +			DRM_DEBUG("%s: Enabling hdmi deep color 36 for 12 bpc.\n", +					 connector->name); +			break; +	} + +	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 */ @@ -287,9 +386,13 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	/* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */ -	WREG32(HDMI_ACR_PACKET_CONTROL + offset, -	       HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ -	       HDMI_ACR_SOURCE); /* select SW CTS value */ +	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); @@ -321,8 +424,10 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	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); @@ -355,12 +460,16 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode  	WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);  	WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);  	WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); + +	/* enable audio after to setting up hw */ +	if (ASIC_IS_DCE6(rdev)) +		dce6_audio_enable(rdev, dig->afmt->pin, true); +	else +		r600_audio_enable(rdev, dig->afmt->pin, true);  }  void evergreen_hdmi_enable(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; @@ -373,15 +482,6 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)  	if (!enable && !dig->afmt->enabled)  		return; -	if (enable) { -		if (ASIC_IS_DCE6(rdev)) -			dig->afmt->pin = dce6_audio_get_pin(rdev); -		else -			dig->afmt->pin = r600_audio_get_pin(rdev); -	} else { -		dig->afmt->pin = NULL; -	} -  	dig->afmt->enabled = enable;  	DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 8a4e641f0e3..23bff590fb6 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -33,6 +33,7 @@  #define EVERGREEN_PIF_PHY0_DATA                         0xc  #define EVERGREEN_PIF_PHY1_INDEX                        0x10  #define EVERGREEN_PIF_PHY1_DATA                         0x14 +#define EVERGREEN_MM_INDEX_HI                           0x18  #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS               0x310  #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH          0x324 @@ -115,6 +116,8 @@  #       define EVERGREEN_GRPH_ARRAY_LINEAR_ALIGNED      1  #       define EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1      2  #       define EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1      4 +#define EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL         0x6808 +#       define EVERGREEN_LUT_10BIT_BYPASS_EN            (1 << 8)  #define EVERGREEN_GRPH_SWAP_CONTROL                     0x680c  #       define EVERGREEN_GRPH_ENDIAN_SWAP(x)            (((x) & 0x3) << 0)  #       define EVERGREEN_GRPH_ENDIAN_NONE               0 @@ -236,7 +239,6 @@  #       define EVERGREEN_CRTC_V_BLANK                   (1 << 0)  #define EVERGREEN_CRTC_STATUS_POSITION                  0x6e90  #define EVERGREEN_CRTC_STATUS_HV_COUNT                  0x6ea0 -#define EVERGREEN_MASTER_UPDATE_MODE                    0x6ef8  #define EVERGREEN_CRTC_UPDATE_LOCK                      0x6ed4  #define EVERGREEN_MASTER_UPDATE_LOCK                    0x6ef4  #define EVERGREEN_MASTER_UPDATE_MODE                    0x6ef8 diff --git a/drivers/gpu/drm/radeon/evergreen_smc.h b/drivers/gpu/drm/radeon/evergreen_smc.h index 76ada8cfe90..3a03ba37d04 100644 --- a/drivers/gpu/drm/radeon/evergreen_smc.h +++ b/drivers/gpu/drm/radeon/evergreen_smc.h @@ -57,7 +57,7 @@ typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;  #define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100 -#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x0 +#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x8  #define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable      0xC  #define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 8768fd6a1e2..b066d6711b8 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -82,12 +82,16 @@  #define	CG_SPLL_FUNC_CNTL_2				0x604  #define		SCLK_MUX_SEL(x)				((x) << 0)  #define		SCLK_MUX_SEL_MASK			(0x1ff << 0) +#define		SCLK_MUX_UPDATE				(1 << 26)  #define	CG_SPLL_FUNC_CNTL_3				0x608  #define		SPLL_FB_DIV(x)				((x) << 0)  #define		SPLL_FB_DIV_MASK			(0x3ffffff << 0)  #define		SPLL_DITHEN				(1 << 28) +#define	CG_SPLL_STATUS					0x60c +#define		SPLL_CHG_STATUS				(1 << 1)  #define MPLL_CNTL_MODE                                  0x61c +#       define MPLL_MCLK_SEL                            (1 << 11)  #       define SS_SSEN                                  (1 << 24)  #       define SS_DSMODE_EN                             (1 << 25) @@ -513,10 +517,11 @@  #       define HDMI_ERROR_ACK                (1 << 8)  #       define HDMI_ERROR_MASK               (1 << 9)  #       define HDMI_DEEP_COLOR_ENABLE        (1 << 24) -#       define HDMI_DEEP_COLOR_DEPTH         (((x) & 3) << 28) +#       define HDMI_DEEP_COLOR_DEPTH(x)      (((x) & 3) << 28)  #       define HDMI_24BIT_DEEP_COLOR         0  #       define HDMI_30BIT_DEEP_COLOR         1  #       define HDMI_36BIT_DEEP_COLOR         2 +#       define HDMI_DEEP_COLOR_DEPTH_MASK    (3 << 28)  #define HDMI_STATUS                          0x7034  #       define HDMI_ACTIVE_AVMUTE            (1 << 0)  #       define HDMI_AUDIO_PACKET_ERROR       (1 << 16) @@ -750,6 +755,44 @@   * bit6 = 192 kHz   */ +#define AZ_CHANNEL_COUNT_CONTROL                          0x5fe4 +#       define HBR_CHANNEL_COUNT(x)                       (((x) & 0x7) << 0) +#       define COMPRESSED_CHANNEL_COUNT(x)                (((x) & 0x7) << 4) +/* HBR_CHANNEL_COUNT, COMPRESSED_CHANNEL_COUNT + * 0   = use stream header + * 1-7 = channel count - 1 + */ +#define AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC         0x5fe8 +#       define VIDEO_LIPSYNC(x)                           (((x) & 0xff) << 0) +#       define AUDIO_LIPSYNC(x)                           (((x) & 0xff) << 8) +/* VIDEO_LIPSYNC, AUDIO_LIPSYNC + * 0   = invalid + * x   = legal delay value + * 255 = sync not supported + */ +#define AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_HBR             0x5fec +#       define HBR_CAPABLE                                (1 << 0) /* enabled by default */ + +#define AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_AV_ASSOCIATION0 0x5ff4 +#       define DISPLAY0_TYPE(x)                           (((x) & 0x3) << 0) +#       define DISPLAY_TYPE_NONE                   0 +#       define DISPLAY_TYPE_HDMI                   1 +#       define DISPLAY_TYPE_DP                     2 +#       define DISPLAY0_ID(x)                             (((x) & 0x3f) << 2) +#       define DISPLAY1_TYPE(x)                           (((x) & 0x3) << 8) +#       define DISPLAY1_ID(x)                             (((x) & 0x3f) << 10) +#       define DISPLAY2_TYPE(x)                           (((x) & 0x3) << 16) +#       define DISPLAY2_ID(x)                             (((x) & 0x3f) << 18) +#       define DISPLAY3_TYPE(x)                           (((x) & 0x3) << 24) +#       define DISPLAY3_ID(x)                             (((x) & 0x3f) << 26) +#define AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_AV_ASSOCIATION1 0x5ff8 +#       define DISPLAY4_TYPE(x)                           (((x) & 0x3) << 0) +#       define DISPLAY4_ID(x)                             (((x) & 0x3f) << 2) +#       define DISPLAY5_TYPE(x)                           (((x) & 0x3) << 8) +#       define DISPLAY5_ID(x)                             (((x) & 0x3f) << 10) +#define AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_AV_NUMBER       0x5ffc +#       define NUMBER_OF_DISPLAY_ID(x)                    (((x) & 0x7) << 0) +  #define AZ_HOT_PLUG_CONTROL                               0x5e78  #       define AZ_FORCE_CODEC_WAKE                        (1 << 0)  #       define PIN0_JACK_DETECTION_ENABLE                 (1 << 4) @@ -1312,6 +1355,38 @@  #       define DC_HPDx_RX_INT_TIMER(x)                    ((x) << 16)  #       define DC_HPDx_EN                                 (1 << 28) +/* DCE4/5/6 FMT blocks */ +#define FMT_DYNAMIC_EXP_CNTL                 0x6fb4 +#       define FMT_DYNAMIC_EXP_EN            (1 << 0) +#       define FMT_DYNAMIC_EXP_MODE          (1 << 4) +        /* 0 = 10bit -> 12bit, 1 = 8bit -> 12bit */ +#define FMT_CONTROL                          0x6fb8 +#       define FMT_PIXEL_ENCODING            (1 << 16) +        /* 0 = RGB 4:4:4 or YCbCr 4:4:4, 1 = YCbCr 4:2:2 */ +#define FMT_BIT_DEPTH_CONTROL                0x6fc8 +#       define FMT_TRUNCATE_EN               (1 << 0) +#       define FMT_TRUNCATE_DEPTH            (1 << 4) +#       define FMT_SPATIAL_DITHER_EN         (1 << 8) +#       define FMT_SPATIAL_DITHER_MODE(x)    ((x) << 9) +#       define FMT_SPATIAL_DITHER_DEPTH      (1 << 12) +#       define FMT_FRAME_RANDOM_ENABLE       (1 << 13) +#       define FMT_RGB_RANDOM_ENABLE         (1 << 14) +#       define FMT_HIGHPASS_RANDOM_ENABLE    (1 << 15) +#       define FMT_TEMPORAL_DITHER_EN        (1 << 16) +#       define FMT_TEMPORAL_DITHER_DEPTH     (1 << 20) +#       define FMT_TEMPORAL_DITHER_OFFSET(x) ((x) << 21) +#       define FMT_TEMPORAL_LEVEL            (1 << 24) +#       define FMT_TEMPORAL_DITHER_RESET     (1 << 25) +#       define FMT_25FRC_SEL(x)              ((x) << 26) +#       define FMT_50FRC_SEL(x)              ((x) << 28) +#       define FMT_75FRC_SEL(x)              ((x) << 30) +#define FMT_CLAMP_CONTROL                    0x6fe4 +#       define FMT_CLAMP_DATA_EN             (1 << 0) +#       define FMT_CLAMP_COLOR_FORMAT(x)     ((x) << 16) +#       define FMT_CLAMP_6BPC                0 +#       define FMT_CLAMP_8BPC                1 +#       define FMT_CLAMP_10BPC               2 +  /* ASYNC DMA */  #define DMA_RB_RPTR                                       0xd008  #define DMA_RB_WPTR                                       0xd00c @@ -1501,7 +1576,7 @@   * 6. COMMAND [29:22] | BYTE_COUNT [20:0]   */  #              define PACKET3_CP_DMA_DST_SEL(x)    ((x) << 20) -                /* 0 - SRC_ADDR +                /* 0 - DST_ADDR  		 * 1 - GDS  		 */  #              define PACKET3_CP_DMA_ENGINE(x)     ((x) << 27) @@ -1516,7 +1591,7 @@  #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)  /* COMMAND */  #              define PACKET3_CP_DMA_DIS_WC        (1 << 21) -#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23) +#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)                  /* 0 - none  		 * 1 - 8 in 16  		 * 2 - 8 in 32 diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index 71399065db0..9ef8c38f2d6 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -546,6 +546,52 @@ static int kv_set_divider_value(struct radeon_device *rdev,  	return 0;  } +static u32 kv_convert_vid2_to_vid7(struct radeon_device *rdev, +				   struct sumo_vid_mapping_table *vid_mapping_table, +				   u32 vid_2bit) +{ +	struct radeon_clock_voltage_dependency_table *vddc_sclk_table = +		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; +	u32 i; + +	if (vddc_sclk_table && vddc_sclk_table->count) { +		if (vid_2bit < vddc_sclk_table->count) +			return vddc_sclk_table->entries[vid_2bit].v; +		else +			return vddc_sclk_table->entries[vddc_sclk_table->count - 1].v; +	} else { +		for (i = 0; i < vid_mapping_table->num_entries; i++) { +			if (vid_mapping_table->entries[i].vid_2bit == vid_2bit) +				return vid_mapping_table->entries[i].vid_7bit; +		} +		return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit; +	} +} + +static u32 kv_convert_vid7_to_vid2(struct radeon_device *rdev, +				   struct sumo_vid_mapping_table *vid_mapping_table, +				   u32 vid_7bit) +{ +	struct radeon_clock_voltage_dependency_table *vddc_sclk_table = +		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; +	u32 i; + +	if (vddc_sclk_table && vddc_sclk_table->count) { +		for (i = 0; i < vddc_sclk_table->count; i++) { +			if (vddc_sclk_table->entries[i].v == vid_7bit) +				return i; +		} +		return vddc_sclk_table->count - 1; +	} else { +		for (i = 0; i < vid_mapping_table->num_entries; i++) { +			if (vid_mapping_table->entries[i].vid_7bit == vid_7bit) +				return vid_mapping_table->entries[i].vid_2bit; +		} + +		return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit; +	} +} +  static u16 kv_convert_8bit_index_to_voltage(struct radeon_device *rdev,  					    u16 voltage)  { @@ -556,9 +602,9 @@ static u16 kv_convert_2bit_index_to_voltage(struct radeon_device *rdev,  					    u32 vid_2bit)  {  	struct kv_power_info *pi = kv_get_pi(rdev); -	u32 vid_8bit = sumo_convert_vid2_to_vid7(rdev, -						 &pi->sys_info.vid_mapping_table, -						 vid_2bit); +	u32 vid_8bit = kv_convert_vid2_to_vid7(rdev, +					       &pi->sys_info.vid_mapping_table, +					       vid_2bit);  	return kv_convert_8bit_index_to_voltage(rdev, (u16)vid_8bit);  } @@ -639,7 +685,7 @@ static int kv_force_lowest_valid(struct radeon_device *rdev)  static int kv_unforce_levels(struct radeon_device *rdev)  { -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return kv_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);  	else  		return kv_set_enabled_levels(rdev); @@ -1126,11 +1172,6 @@ int kv_dpm_enable(struct radeon_device *rdev)  	struct kv_power_info *pi = kv_get_pi(rdev);  	int ret; -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_HDP), false); -  	ret = kv_process_firmware_header(rdev);  	if (ret) {  		DRM_ERROR("kv_process_firmware_header failed\n"); @@ -1215,6 +1256,21 @@ int kv_dpm_enable(struct radeon_device *rdev)  	kv_reset_acp_boot_level(rdev); +	ret = kv_smc_bapm_enable(rdev, false); +	if (ret) { +		DRM_ERROR("kv_smc_bapm_enable failed\n"); +		return ret; +	} + +	kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); + +	return ret; +} + +int kv_dpm_late_enable(struct radeon_device *rdev) +{ +	int ret = 0; +  	if (rdev->irq.installed &&  	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {  		ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); @@ -1226,35 +1282,17 @@ int kv_dpm_enable(struct radeon_device *rdev)  		radeon_irq_set(rdev);  	} -	ret = kv_smc_bapm_enable(rdev, false); -	if (ret) { -		DRM_ERROR("kv_smc_bapm_enable failed\n"); -		return ret; -	} -  	/* powerdown unused blocks for now */  	kv_dpm_powergate_acp(rdev, true);  	kv_dpm_powergate_samu(rdev, true);  	kv_dpm_powergate_vce(rdev, true);  	kv_dpm_powergate_uvd(rdev, true); -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_HDP), true); - -	kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); -  	return ret;  }  void kv_dpm_disable(struct radeon_device *rdev)  { -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_HDP), false); -  	kv_smc_bapm_enable(rdev, false);  	/* powerup blocks */ @@ -1346,13 +1384,11 @@ static int kv_enable_uvd_dpm(struct radeon_device *rdev, bool enable)  					PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable);  } -#if 0  static int kv_enable_vce_dpm(struct radeon_device *rdev, bool enable)  {  	return kv_notify_message_to_smu(rdev, enable ?  					PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable);  } -#endif  static int kv_enable_samu_dpm(struct radeon_device *rdev, bool enable)  { @@ -1372,13 +1408,20 @@ static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate)  	struct radeon_uvd_clock_voltage_dependency_table *table =  		&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;  	int ret; +	u32 mask;  	if (!gate) { -		if (!pi->caps_uvd_dpm || table->count || pi->caps_stable_p_state) +		if (table->count)  			pi->uvd_boot_level = table->count - 1;  		else  			pi->uvd_boot_level = 0; +		if (!pi->caps_uvd_dpm || pi->caps_stable_p_state) { +			mask = 1 << pi->uvd_boot_level; +		} else { +			mask = 0x1f; +		} +  		ret = kv_copy_bytes_to_smc(rdev,  					   pi->dpm_table_start +  					   offsetof(SMU7_Fusion_DpmTable, UvdBootLevel), @@ -1387,17 +1430,14 @@ static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate)  		if (ret)  			return ret; -		if (!pi->caps_uvd_dpm || -		    pi->caps_stable_p_state) -			kv_send_msg_to_smc_with_parameter(rdev, -							  PPSMC_MSG_UVDDPM_SetEnabledMask, -							  (1 << pi->uvd_boot_level)); +		kv_send_msg_to_smc_with_parameter(rdev, +						  PPSMC_MSG_UVDDPM_SetEnabledMask, +						  mask);  	}  	return kv_enable_uvd_dpm(rdev, !gate);  } -#if 0  static u8 kv_get_vce_boot_level(struct radeon_device *rdev)  {  	u8 i; @@ -1422,6 +1462,9 @@ static int kv_update_vce_dpm(struct radeon_device *rdev,  	int ret;  	if (radeon_new_state->evclk > 0 && radeon_current_state->evclk == 0) { +		kv_dpm_powergate_vce(rdev, false); +		/* turn the clocks on when encoding */ +		cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false);  		if (pi->caps_stable_p_state)  			pi->vce_boot_level = table->count - 1;  		else @@ -1444,11 +1487,13 @@ static int kv_update_vce_dpm(struct radeon_device *rdev,  		kv_enable_vce_dpm(rdev, true);  	} else if (radeon_new_state->evclk == 0 && radeon_current_state->evclk > 0) {  		kv_enable_vce_dpm(rdev, false); +		/* turn the clocks off when not encoding */ +		cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true); +		kv_dpm_powergate_vce(rdev, true);  	}  	return 0;  } -#endif  static int kv_update_samu_dpm(struct radeon_device *rdev, bool gate)  { @@ -1583,11 +1628,16 @@ static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate)  	pi->vce_power_gated = gate;  	if (gate) { -		if (pi->caps_vce_pg) +		if (pi->caps_vce_pg) { +			/* XXX do we need a vce_v1_0_stop() ?  */  			kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerOFF); +		}  	} else { -		if (pi->caps_vce_pg) +		if (pi->caps_vce_pg) {  			kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerON); +			vce_v2_0_resume(rdev); +			vce_v1_0_start(rdev); +		}  	}  } @@ -1618,7 +1668,7 @@ static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate)  	if (pi->acp_power_gated == gate)  		return; -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return;  	pi->acp_power_gated = gate; @@ -1776,14 +1826,9 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)  {  	struct kv_power_info *pi = kv_get_pi(rdev);  	struct radeon_ps *new_ps = &pi->requested_rps; -	/*struct radeon_ps *old_ps = &pi->current_rps;*/ +	struct radeon_ps *old_ps = &pi->current_rps;  	int ret; -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_HDP), false); -  	if (pi->bapm_enable) {  		ret = kv_smc_bapm_enable(rdev, rdev->pm.dpm.ac_power);  		if (ret) { @@ -1792,7 +1837,7 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)  		}  	} -	if (rdev->family == CHIP_KABINI) { +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {  		if (pi->enable_dpm) {  			kv_set_valid_clock_range(rdev, new_ps);  			kv_update_dfs_bypass_settings(rdev, new_ps); @@ -1811,14 +1856,15 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)  			kv_set_enabled_levels(rdev);  			kv_force_lowest_valid(rdev);  			kv_unforce_levels(rdev); -#if 0 +  			ret = kv_update_vce_dpm(rdev, new_ps, old_ps);  			if (ret) {  				DRM_ERROR("kv_update_vce_dpm failed\n");  				return ret;  			} -#endif  			kv_update_sclk_t(rdev); +			if (rdev->family == CHIP_MULLINS) +				kv_enable_nb_dpm(rdev);  		}  	} else {  		if (pi->enable_dpm) { @@ -1836,24 +1882,17 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)  			kv_program_nbps_index_settings(rdev, new_ps);  			kv_freeze_sclk_dpm(rdev, false);  			kv_set_enabled_levels(rdev); -#if 0  			ret = kv_update_vce_dpm(rdev, new_ps, old_ps);  			if (ret) {  				DRM_ERROR("kv_update_vce_dpm failed\n");  				return ret;  			} -#endif  			kv_update_acp_boot_level(rdev);  			kv_update_sclk_t(rdev);  			kv_enable_nb_dpm(rdev);  		}  	} -	cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			     RADEON_CG_BLOCK_SDMA | -			     RADEON_CG_BLOCK_BIF | -			     RADEON_CG_BLOCK_HDP), true); -  	return 0;  } @@ -1876,7 +1915,7 @@ void kv_dpm_reset_asic(struct radeon_device *rdev)  {  	struct kv_power_info *pi = kv_get_pi(rdev); -	if (rdev->family == CHIP_KABINI) { +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {  		kv_force_lowest_valid(rdev);  		kv_init_graphics_levels(rdev);  		kv_program_bootup_state(rdev); @@ -1915,14 +1954,41 @@ static void kv_construct_max_power_limits_table(struct radeon_device *rdev,  static void kv_patch_voltage_values(struct radeon_device *rdev)  {  	int i; -	struct radeon_uvd_clock_voltage_dependency_table *table = +	struct radeon_uvd_clock_voltage_dependency_table *uvd_table =  		&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; +	struct radeon_vce_clock_voltage_dependency_table *vce_table = +		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; +	struct radeon_clock_voltage_dependency_table *samu_table = +		&rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; +	struct radeon_clock_voltage_dependency_table *acp_table = +		&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; + +	if (uvd_table->count) { +		for (i = 0; i < uvd_table->count; i++) +			uvd_table->entries[i].v = +				kv_convert_8bit_index_to_voltage(rdev, +								 uvd_table->entries[i].v); +	} -	if (table->count) { -		for (i = 0; i < table->count; i++) -			table->entries[i].v = +	if (vce_table->count) { +		for (i = 0; i < vce_table->count; i++) +			vce_table->entries[i].v =  				kv_convert_8bit_index_to_voltage(rdev, -								 table->entries[i].v); +								 vce_table->entries[i].v); +	} + +	if (samu_table->count) { +		for (i = 0; i < samu_table->count; i++) +			samu_table->entries[i].v = +				kv_convert_8bit_index_to_voltage(rdev, +								 samu_table->entries[i].v); +	} + +	if (acp_table->count) { +		for (i = 0; i < acp_table->count; i++) +			acp_table->entries[i].v = +				kv_convert_8bit_index_to_voltage(rdev, +								 acp_table->entries[i].v);  	}  } @@ -1955,7 +2021,7 @@ static int kv_force_dpm_highest(struct radeon_device *rdev)  			break;  	} -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);  	else  		return kv_set_enabled_level(rdev, i); @@ -1975,7 +2041,7 @@ static int kv_force_dpm_lowest(struct radeon_device *rdev)  			break;  	} -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);  	else  		return kv_set_enabled_level(rdev, i); @@ -2055,6 +2121,14 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,  	struct radeon_clock_and_voltage_limits *max_limits =  		&rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; +	if (new_rps->vce_active) { +		new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; +		new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk; +	} else { +		new_rps->evclk = 0; +		new_rps->ecclk = 0; +	} +  	mclk = max_limits->mclk;  	sclk = min_sclk; @@ -2074,6 +2148,11 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,  		sclk = stable_p_state_sclk;  	} +	if (new_rps->vce_active) { +		if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk) +			sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk; +	} +  	ps->need_dfs_bypass = true;  	for (i = 0; i < ps->num_levels; i++) { @@ -2110,7 +2189,8 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,  		}  	} -	pi->video_start = new_rps->dclk || new_rps->vclk; +	pi->video_start = new_rps->dclk || new_rps->vclk || +		new_rps->evclk || new_rps->ecclk;  	if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==  	    ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) @@ -2118,7 +2198,7 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,  	else  		pi->battery_state = false; -	if (rdev->family == CHIP_KABINI) { +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {  		ps->dpm0_pg_nb_ps_lo = 0x1;  		ps->dpm0_pg_nb_ps_hi = 0x0;  		ps->dpmx_nb_ps_lo = 0x1; @@ -2179,7 +2259,7 @@ static int kv_calculate_nbps_level_settings(struct radeon_device *rdev)  	if (pi->lowest_valid > pi->highest_valid)  		return -EINVAL; -	if (rdev->family == CHIP_KABINI) { +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {  		for (i = pi->lowest_valid; i <= pi->highest_valid; i++) {  			pi->graphics_level[i].GnbSlow = 1;  			pi->graphics_level[i].ForceNbPs1 = 0; @@ -2253,9 +2333,9 @@ static void kv_init_graphics_levels(struct radeon_device *rdev)  				break;  			kv_set_divider_value(rdev, i, table->entries[i].clk); -			vid_2bit = sumo_convert_vid7_to_vid2(rdev, -							     &pi->sys_info.vid_mapping_table, -							     table->entries[i].v); +			vid_2bit = kv_convert_vid7_to_vid2(rdev, +							   &pi->sys_info.vid_mapping_table, +							   table->entries[i].v);  			kv_set_vid(rdev, i, vid_2bit);  			kv_set_at(rdev, i, pi->at[i]);  			kv_dpm_power_level_enabled_for_throttle(rdev, i, true); @@ -2324,7 +2404,7 @@ static void kv_program_nbps_index_settings(struct radeon_device *rdev,  	struct kv_power_info *pi = kv_get_pi(rdev);  	u32 nbdpmconfig1; -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return;  	if (pi->sys_info.nb_dpm_enable) { @@ -2556,9 +2636,6 @@ static int kv_parse_power_table(struct radeon_device *rdev)  	if (!rdev->pm.dpm.ps)  		return -ENOMEM;  	power_state_offset = (u8 *)state_array->states; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < state_array->ucNumEntries; i++) {  		u8 *idx;  		power_state = (union pplib_power_state *)power_state_offset; @@ -2595,6 +2672,19 @@ static int kv_parse_power_table(struct radeon_device *rdev)  		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;  	}  	rdev->pm.dpm.num_ps = state_array->ucNumEntries; + +	/* fill in the vce power states */ +	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) { +		u32 sclk; +		clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx; +		clock_info = (union pplib_clock_info *) +			&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; +		sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); +		sclk |= clock_info->sumo.ucEngineClockHigh << 16; +		rdev->pm.dpm.vce_states[i].sclk = sclk; +		rdev->pm.dpm.vce_states[i].mclk = 0; +	} +  	return 0;  } @@ -2608,6 +2698,10 @@ int kv_dpm_init(struct radeon_device *rdev)  		return -ENOMEM;  	rdev->pm.dpm.priv = pi; +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = r600_parse_extended_power_table(rdev);  	if (ret)  		return ret; @@ -2617,9 +2711,6 @@ int kv_dpm_init(struct radeon_device *rdev)          pi->sram_end = SMC_RAM_END; -	if (rdev->family == CHIP_KABINI) -		pi->high_voltage_t = 4001; -  	pi->enable_nb_dpm = true;  	pi->caps_power_containment = true; @@ -2641,7 +2732,7 @@ int kv_dpm_init(struct radeon_device *rdev)  	pi->caps_fps = false; /* true? */  	pi->caps_uvd_pg = true;  	pi->caps_uvd_dpm = true; -	pi->caps_vce_pg = false; +	pi->caps_vce_pg = false; /* XXX true */  	pi->caps_samu_pg = false;  	pi->caps_acp_pg = false;  	pi->caps_stable_p_state = false; diff --git a/drivers/gpu/drm/radeon/mkregtable.c b/drivers/gpu/drm/radeon/mkregtable.c index af85299f212..4a85bb644e2 100644 --- a/drivers/gpu/drm/radeon/mkregtable.c +++ b/drivers/gpu/drm/radeon/mkregtable.c @@ -655,7 +655,7 @@ static int parser_auth(struct table *t, const char *filename)  	/* first line will contain the last register  	 * and gpu name */ -	sscanf(buf, "%s %s", gpu_name, last_reg_s); +	sscanf(buf, "%9s %9s", gpu_name, last_reg_s);  	t->gpu_prefix = gpu_name;  	last_reg = strtol(last_reg_s, NULL, 16); diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 93c1f9ef5da..5a33ca68186 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -174,11 +174,7 @@ extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev);  extern void evergreen_program_aspm(struct radeon_device *rdev);  extern void sumo_rlc_fini(struct radeon_device *rdev);  extern int sumo_rlc_init(struct radeon_device *rdev); -extern void cayman_dma_vm_set_page(struct radeon_device *rdev, -				   struct radeon_ib *ib, -				   uint64_t pe, -				   uint64_t addr, unsigned count, -				   uint32_t incr, uint32_t flags); +extern void evergreen_gpu_pci_config_reset(struct radeon_device *rdev);  /* Firmware Names */  MODULE_FIRMWARE("radeon/BARTS_pfp.bin"); @@ -804,6 +800,7 @@ int ni_init_microcode(struct radeon_device *rdev)  			       fw_name);  			release_firmware(rdev->smc_fw);  			rdev->smc_fw = NULL; +			err = 0;  		} else if (rdev->smc_fw->size != smc_req_size) {  			printk(KERN_ERR  			       "ni_mc: Bogus length %zu in firmware \"%s\"\n", @@ -899,6 +896,10 @@ static void cayman_gpu_init(struct radeon_device *rdev)  		    (rdev->pdev->device == 0x999C)) {  			rdev->config.cayman.max_simds_per_se = 6;  			rdev->config.cayman.max_backends_per_se = 2; +			rdev->config.cayman.max_hw_contexts = 8; +			rdev->config.cayman.sx_max_export_size = 256; +			rdev->config.cayman.sx_max_export_pos_size = 64; +			rdev->config.cayman.sx_max_export_smx_size = 192;  		} else if ((rdev->pdev->device == 0x9903) ||  			   (rdev->pdev->device == 0x9904) ||  			   (rdev->pdev->device == 0x990A) || @@ -909,6 +910,10 @@ static void cayman_gpu_init(struct radeon_device *rdev)  			   (rdev->pdev->device == 0x999D)) {  			rdev->config.cayman.max_simds_per_se = 4;  			rdev->config.cayman.max_backends_per_se = 2; +			rdev->config.cayman.max_hw_contexts = 8; +			rdev->config.cayman.sx_max_export_size = 256; +			rdev->config.cayman.sx_max_export_pos_size = 64; +			rdev->config.cayman.sx_max_export_smx_size = 192;  		} else if ((rdev->pdev->device == 0x9919) ||  			   (rdev->pdev->device == 0x9990) ||  			   (rdev->pdev->device == 0x9991) || @@ -919,9 +924,17 @@ static void cayman_gpu_init(struct radeon_device *rdev)  			   (rdev->pdev->device == 0x99A0)) {  			rdev->config.cayman.max_simds_per_se = 3;  			rdev->config.cayman.max_backends_per_se = 1; +			rdev->config.cayman.max_hw_contexts = 4; +			rdev->config.cayman.sx_max_export_size = 128; +			rdev->config.cayman.sx_max_export_pos_size = 32; +			rdev->config.cayman.sx_max_export_smx_size = 96;  		} else {  			rdev->config.cayman.max_simds_per_se = 2;  			rdev->config.cayman.max_backends_per_se = 1; +			rdev->config.cayman.max_hw_contexts = 4; +			rdev->config.cayman.sx_max_export_size = 128; +			rdev->config.cayman.sx_max_export_pos_size = 32; +			rdev->config.cayman.sx_max_export_smx_size = 96;  		}  		rdev->config.cayman.max_texture_channel_caches = 2;  		rdev->config.cayman.max_gprs = 256; @@ -929,10 +942,6 @@ static void cayman_gpu_init(struct radeon_device *rdev)  		rdev->config.cayman.max_gs_threads = 32;  		rdev->config.cayman.max_stack_entries = 512;  		rdev->config.cayman.sx_num_of_sets = 8; -		rdev->config.cayman.sx_max_export_size = 256; -		rdev->config.cayman.sx_max_export_pos_size = 64; -		rdev->config.cayman.sx_max_export_smx_size = 192; -		rdev->config.cayman.max_hw_contexts = 8;  		rdev->config.cayman.sq_num_cf_insts = 2;  		rdev->config.cayman.sc_prim_fifo_size = 0x40; @@ -1048,6 +1057,18 @@ static void cayman_gpu_init(struct radeon_device *rdev)  			disabled_rb_mask &= ~(1 << i);  	} +	for (i = 0; i < rdev->config.cayman.max_shader_engines; i++) { +		u32 simd_disable_bitmap; + +		WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); +		WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); +		simd_disable_bitmap = (RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffff0000) >> 16; +		simd_disable_bitmap |= 0xffffffff << rdev->config.cayman.max_simds_per_se; +		tmp <<= 16; +		tmp |= simd_disable_bitmap; +	} +	rdev->config.cayman.active_simds = hweight32(~tmp); +  	WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES);  	WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); @@ -1219,12 +1240,14 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev)  	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);  	/* Setup L2 cache */  	WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | +	       ENABLE_L2_FRAGMENT_PROCESSING |  	       ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |  	       ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |  	       EFFECTIVE_L2_QUEUE_SIZE(7) |  	       CONTEXT1_IDENTITY_ACCESS_MODE(1));  	WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);  	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY | +	       BANK_SELECT(6) |  	       L2_CACHE_BIGK_FRAGMENT_SIZE(6));  	/* setup context0 */  	WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); @@ -1257,6 +1280,7 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev)  	       (u32)(rdev->dummy_page.addr >> 12));  	WREG32(VM_CONTEXT1_CNTL2, 4);  	WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) | +				PAGE_TABLE_BLOCK_SIZE(radeon_vm_block_size - 9) |  				RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |  				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |  				DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT | @@ -1322,20 +1346,19 @@ void cayman_fence_ring_emit(struct radeon_device *rdev,  {  	struct radeon_ring *ring = &rdev->ring[fence->ring];  	u64 addr = rdev->fence_drv[fence->ring].gpu_addr; +	u32 cp_coher_cntl = PACKET3_FULL_CACHE_ENA | PACKET3_TC_ACTION_ENA | +		PACKET3_SH_ACTION_ENA;  	/* flush read cache over gart for this vmid */ -	radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); -	radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2); -	radeon_ring_write(ring, 0);  	radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); -	radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | PACKET3_SH_ACTION_ENA); +	radeon_ring_write(ring, PACKET3_ENGINE_ME | cp_coher_cntl);  	radeon_ring_write(ring, 0xFFFFFFFF);  	radeon_ring_write(ring, 0);  	radeon_ring_write(ring, 10); /* poll interval */  	/* EVENT_WRITE_EOP - flush caches, send int */  	radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));  	radeon_ring_write(ring, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT_TS) | EVENT_INDEX(5)); -	radeon_ring_write(ring, addr & 0xffffffff); +	radeon_ring_write(ring, lower_32_bits(addr));  	radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | DATA_SEL(1) | INT_SEL(2));  	radeon_ring_write(ring, fence->seq);  	radeon_ring_write(ring, 0); @@ -1344,6 +1367,8 @@ void cayman_fence_ring_emit(struct radeon_device *rdev,  void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)  {  	struct radeon_ring *ring = &rdev->ring[ib->ring]; +	u32 cp_coher_cntl = PACKET3_FULL_CACHE_ENA | PACKET3_TC_ACTION_ENA | +		PACKET3_SH_ACTION_ENA;  	/* set to DX10/11 mode */  	radeon_ring_write(ring, PACKET3(PACKET3_MODE_CONTROL, 0)); @@ -1368,14 +1393,11 @@ void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)  			  (ib->vm ? (ib->vm->id << 24) : 0));  	/* flush read cache over gart for this vmid */ -	radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); -	radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2); -	radeon_ring_write(ring, ib->vm ? ib->vm->id : 0);  	radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); -	radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | PACKET3_SH_ACTION_ENA); +	radeon_ring_write(ring, PACKET3_ENGINE_ME | cp_coher_cntl);  	radeon_ring_write(ring, 0xFFFFFFFF);  	radeon_ring_write(ring, 0); -	radeon_ring_write(ring, 10); /* poll interval */ +	radeon_ring_write(ring, ((ib->vm ? ib->vm->id : 0) << 24) | 10); /* poll interval */  }  static void cayman_cp_enable(struct radeon_device *rdev, bool enable) @@ -1383,13 +1405,63 @@ static void cayman_cp_enable(struct radeon_device *rdev, bool enable)  	if (enable)  		WREG32(CP_ME_CNTL, 0);  	else { -		radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); +		if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +			radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);  		WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));  		WREG32(SCRATCH_UMSK, 0);  		rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;  	}  } +u32 cayman_gfx_get_rptr(struct radeon_device *rdev, +			struct radeon_ring *ring) +{ +	u32 rptr; + +	if (rdev->wb.enabled) +		rptr = rdev->wb.wb[ring->rptr_offs/4]; +	else { +		if (ring->idx == RADEON_RING_TYPE_GFX_INDEX) +			rptr = RREG32(CP_RB0_RPTR); +		else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX) +			rptr = RREG32(CP_RB1_RPTR); +		else +			rptr = RREG32(CP_RB2_RPTR); +	} + +	return rptr; +} + +u32 cayman_gfx_get_wptr(struct radeon_device *rdev, +			struct radeon_ring *ring) +{ +	u32 wptr; + +	if (ring->idx == RADEON_RING_TYPE_GFX_INDEX) +		wptr = RREG32(CP_RB0_WPTR); +	else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX) +		wptr = RREG32(CP_RB1_WPTR); +	else +		wptr = RREG32(CP_RB2_WPTR); + +	return wptr; +} + +void cayman_gfx_set_wptr(struct radeon_device *rdev, +			 struct radeon_ring *ring) +{ +	if (ring->idx == RADEON_RING_TYPE_GFX_INDEX) { +		WREG32(CP_RB0_WPTR, ring->wptr); +		(void)RREG32(CP_RB0_WPTR); +	} else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX) { +		WREG32(CP_RB1_WPTR, ring->wptr); +		(void)RREG32(CP_RB1_WPTR); +	} else { +		WREG32(CP_RB2_WPTR, ring->wptr); +		(void)RREG32(CP_RB2_WPTR); +	} +} +  static int cayman_cp_load_microcode(struct radeon_device *rdev)  {  	const __be32 *fw_data; @@ -1518,6 +1590,16 @@ static int cayman_cp_resume(struct radeon_device *rdev)  		CP_RB1_BASE,  		CP_RB2_BASE  	}; +	static const unsigned cp_rb_rptr[] = { +		CP_RB0_RPTR, +		CP_RB1_RPTR, +		CP_RB2_RPTR +	}; +	static const unsigned cp_rb_wptr[] = { +		CP_RB0_WPTR, +		CP_RB1_WPTR, +		CP_RB2_WPTR +	};  	struct radeon_ring *ring;  	int i, r; @@ -1575,9 +1657,9 @@ static int cayman_cp_resume(struct radeon_device *rdev)  		ring = &rdev->ring[ridx[i]];  		WREG32_P(cp_rb_cntl[i], RB_RPTR_WR_ENA, ~RB_RPTR_WR_ENA); -		ring->rptr = ring->wptr = 0; -		WREG32(ring->rptr_reg, ring->rptr); -		WREG32(ring->wptr_reg, ring->wptr); +		ring->wptr = 0; +		WREG32(cp_rb_rptr[i], 0); +		WREG32(cp_rb_wptr[i], ring->wptr);  		mdelay(1);  		WREG32_P(cp_rb_cntl[i], 0, ~RB_RPTR_WR_ENA); @@ -1597,6 +1679,9 @@ static int cayman_cp_resume(struct radeon_device *rdev)  		return r;  	} +	if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); +  	return 0;  } @@ -1823,8 +1908,10 @@ int cayman_asic_reset(struct radeon_device *rdev)  	reset_mask = cayman_gpu_check_soft_reset(rdev); -	if (!reset_mask) -		r600_set_bios_scratch_engine_hung(rdev, false); +	if (reset_mask) +		evergreen_gpu_pci_config_reset(rdev); + +	r600_set_bios_scratch_engine_hung(rdev, false);  	return 0;  } @@ -1845,11 +1932,9 @@ bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	if (!(reset_mask & (RADEON_RESET_GFX |  			    RADEON_RESET_COMPUTE |  			    RADEON_RESET_CP))) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force CP activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -1870,23 +1955,7 @@ static int cayman_startup(struct radeon_device *rdev)  	evergreen_mc_program(rdev); -	if (rdev->flags & RADEON_IS_IGP) { -		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { -			r = ni_init_microcode(rdev); -			if (r) { -				DRM_ERROR("Failed to load firmware!\n"); -				return r; -			} -		} -	} else { -		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { -			r = ni_init_microcode(rdev); -			if (r) { -				DRM_ERROR("Failed to load firmware!\n"); -				return r; -			} -		} - +	if (!(rdev->flags & RADEON_IS_IGP) && !rdev->pm.dpm_enabled) {  		r = ni_mc_load_microcode(rdev);  		if (r) {  			DRM_ERROR("Failed to load MC firmware!\n"); @@ -1973,23 +2042,18 @@ static int cayman_startup(struct radeon_device *rdev)  	evergreen_irq_set(rdev);  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, -			     CP_RB0_RPTR, CP_RB0_WPTR,  			     RADEON_CP_PACKET2);  	if (r)  		return r;  	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, -			     DMA_RB_RPTR + DMA0_REGISTER_OFFSET, -			     DMA_RB_WPTR + DMA0_REGISTER_OFFSET,  			     DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));  	if (r)  		return r;  	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET, -			     DMA_RB_RPTR + DMA1_REGISTER_OFFSET, -			     DMA_RB_WPTR + DMA1_REGISTER_OFFSET,  			     DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));  	if (r)  		return r; @@ -2008,7 +2072,6 @@ static int cayman_startup(struct radeon_device *rdev)  	ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];  	if (ring->ring_size) {  		r = radeon_ring_init(rdev, ring, ring->ring_size, 0, -				     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,  				     RADEON_CP_PACKET2);  		if (!r)  			r = uvd_v1_0_init(rdev); @@ -2055,6 +2118,9 @@ int cayman_resume(struct radeon_device *rdev)  	/* init golden registers */  	ni_init_golden_registers(rdev); +	if (rdev->pm.pm_method == PM_METHOD_DPM) +		radeon_pm_resume(rdev); +  	rdev->accel_working = true;  	r = cayman_startup(rdev);  	if (r) { @@ -2067,6 +2133,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 @@ -2137,6 +2204,27 @@ int cayman_init(struct radeon_device *rdev)  	if (r)  		return r; +	if (rdev->flags & RADEON_IS_IGP) { +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { +			r = ni_init_microcode(rdev); +			if (r) { +				DRM_ERROR("Failed to load firmware!\n"); +				return r; +			} +		} +	} else { +		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { +			r = ni_init_microcode(rdev); +			if (r) { +				DRM_ERROR("Failed to load firmware!\n"); +				return r; +			} +		} +	} + +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	ring->ring_obj = NULL;  	r600_ring_init(rdev, ring, 1024 * 1024); @@ -2196,6 +2284,7 @@ int cayman_init(struct radeon_device *rdev)  void cayman_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	cayman_cp_fini(rdev);  	cayman_dma_fini(rdev);  	r600_irq_fini(rdev); @@ -2399,77 +2488,6 @@ void cayman_vm_decode_fault(struct radeon_device *rdev,  	       block, mc_id);  } -#define R600_ENTRY_VALID   (1 << 0) -#define R600_PTE_SYSTEM    (1 << 1) -#define R600_PTE_SNOOPED   (1 << 2) -#define R600_PTE_READABLE  (1 << 5) -#define R600_PTE_WRITEABLE (1 << 6) - -uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags) -{ -	uint32_t r600_flags = 0; -	r600_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_ENTRY_VALID : 0; -	r600_flags |= (flags & RADEON_VM_PAGE_READABLE) ? R600_PTE_READABLE : 0; -	r600_flags |= (flags & RADEON_VM_PAGE_WRITEABLE) ? R600_PTE_WRITEABLE : 0; -	if (flags & RADEON_VM_PAGE_SYSTEM) { -		r600_flags |= R600_PTE_SYSTEM; -		r600_flags |= (flags & RADEON_VM_PAGE_SNOOPED) ? R600_PTE_SNOOPED : 0; -	} -	return r600_flags; -} - -/** - * cayman_vm_set_page - update the page tables using the CP - * - * @rdev: radeon_device pointer - * @ib: indirect buffer to fill with commands - * @pe: addr of the page entry - * @addr: dst addr to write into pe - * @count: number of page entries to update - * @incr: increase next addr by incr bytes - * @flags: access flags - * - * Update the page tables using the CP (cayman/TN). - */ -void cayman_vm_set_page(struct radeon_device *rdev, -			struct radeon_ib *ib, -			uint64_t pe, -			uint64_t addr, unsigned count, -			uint32_t incr, uint32_t flags) -{ -	uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); -	uint64_t value; -	unsigned ndw; - -	if (rdev->asic->vm.pt_ring_index == RADEON_RING_TYPE_GFX_INDEX) { -		while (count) { -			ndw = 1 + count * 2; -			if (ndw > 0x3FFF) -				ndw = 0x3FFF; - -			ib->ptr[ib->length_dw++] = PACKET3(PACKET3_ME_WRITE, ndw); -			ib->ptr[ib->length_dw++] = pe; -			ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; -			for (; ndw > 1; ndw -= 2, --count, pe += 8) { -				if (flags & RADEON_VM_PAGE_SYSTEM) { -					value = radeon_vm_map_gart(rdev, addr); -					value &= 0xFFFFFFFFFFFFF000ULL; -				} else if (flags & RADEON_VM_PAGE_VALID) { -					value = addr; -				} else { -					value = 0; -				} -				addr += incr; -				value |= r600_flags; -				ib->ptr[ib->length_dw++] = value; -				ib->ptr[ib->length_dw++] = upper_32_bits(value); -			} -		} -	} else { -		cayman_dma_vm_set_page(rdev, ib, pe, addr, count, incr, flags); -	} -} -  /**   * cayman_vm_flush - vm flush using the CP   * diff --git a/drivers/gpu/drm/radeon/ni_dma.c b/drivers/gpu/drm/radeon/ni_dma.c index dd6e9688fbe..6378e027669 100644 --- a/drivers/gpu/drm/radeon/ni_dma.c +++ b/drivers/gpu/drm/radeon/ni_dma.c @@ -24,6 +24,7 @@  #include <drm/drmP.h>  #include "radeon.h"  #include "radeon_asic.h" +#include "radeon_trace.h"  #include "nid.h"  u32 cayman_gpu_check_soft_reset(struct radeon_device *rdev); @@ -42,6 +43,75 @@ u32 cayman_gpu_check_soft_reset(struct radeon_device *rdev);   */  /** + * cayman_dma_get_rptr - get the current read pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Get the current rptr from the hardware (cayman+). + */ +uint32_t cayman_dma_get_rptr(struct radeon_device *rdev, +			     struct radeon_ring *ring) +{ +	u32 rptr, reg; + +	if (rdev->wb.enabled) { +		rptr = rdev->wb.wb[ring->rptr_offs/4]; +	} else { +		if (ring->idx == R600_RING_TYPE_DMA_INDEX) +			reg = DMA_RB_RPTR + DMA0_REGISTER_OFFSET; +		else +			reg = DMA_RB_RPTR + DMA1_REGISTER_OFFSET; + +		rptr = RREG32(reg); +	} + +	return (rptr & 0x3fffc) >> 2; +} + +/** + * cayman_dma_get_wptr - get the current write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Get the current wptr from the hardware (cayman+). + */ +uint32_t cayman_dma_get_wptr(struct radeon_device *rdev, +			   struct radeon_ring *ring) +{ +	u32 reg; + +	if (ring->idx == R600_RING_TYPE_DMA_INDEX) +		reg = DMA_RB_WPTR + DMA0_REGISTER_OFFSET; +	else +		reg = DMA_RB_WPTR + DMA1_REGISTER_OFFSET; + +	return (RREG32(reg) & 0x3fffc) >> 2; +} + +/** + * cayman_dma_set_wptr - commit the write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Write the wptr back to the hardware (cayman+). + */ +void cayman_dma_set_wptr(struct radeon_device *rdev, +			 struct radeon_ring *ring) +{ +	u32 reg; + +	if (ring->idx == R600_RING_TYPE_DMA_INDEX) +		reg = DMA_RB_WPTR + DMA0_REGISTER_OFFSET; +	else +		reg = DMA_RB_WPTR + DMA1_REGISTER_OFFSET; + +	WREG32(reg, (ring->wptr << 2) & 0x3fffc); +} + +/**   * cayman_dma_ring_ib_execute - Schedule an IB on the DMA engine   *   * @rdev: radeon_device pointer @@ -87,7 +157,9 @@ void cayman_dma_stop(struct radeon_device *rdev)  {  	u32 rb_cntl; -	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); +	if ((rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) || +	    (rdev->asic->copy.copy_ring_index == CAYMAN_RING_TYPE_DMA1_INDEX)) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);  	/* dma0 */  	rb_cntl = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET); @@ -176,8 +248,6 @@ int cayman_dma_resume(struct radeon_device *rdev)  		ring->wptr = 0;  		WREG32(DMA_RB_WPTR + reg_offset, ring->wptr << 2); -		ring->rptr = RREG32(DMA_RB_RPTR + reg_offset) >> 2; -  		WREG32(DMA_RB_CNTL + reg_offset, rb_cntl | DMA_RB_ENABLE);  		ring->ready = true; @@ -189,7 +259,9 @@ int cayman_dma_resume(struct radeon_device *rdev)  		}  	} -	radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); +	if ((rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) || +	    (rdev->asic->copy.copy_ring_index == CAYMAN_RING_TYPE_DMA1_INDEX)) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);  	return 0;  } @@ -228,11 +300,9 @@ bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  		mask = RADEON_RESET_DMA1;  	if (!(reset_mask & mask)) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force ring activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -245,8 +315,7 @@ bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)   * @addr: dst addr to write into pe   * @count: number of page entries to update   * @incr: increase next addr by incr bytes - * @flags: access flags - * @r600_flags: hw access flags  + * @flags: hw access flags    *   * Update the page tables using the DMA (cayman/TN).   */ @@ -256,11 +325,12 @@ void cayman_dma_vm_set_page(struct radeon_device *rdev,  			    uint64_t addr, unsigned count,  			    uint32_t incr, uint32_t flags)  { -	uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);  	uint64_t value;  	unsigned ndw; -	if ((flags & RADEON_VM_PAGE_SYSTEM) || (count == 1)) { +	trace_radeon_vm_set_page(pe, addr, count, incr, flags); + +	if ((flags & R600_PTE_SYSTEM) || (count == 1)) {  		while (count) {  			ndw = count * 2;  			if (ndw > 0xFFFFE) @@ -271,16 +341,16 @@ void cayman_dma_vm_set_page(struct radeon_device *rdev,  			ib->ptr[ib->length_dw++] = pe;  			ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff;  			for (; ndw > 0; ndw -= 2, --count, pe += 8) { -				if (flags & RADEON_VM_PAGE_SYSTEM) { +				if (flags & R600_PTE_SYSTEM) {  					value = radeon_vm_map_gart(rdev, addr);  					value &= 0xFFFFFFFFFFFFF000ULL; -				} else if (flags & RADEON_VM_PAGE_VALID) { +				} else if (flags & R600_PTE_VALID) {  					value = addr;  				} else {  					value = 0;  				}  				addr += incr; -				value |= r600_flags; +				value |= flags;  				ib->ptr[ib->length_dw++] = value;  				ib->ptr[ib->length_dw++] = upper_32_bits(value);  			} @@ -291,7 +361,7 @@ void cayman_dma_vm_set_page(struct radeon_device *rdev,  			if (ndw > 0xFFFFE)  				ndw = 0xFFFFE; -			if (flags & RADEON_VM_PAGE_VALID) +			if (flags & R600_PTE_VALID)  				value = addr;  			else  				value = 0; @@ -299,7 +369,7 @@ void cayman_dma_vm_set_page(struct radeon_device *rdev,  			ib->ptr[ib->length_dw++] = DMA_PTE_PDE_PACKET(ndw);  			ib->ptr[ib->length_dw++] = pe; /* dst addr */  			ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; -			ib->ptr[ib->length_dw++] = r600_flags; /* mask */ +			ib->ptr[ib->length_dw++] = flags; /* mask */  			ib->ptr[ib->length_dw++] = 0;  			ib->ptr[ib->length_dw++] = value; /* value */  			ib->ptr[ib->length_dw++] = upper_32_bits(value); diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index f2633902815..01fc4888e6f 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -720,6 +720,8 @@ static const u32 cayman_sysls_enable[] =  struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);  struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev); +extern int ni_mc_load_microcode(struct radeon_device *rdev); +  struct ni_power_info *ni_get_pi(struct radeon_device *rdev)  {          struct ni_power_info *pi = rdev->pm.dpm.priv; @@ -785,8 +787,8 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,  	struct ni_ps *ps = ni_get_ps(rps);  	struct radeon_clock_and_voltage_limits *max_limits;  	bool disable_mclk_switching; -	u32 mclk, sclk; -	u16 vddc, vddci; +	u32 mclk; +	u16 vddci;  	u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;  	int i; @@ -839,24 +841,14 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,  	/* XXX validate the min clocks required for display */ +	/* adjust low state */  	if (disable_mclk_switching) { -		mclk  = ps->performance_levels[ps->performance_level_count - 1].mclk; -		sclk = ps->performance_levels[0].sclk; -		vddc = ps->performance_levels[0].vddc; -		vddci = ps->performance_levels[ps->performance_level_count - 1].vddci; -	} else { -		sclk = ps->performance_levels[0].sclk; -		mclk = ps->performance_levels[0].mclk; -		vddc = ps->performance_levels[0].vddc; -		vddci = ps->performance_levels[0].vddci; +		ps->performance_levels[0].mclk = +			ps->performance_levels[ps->performance_level_count - 1].mclk; +		ps->performance_levels[0].vddci = +			ps->performance_levels[ps->performance_level_count - 1].vddci;  	} -	/* adjusted low state */ -	ps->performance_levels[0].sclk = sclk; -	ps->performance_levels[0].mclk = mclk; -	ps->performance_levels[0].vddc = vddc; -	ps->performance_levels[0].vddci = vddci; -  	btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,  				  &ps->performance_levels[0].sclk,  				  &ps->performance_levels[0].mclk); @@ -868,11 +860,15 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,  			ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;  	} +	/* adjust remaining states */  	if (disable_mclk_switching) {  		mclk = ps->performance_levels[0].mclk; +		vddci = ps->performance_levels[0].vddci;  		for (i = 1; i < ps->performance_level_count; i++) {  			if (mclk < ps->performance_levels[i].mclk)  				mclk = ps->performance_levels[i].mclk; +			if (vddci < ps->performance_levels[i].vddci) +				vddci = ps->performance_levels[i].vddci;  		}  		for (i = 0; i < ps->performance_level_count; i++) {  			ps->performance_levels[i].mclk = mclk; @@ -1319,7 +1315,7 @@ static void ni_populate_smc_voltage_tables(struct radeon_device *rdev,  		table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] = 0;  		table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] = -			cpu_to_be32(eg_pi->vddc_voltage_table.mask_low); +			cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);  	}  } @@ -2592,7 +2588,7 @@ static int ni_populate_sq_ramping_values(struct radeon_device *rdev,  	if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))  		enable_sq_ramping = false; -	if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) +	if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))  		enable_sq_ramping = false;  	for (i = 0; i < state->performance_level_count; i++) { @@ -3445,9 +3441,9 @@ static int ni_enable_smc_cac(struct radeon_device *rdev,  static int ni_pcie_performance_request(struct radeon_device *rdev,  				       u8 perf_req, bool advertise)  { +#if defined(CONFIG_ACPI)  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); -#if defined(CONFIG_ACPI)  	if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) ||              (perf_req == PCIE_PERF_REQ_PECI_GEN2)) {  		if (eg_pi->pcie_performance_request_registered == false) @@ -3571,7 +3567,11 @@ void ni_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,  void ni_dpm_setup_asic(struct radeon_device *rdev)  {  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); +	int r; +	r = ni_mc_load_microcode(rdev); +	if (r) +		DRM_ERROR("Failed to load MC firmware!\n");  	ni_read_clock_registers(rdev);  	btc_read_arb_registers(rdev);  	rv770_get_memory_type(rdev); @@ -3716,21 +3716,6 @@ int ni_dpm_enable(struct radeon_device *rdev)  	if (eg_pi->ls_clock_gating)  		ni_ls_clockgating_enable(rdev, true); -	if (rdev->irq.installed && -	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { -		PPSMC_Result result; - -		ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, 0xff * 1000); -		if (ret) -			return ret; -		rdev->irq.dpm_thermal = true; -		radeon_irq_set(rdev); -		result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); - -		if (result != PPSMC_Result_OK) -			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); -	} -  	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);  	ni_update_current_ps(rdev, boot_ps); @@ -3960,7 +3945,6 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev,  	struct rv7xx_power_info *pi = rv770_get_pi(rdev);  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);  	struct ni_ps *ps = ni_get_ps(rps); -	u16 vddc;  	struct rv7xx_pl *pl = &ps->performance_levels[index];  	ps->performance_level_count = index + 1; @@ -3976,8 +3960,8 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev,  	/* patch up vddc if necessary */  	if (pl->vddc == 0xff01) { -		if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) -			pl->vddc = vddc; +		if (pi->max_vddc) +			pl->vddc = pi->max_vddc;  	}  	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { @@ -4041,9 +4025,6 @@ static int ni_parse_power_table(struct radeon_device *rdev)  				  power_info->pplib.ucNumStates, GFP_KERNEL);  	if (!rdev->pm.dpm.ps)  		return -ENOMEM; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < power_info->pplib.ucNumStates; i++) {  		power_state = (union pplib_power_state *) @@ -4105,6 +4086,10 @@ int ni_dpm_init(struct radeon_device *rdev)  	pi->min_vddc_in_table = 0;  	pi->max_vddc_in_table = 0; +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = ni_parse_power_table(rdev);  	if (ret)  		return ret; @@ -4337,7 +4322,8 @@ void ni_dpm_print_power_state(struct radeon_device *rdev,  void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,  						    struct seq_file *m)  { -	struct radeon_ps *rps = rdev->pm.dpm.current_ps; +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); +	struct radeon_ps *rps = &eg_pi->current_rps;  	struct ni_ps *ps = ni_get_ps(rps);  	struct rv7xx_pl *pl;  	u32 current_index = diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 22421bc80c0..2e12e4d6925 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -128,6 +128,7 @@  #define		READ_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 16)  #define		WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 18)  #define		WRITE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 19) +#define		PAGE_TABLE_BLOCK_SIZE(x)			(((x) & 0xF) << 24)  #define VM_CONTEXT1_CNTL				0x1414  #define VM_CONTEXT0_CNTL2				0x1430  #define VM_CONTEXT1_CNTL2				0x1434 @@ -1154,6 +1155,7 @@  #              define PACKET3_DB_ACTION_ENA        (1 << 26)  #              define PACKET3_SH_ACTION_ENA        (1 << 27)  #              define PACKET3_SX_ACTION_ENA        (1 << 28) +#              define PACKET3_ENGINE_ME            (1 << 31)  #define	PACKET3_ME_INITIALIZE				0x44  #define		PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)  #define	PACKET3_COND_WRITE				0x45 diff --git a/drivers/gpu/drm/radeon/pptable.h b/drivers/gpu/drm/radeon/pptable.h index da43ab32883..2d532996c69 100644 --- a/drivers/gpu/drm/radeon/pptable.h +++ b/drivers/gpu/drm/radeon/pptable.h @@ -23,7 +23,7 @@  #ifndef _PPTABLE_H  #define _PPTABLE_H -#pragma pack(push, 1) +#pragma pack(1)  typedef struct _ATOM_PPLIB_THERMALCONTROLLER @@ -677,6 +677,6 @@ typedef struct _ATOM_PPLIB_PPM_Table        ULONG  ulTjmax;  } ATOM_PPLIB_PPM_Table; -#pragma pack(pop) +#pragma pack()  #endif diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index d71333033b2..1544efcf1c3 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -142,36 +142,6 @@ void r100_wait_for_vblank(struct radeon_device *rdev, int crtc)  }  /** - * r100_pre_page_flip - pre-pageflip callback. - * - * @rdev: radeon_device pointer - * @crtc: crtc to prepare for pageflip on - * - * Pre-pageflip callback (r1xx-r4xx). - * Enables the pageflip irq (vblank irq). - */ -void r100_pre_page_flip(struct radeon_device *rdev, int crtc) -{ -	/* enable the pflip int */ -	radeon_irq_kms_pflip_irq_get(rdev, crtc); -} - -/** - * r100_post_page_flip - pos-pageflip callback. - * - * @rdev: radeon_device pointer - * @crtc: crtc to cleanup pageflip on - * - * Post-pageflip callback (r1xx-r4xx). - * Disables the pageflip irq (vblank irq). - */ -void r100_post_page_flip(struct radeon_device *rdev, int crtc) -{ -	/* disable the pflip int */ -	radeon_irq_kms_pflip_irq_put(rdev, crtc); -} - -/**   * r100_page_flip - pageflip callback.   *   * @rdev: radeon_device pointer @@ -182,9 +152,8 @@ void r100_post_page_flip(struct radeon_device *rdev, int crtc)   * During vblank we take the crtc lock and wait for the update_pending   * bit to go high, when it does, we release the lock, and allow the   * double buffered update to take place. - * Returns the current update pending status.   */ -u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  {  	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];  	u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; @@ -206,8 +175,24 @@ u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  	tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK;  	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); +} + +/** + * r100_page_flip_pending - check if page flip is still pending + * + * @rdev: radeon_device pointer + * @crtc_id: crtc to check + * + * Check if the last pagefilp is still pending (r1xx-r4xx). + * Returns the current update pending status. + */ +bool r100_page_flip_pending(struct radeon_device *rdev, int crtc_id) +{ +	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; +  	/* Return current update_pending status: */ -	return RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET; +	return !!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & +		RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET);  }  /** @@ -697,15 +682,11 @@ void r100_pci_gart_disable(struct radeon_device *rdev)  	WREG32(RADEON_AIC_HI_ADDR, 0);  } -int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, +			    uint64_t addr)  {  	u32 *gtt = rdev->gart.ptr; - -	if (i < 0 || i > rdev->gart.num_gpu_pages) { -		return -EINVAL; -	}  	gtt[i] = cpu_to_le32(lower_32_bits(addr)); -	return 0;  }  void r100_pci_gart_fini(struct radeon_device *rdev) @@ -794,7 +775,7 @@ int r100_irq_process(struct radeon_device *rdev)  				wake_up(&rdev->irq.vblank_queue);  			}  			if (atomic_read(&rdev->irq.pflip[0])) -				radeon_crtc_handle_flip(rdev, 0); +				radeon_crtc_handle_vblank(rdev, 0);  		}  		if (status & RADEON_CRTC2_VBLANK_STAT) {  			if (rdev->irq.crtc_vblank_int[1]) { @@ -803,7 +784,7 @@ int r100_irq_process(struct radeon_device *rdev)  				wake_up(&rdev->irq.vblank_queue);  			}  			if (atomic_read(&rdev->irq.pflip[1])) -				radeon_crtc_handle_flip(rdev, 1); +				radeon_crtc_handle_vblank(rdev, 1);  		}  		if (status & RADEON_FP_DETECT_STAT) {  			queue_hotplug = true; @@ -869,13 +850,14 @@ void r100_fence_ring_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, RADEON_SW_INT_FIRE);  } -void r100_semaphore_ring_emit(struct radeon_device *rdev, +bool r100_semaphore_ring_emit(struct radeon_device *rdev,  			      struct radeon_ring *ring,  			      struct radeon_semaphore *semaphore,  			      bool emit_wait)  {  	/* Unused on older asics, since we don't have semaphores or multiple rings */  	BUG(); +	return false;  }  int r100_copy_blit(struct radeon_device *rdev, @@ -1049,6 +1031,36 @@ static int r100_cp_init_microcode(struct radeon_device *rdev)  	return err;  } +u32 r100_gfx_get_rptr(struct radeon_device *rdev, +		      struct radeon_ring *ring) +{ +	u32 rptr; + +	if (rdev->wb.enabled) +		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); +	else +		rptr = RREG32(RADEON_CP_RB_RPTR); + +	return rptr; +} + +u32 r100_gfx_get_wptr(struct radeon_device *rdev, +		      struct radeon_ring *ring) +{ +	u32 wptr; + +	wptr = RREG32(RADEON_CP_RB_WPTR); + +	return wptr; +} + +void r100_gfx_set_wptr(struct radeon_device *rdev, +		       struct radeon_ring *ring) +{ +	WREG32(RADEON_CP_RB_WPTR, ring->wptr); +	(void)RREG32(RADEON_CP_RB_WPTR); +} +  static void r100_cp_load_microcode(struct radeon_device *rdev)  {  	const __be32 *fw_data; @@ -1101,7 +1113,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)  	ring_size = (1 << (rb_bufsz + 1)) * 4;  	r100_cp_load_microcode(rdev);  	r = radeon_ring_init(rdev, ring, ring_size, RADEON_WB_CP_RPTR_OFFSET, -			     RADEON_CP_RB_RPTR, RADEON_CP_RB_WPTR,  			     RADEON_CP_PACKET2);  	if (r) {  		return r; @@ -1163,7 +1174,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)  	WREG32(RADEON_CP_RB_CNTL, tmp);  	udelay(10); -	ring->rptr = RREG32(RADEON_CP_RB_RPTR);  	/* Set cp mode to bus mastering & enable cp*/  	WREG32(RADEON_CP_CSQ_MODE,  	       REG_SET(RADEON_INDIRECT2_START, indirect2_start) | @@ -1245,12 +1255,12 @@ int r100_reloc_pitch_offset(struct radeon_cs_parser *p,  	value = radeon_get_ib_value(p, idx);  	tmp = value & 0x003fffff; -	tmp += (((u32)reloc->lobj.gpu_offset) >> 10); +	tmp += (((u32)reloc->gpu_offset) >> 10);  	if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { -		if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +		if (reloc->tiling_flags & RADEON_TILING_MACRO)  			tile_flags |= RADEON_DST_TILE_MACRO; -		if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { +		if (reloc->tiling_flags & RADEON_TILING_MICRO) {  			if (reg == RADEON_SRC_PITCH_OFFSET) {  				DRM_ERROR("Cannot src blit from microtiled surface\n");  				radeon_cs_dump_packet(p, pkt); @@ -1296,7 +1306,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,  			return r;  		}  		idx_value = radeon_get_ib_value(p, idx); -		ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->lobj.gpu_offset); +		ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset);  		track->arrays[i + 0].esize = idx_value >> 8;  		track->arrays[i + 0].robj = reloc->robj; @@ -1308,7 +1318,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,  			radeon_cs_dump_packet(p, pkt);  			return r;  		} -		ib[idx+2] = radeon_get_ib_value(p, idx + 2) + ((u32)reloc->lobj.gpu_offset); +		ib[idx+2] = radeon_get_ib_value(p, idx + 2) + ((u32)reloc->gpu_offset);  		track->arrays[i + 1].robj = reloc->robj;  		track->arrays[i + 1].esize = idx_value >> 24;  		track->arrays[i + 1].esize &= 0x7F; @@ -1322,7 +1332,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,  			return r;  		}  		idx_value = radeon_get_ib_value(p, idx); -		ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->lobj.gpu_offset); +		ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset);  		track->arrays[i + 0].robj = reloc->robj;  		track->arrays[i + 0].esize = idx_value >> 8;  		track->arrays[i + 0].esize &= 0x7F; @@ -1434,7 +1444,7 @@ int r100_cs_packet_parse_vline(struct radeon_cs_parser *p)  	obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);  	if (!obj) {  		DRM_ERROR("cannot find crtc %d\n", crtc_id); -		return -EINVAL; +		return -ENOENT;  	}  	crtc = obj_to_crtc(obj);  	radeon_crtc = to_radeon_crtc(crtc); @@ -1565,7 +1575,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  		track->zb.robj = reloc->robj;  		track->zb.offset = idx_value;  		track->zb_dirty = true; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case RADEON_RB3D_COLOROFFSET:  		r = radeon_cs_packet_next_reloc(p, &reloc, 0); @@ -1578,7 +1588,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  		track->cb[0].robj = reloc->robj;  		track->cb[0].offset = idx_value;  		track->cb_dirty = true; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case RADEON_PP_TXOFFSET_0:  	case RADEON_PP_TXOFFSET_1: @@ -1592,16 +1602,16 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  			return r;  		}  		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			if (reloc->tiling_flags & RADEON_TILING_MACRO)  				tile_flags |= RADEON_TXO_MACRO_TILE; -			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			if (reloc->tiling_flags & RADEON_TILING_MICRO)  				tile_flags |= RADEON_TXO_MICRO_TILE_X2;  			tmp = idx_value & ~(0x7 << 2);  			tmp |= tile_flags; -			ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset); +			ib[idx] = tmp + ((u32)reloc->gpu_offset);  		} else -			ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +			ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		track->textures[i].robj = reloc->robj;  		track->tex_dirty = true;  		break; @@ -1619,7 +1629,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  			return r;  		}  		track->textures[0].cube_info[i].offset = idx_value; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		track->textures[0].cube_info[i].robj = reloc->robj;  		track->tex_dirty = true;  		break; @@ -1637,7 +1647,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  			return r;  		}  		track->textures[1].cube_info[i].offset = idx_value; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		track->textures[1].cube_info[i].robj = reloc->robj;  		track->tex_dirty = true;  		break; @@ -1655,7 +1665,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  			return r;  		}  		track->textures[2].cube_info[i].offset = idx_value; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		track->textures[2].cube_info[i].robj = reloc->robj;  		track->tex_dirty = true;  		break; @@ -1673,9 +1683,9 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  			return r;  		}  		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			if (reloc->tiling_flags & RADEON_TILING_MACRO)  				tile_flags |= RADEON_COLOR_TILE_ENABLE; -			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			if (reloc->tiling_flags & RADEON_TILING_MICRO)  				tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;  			tmp = idx_value & ~(0x7 << 16); @@ -1743,7 +1753,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  			radeon_cs_dump_packet(p, pkt);  			return r;  		} -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case RADEON_PP_CNTL:  		{ @@ -1903,7 +1913,7 @@ static int r100_packet3_check(struct radeon_cs_parser *p,  			radeon_cs_dump_packet(p, pkt);  			return r;  		} -		ib[idx+1] = radeon_get_ib_value(p, idx+1) + ((u32)reloc->lobj.gpu_offset); +		ib[idx+1] = radeon_get_ib_value(p, idx+1) + ((u32)reloc->gpu_offset);  		r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj);  		if (r) {  			return r; @@ -1917,7 +1927,7 @@ static int r100_packet3_check(struct radeon_cs_parser *p,  			radeon_cs_dump_packet(p, pkt);  			return r;  		} -		ib[idx] = radeon_get_ib_value(p, idx) + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = radeon_get_ib_value(p, idx) + ((u32)reloc->gpu_offset);  		track->num_arrays = 1;  		track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 2)); @@ -2493,11 +2503,9 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	rbbm_status = RREG32(R_000E40_RBBM_STATUS);  	if (!G_000E40_GUI_ACTIVE(rbbm_status)) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force CP activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -3193,12 +3201,12 @@ void r100_bandwidth_update(struct radeon_device *rdev)  	if (rdev->mode_info.crtcs[0]->base.enabled) {  		mode1 = &rdev->mode_info.crtcs[0]->base.mode; -		pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8; +		pixel_bytes1 = rdev->mode_info.crtcs[0]->base.primary->fb->bits_per_pixel / 8;  	}  	if (!(rdev->flags & RADEON_SINGLE_CRTC)) {  		if (rdev->mode_info.crtcs[1]->base.enabled) {  			mode2 = &rdev->mode_info.crtcs[1]->base.mode; -			pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8; +			pixel_bytes2 = rdev->mode_info.crtcs[1]->base.primary->fb->bits_per_pixel / 8;  		}  	} @@ -3922,6 +3930,7 @@ int r100_resume(struct radeon_device *rdev)  int r100_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r100_cp_disable(rdev);  	radeon_wb_disable(rdev);  	r100_irq_disable(rdev); @@ -3932,6 +3941,7 @@ int r100_suspend(struct radeon_device *rdev)  void r100_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r100_cp_fini(rdev);  	radeon_wb_fini(rdev);  	radeon_ib_pool_fini(rdev); @@ -4038,6 +4048,9 @@ int r100_init(struct radeon_device *rdev)  	}  	r100_set_safe_registers(rdev); +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->accel_working = true;  	r = r100_startup(rdev);  	if (r) { diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index b3807edb193..58f0473aa73 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -185,7 +185,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,  		track->zb.robj = reloc->robj;  		track->zb.offset = idx_value;  		track->zb_dirty = true; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case RADEON_RB3D_COLOROFFSET:  		r = radeon_cs_packet_next_reloc(p, &reloc, 0); @@ -198,7 +198,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,  		track->cb[0].robj = reloc->robj;  		track->cb[0].offset = idx_value;  		track->cb_dirty = true; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case R200_PP_TXOFFSET_0:  	case R200_PP_TXOFFSET_1: @@ -215,16 +215,16 @@ int r200_packet0_check(struct radeon_cs_parser *p,  			return r;  		}  		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			if (reloc->tiling_flags & RADEON_TILING_MACRO)  				tile_flags |= R200_TXO_MACRO_TILE; -			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			if (reloc->tiling_flags & RADEON_TILING_MICRO)  				tile_flags |= R200_TXO_MICRO_TILE;  			tmp = idx_value & ~(0x7 << 2);  			tmp |= tile_flags; -			ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset); +			ib[idx] = tmp + ((u32)reloc->gpu_offset);  		} else -			ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +			ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		track->textures[i].robj = reloc->robj;  		track->tex_dirty = true;  		break; @@ -268,7 +268,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,  			return r;  		}  		track->textures[i].cube_info[face - 1].offset = idx_value; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		track->textures[i].cube_info[face - 1].robj = reloc->robj;  		track->tex_dirty = true;  		break; @@ -287,9 +287,9 @@ int r200_packet0_check(struct radeon_cs_parser *p,  		}  		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			if (reloc->tiling_flags & RADEON_TILING_MACRO)  				tile_flags |= RADEON_COLOR_TILE_ENABLE; -			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			if (reloc->tiling_flags & RADEON_TILING_MICRO)  				tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;  			tmp = idx_value & ~(0x7 << 16); @@ -362,7 +362,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,  			radeon_cs_dump_packet(p, pkt);  			return r;  		} -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case RADEON_PP_CNTL:  		{ diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index d8dd269b915..3c21d77a483 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -72,13 +72,11 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)  #define R300_PTE_WRITEABLE (1 << 2)  #define R300_PTE_READABLE  (1 << 3) -int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, +			      uint64_t addr)  {  	void __iomem *ptr = rdev->gart.ptr; -	if (i < 0 || i > rdev->gart.num_gpu_pages) { -		return -EINVAL; -	}  	addr = (lower_32_bits(addr) >> 8) |  	       ((upper_32_bits(addr) & 0xff) << 24) |  	       R300_PTE_WRITEABLE | R300_PTE_READABLE; @@ -86,7 +84,6 @@ int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)  	 * 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)); -	return 0;  }  int rv370_pcie_gart_init(struct radeon_device *rdev) @@ -640,7 +637,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  		track->cb[i].robj = reloc->robj;  		track->cb[i].offset = idx_value;  		track->cb_dirty = true; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case R300_ZB_DEPTHOFFSET:  		r = radeon_cs_packet_next_reloc(p, &reloc, 0); @@ -653,7 +650,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  		track->zb.robj = reloc->robj;  		track->zb.offset = idx_value;  		track->zb_dirty = true; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case R300_TX_OFFSET_0:  	case R300_TX_OFFSET_0+4: @@ -682,16 +679,16 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  		if (p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS) {  			ib[idx] = (idx_value & 31) | /* keep the 1st 5 bits */ -				  ((idx_value & ~31) + (u32)reloc->lobj.gpu_offset); +				  ((idx_value & ~31) + (u32)reloc->gpu_offset);  		} else { -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			if (reloc->tiling_flags & RADEON_TILING_MACRO)  				tile_flags |= R300_TXO_MACRO_TILE; -			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			if (reloc->tiling_flags & RADEON_TILING_MICRO)  				tile_flags |= R300_TXO_MICRO_TILE; -			else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) +			else if (reloc->tiling_flags & RADEON_TILING_MICRO_SQUARE)  				tile_flags |= R300_TXO_MICRO_TILE_SQUARE; -			tmp = idx_value + ((u32)reloc->lobj.gpu_offset); +			tmp = idx_value + ((u32)reloc->gpu_offset);  			tmp |= tile_flags;  			ib[idx] = tmp;  		} @@ -753,11 +750,11 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  				return r;  			} -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			if (reloc->tiling_flags & RADEON_TILING_MACRO)  				tile_flags |= R300_COLOR_TILE_ENABLE; -			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			if (reloc->tiling_flags & RADEON_TILING_MICRO)  				tile_flags |= R300_COLOR_MICROTILE_ENABLE; -			else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) +			else if (reloc->tiling_flags & RADEON_TILING_MICRO_SQUARE)  				tile_flags |= R300_COLOR_MICROTILE_SQUARE_ENABLE;  			tmp = idx_value & ~(0x7 << 16); @@ -838,11 +835,11 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  				return r;  			} -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			if (reloc->tiling_flags & RADEON_TILING_MACRO)  				tile_flags |= R300_DEPTHMACROTILE_ENABLE; -			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			if (reloc->tiling_flags & RADEON_TILING_MICRO)  				tile_flags |= R300_DEPTHMICROTILE_TILED; -			else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) +			else if (reloc->tiling_flags & RADEON_TILING_MICRO_SQUARE)  				tile_flags |= R300_DEPTHMICROTILE_TILED_SQUARE;  			tmp = idx_value & ~(0x7 << 16); @@ -1052,7 +1049,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  			radeon_cs_dump_packet(p, pkt);  			return r;  		} -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case 0x4e0c:  		/* RB3D_COLOR_CHANNEL_MASK */ @@ -1097,7 +1094,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  		track->aa.robj = reloc->robj;  		track->aa.offset = idx_value;  		track->aa_dirty = true; -		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); +		ib[idx] = idx_value + ((u32)reloc->gpu_offset);  		break;  	case R300_RB3D_AARESOLVE_PITCH:  		track->aa.pitch = idx_value & 0x3FFE; @@ -1162,7 +1159,7 @@ static int r300_packet3_check(struct radeon_cs_parser *p,  			radeon_cs_dump_packet(p, pkt);  			return r;  		} -		ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->lobj.gpu_offset); +		ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset);  		r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj);  		if (r) {  			return r; @@ -1440,6 +1437,7 @@ int r300_resume(struct radeon_device *rdev)  int r300_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r100_cp_disable(rdev);  	radeon_wb_disable(rdev);  	r100_irq_disable(rdev); @@ -1452,6 +1450,7 @@ int r300_suspend(struct radeon_device *rdev)  void r300_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r100_cp_fini(rdev);  	radeon_wb_fini(rdev);  	radeon_ib_pool_fini(rdev); @@ -1538,6 +1537,9 @@ int r300_init(struct radeon_device *rdev)  	}  	r300_set_reg_safe(rdev); +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->accel_working = true;  	r = r300_startup(rdev);  	if (r) { diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c index 60170ea5e3a..84b1d5367a1 100644 --- a/drivers/gpu/drm/radeon/r300_cmdbuf.c +++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c @@ -75,7 +75,7 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,  		OUT_RING(CP_PACKET0(R300_RE_CLIPRECT_TL_0, nr * 2 - 1));  		for (i = 0; i < nr; ++i) { -			if (DRM_COPY_FROM_USER +			if (copy_from_user  			    (&box, &cmdbuf->boxes[n + i], sizeof(box))) {  				DRM_ERROR("copy cliprect faulted\n");  				return -EFAULT; @@ -928,12 +928,12 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,  		buf_idx = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);  		*buf_idx *= 2; /* 8 bytes per buf */ -		if (DRM_COPY_TO_USER(ref_age_base + *buf_idx, +		if (copy_to_user(ref_age_base + *buf_idx,  				&dev_priv->scratch_ages[header.scratch.reg],  				sizeof(u32)))  			return -EINVAL; -		if (DRM_COPY_FROM_USER(&h_pending, +		if (copy_from_user(&h_pending,  				ref_age_base + *buf_idx + 1,  				sizeof(u32)))  			return -EINVAL; @@ -943,7 +943,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,  		h_pending--; -		if (DRM_COPY_TO_USER(ref_age_base + *buf_idx + 1, +		if (copy_to_user(ref_age_base + *buf_idx + 1,  					&h_pending,  					sizeof(u32)))  			return -EINVAL; diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 6edf2b3a52b..802b19220a2 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -335,6 +335,7 @@ int r420_resume(struct radeon_device *rdev)  int r420_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r420_cp_errata_fini(rdev);  	r100_cp_disable(rdev);  	radeon_wb_disable(rdev); @@ -348,6 +349,7 @@ int r420_suspend(struct radeon_device *rdev)  void r420_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r100_cp_fini(rdev);  	radeon_wb_fini(rdev);  	radeon_ib_pool_fini(rdev); @@ -444,6 +446,9 @@ int r420_init(struct radeon_device *rdev)  	}  	r420_set_reg_safe(rdev); +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->accel_working = true;  	r = r420_startup(rdev);  	if (r) { diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 1dd0d32993d..136b7bc7cd2 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -402,6 +402,7 @@   * block and vice versa.  This applies to GRPH, CUR, etc.   */  #define AVIVO_D1GRPH_LUT_SEL                                    0x6108 +#       define AVIVO_LUT_10BIT_BYPASS_EN                        (1 << 8)  #define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS                    0x6110  #define R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH                0x6914  #define R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH                0x6114 diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index e1aece73b37..98d6053c36c 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -312,6 +312,9 @@ int r520_init(struct radeon_device *rdev)  		return r;  	rv515_set_safe_registers(rdev); +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->accel_working = true;  	r = r520_startup(rdev);  	if (r) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 2a1b1876b43..3c69f58e46e 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -105,6 +105,7 @@ void r600_fini(struct radeon_device *rdev);  void r600_irq_disable(struct radeon_device *rdev);  static void r600_pcie_gen2_enable(struct radeon_device *rdev);  extern int evergreen_rlc_resume(struct radeon_device *rdev); +extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);  /**   * r600_get_xclk - get the xclk @@ -124,6 +125,59 @@ int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)  	return 0;  } +void dce3_program_fmt(struct drm_encoder *encoder) +{ +	struct drm_device *dev = encoder->dev; +	struct radeon_device *rdev = dev->dev_private; +	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); +	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); +	int bpc = 0; +	u32 tmp = 0; +	enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE; + +	if (connector) { +		struct radeon_connector *radeon_connector = to_radeon_connector(connector); +		bpc = radeon_get_monitor_bpc(connector); +		dither = radeon_connector->dither; +	} + +	/* LVDS FMT is set up by atom */ +	if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT) +		return; + +	/* not needed for analog */ +	if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) || +	    (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2)) +		return; + +	if (bpc == 0) +		return; + +	switch (bpc) { +	case 6: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= FMT_SPATIAL_DITHER_EN; +		else +			tmp |= FMT_TRUNCATE_EN; +		break; +	case 8: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= (FMT_SPATIAL_DITHER_EN | FMT_SPATIAL_DITHER_DEPTH); +		else +			tmp |= (FMT_TRUNCATE_EN | FMT_TRUNCATE_DEPTH); +		break; +	case 10: +	default: +		/* not needed */ +		break; +	} + +	WREG32(FMT_BIT_DEPTH_CONTROL + radeon_crtc->crtc_offset, tmp); +} +  /* get temperature in millidegrees */  int rv6xx_get_temp(struct radeon_device *rdev)  { @@ -1591,6 +1645,67 @@ static void r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)  	r600_print_gpu_status_regs(rdev);  } +static void r600_gpu_pci_config_reset(struct radeon_device *rdev) +{ +	struct rv515_mc_save save; +	u32 tmp, i; + +	dev_info(rdev->dev, "GPU pci config reset\n"); + +	/* disable dpm? */ + +	/* Disable CP parsing/prefetching */ +	if (rdev->family >= CHIP_RV770) +		WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1) | S_0086D8_CP_PFP_HALT(1)); +	else +		WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); + +	/* disable the RLC */ +	WREG32(RLC_CNTL, 0); + +	/* Disable DMA */ +	tmp = RREG32(DMA_RB_CNTL); +	tmp &= ~DMA_RB_ENABLE; +	WREG32(DMA_RB_CNTL, tmp); + +	mdelay(50); + +	/* set mclk/sclk to bypass */ +	if (rdev->family >= CHIP_RV770) +		rv770_set_clk_bypass_mode(rdev); +	/* disable BM */ +	pci_clear_master(rdev->pdev); +	/* disable mem access */ +	rv515_mc_stop(rdev, &save); +	if (r600_mc_wait_for_idle(rdev)) { +		dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); +	} + +	/* BIF reset workaround.  Not sure if this is needed on 6xx */ +	tmp = RREG32(BUS_CNTL); +	tmp |= VGA_COHE_SPEC_TIMER_DIS; +	WREG32(BUS_CNTL, tmp); + +	tmp = RREG32(BIF_SCRATCH0); + +	/* reset */ +	radeon_pci_config_reset(rdev); +	mdelay(1); + +	/* BIF reset workaround.  Not sure if this is needed on 6xx */ +	tmp = SOFT_RESET_BIF; +	WREG32(SRBM_SOFT_RESET, tmp); +	mdelay(1); +	WREG32(SRBM_SOFT_RESET, 0); + +	/* wait for asic to come out of reset */ +	for (i = 0; i < rdev->usec_timeout; i++) { +		if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) +			break; +		udelay(1); +	} +} +  int r600_asic_reset(struct radeon_device *rdev)  {  	u32 reset_mask; @@ -1600,10 +1715,17 @@ int r600_asic_reset(struct radeon_device *rdev)  	if (reset_mask)  		r600_set_bios_scratch_engine_hung(rdev, true); +	/* try soft reset */  	r600_gpu_soft_reset(rdev, reset_mask);  	reset_mask = r600_gpu_check_soft_reset(rdev); +	/* try pci config reset */ +	if (reset_mask && radeon_hard_reset) +		r600_gpu_pci_config_reset(rdev); + +	reset_mask = r600_gpu_check_soft_reset(rdev); +  	if (!reset_mask)  		r600_set_bios_scratch_engine_hung(rdev, false); @@ -1626,11 +1748,9 @@ bool r600_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	if (!(reset_mask & (RADEON_RESET_GFX |  			    RADEON_RESET_COMPUTE |  			    RADEON_RESET_CP))) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force CP activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -1838,6 +1958,9 @@ static void r600_gpu_init(struct radeon_device *rdev)  	if (tmp < rdev->config.r600.max_simds) {  		rdev->config.r600.max_simds = tmp;  	} +	tmp = rdev->config.r600.max_simds - +		r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R6XX_MAX_SIMDS_MASK); +	rdev->config.r600.active_simds = tmp;  	disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R6XX_MAX_BACKENDS_MASK;  	tmp = (tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; @@ -2132,7 +2255,8 @@ void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)   */  void r600_cp_stop(struct radeon_device *rdev)  { -	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); +	if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);  	WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));  	WREG32(SCRATCH_UMSK, 0);  	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false; @@ -2302,6 +2426,7 @@ int r600_init_microcode(struct radeon_device *rdev)  			       fw_name);  			release_firmware(rdev->smc_fw);  			rdev->smc_fw = NULL; +			err = 0;  		} else if (rdev->smc_fw->size != smc_req_size) {  			printk(KERN_ERR  			       "smc: Bogus length %zu in firmware \"%s\"\n", @@ -2328,6 +2453,36 @@ out:  	return err;  } +u32 r600_gfx_get_rptr(struct radeon_device *rdev, +		      struct radeon_ring *ring) +{ +	u32 rptr; + +	if (rdev->wb.enabled) +		rptr = rdev->wb.wb[ring->rptr_offs/4]; +	else +		rptr = RREG32(R600_CP_RB_RPTR); + +	return rptr; +} + +u32 r600_gfx_get_wptr(struct radeon_device *rdev, +		      struct radeon_ring *ring) +{ +	u32 wptr; + +	wptr = RREG32(R600_CP_RB_WPTR); + +	return wptr; +} + +void r600_gfx_set_wptr(struct radeon_device *rdev, +		       struct radeon_ring *ring) +{ +	WREG32(R600_CP_RB_WPTR, ring->wptr); +	(void)RREG32(R600_CP_RB_WPTR); +} +  static int r600_cp_load_microcode(struct radeon_device *rdev)  {  	const __be32 *fw_data; @@ -2450,8 +2605,6 @@ int r600_cp_resume(struct radeon_device *rdev)  	WREG32(CP_RB_BASE, ring->gpu_addr >> 8);  	WREG32(CP_DEBUG, (1 << 27) | (1 << 28)); -	ring->rptr = RREG32(CP_RB_RPTR); -  	r600_cp_start(rdev);  	ring->ready = true;  	r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring); @@ -2459,6 +2612,10 @@ int r600_cp_resume(struct radeon_device *rdev)  		ring->ready = false;  		return r;  	} + +	if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); +  	return 0;  } @@ -2553,30 +2710,31 @@ void r600_fence_ring_emit(struct radeon_device *rdev,  			  struct radeon_fence *fence)  {  	struct radeon_ring *ring = &rdev->ring[fence->ring]; +	u32 cp_coher_cntl = PACKET3_TC_ACTION_ENA | PACKET3_VC_ACTION_ENA | +		PACKET3_SH_ACTION_ENA; + +	if (rdev->family >= CHIP_RV770) +		cp_coher_cntl |= PACKET3_FULL_CACHE_ENA;  	if (rdev->wb.use_event) {  		u64 addr = rdev->fence_drv[fence->ring].gpu_addr;  		/* flush read cache over gart */  		radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); -		radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | -					PACKET3_VC_ACTION_ENA | -					PACKET3_SH_ACTION_ENA); +		radeon_ring_write(ring, cp_coher_cntl);  		radeon_ring_write(ring, 0xFFFFFFFF);  		radeon_ring_write(ring, 0);  		radeon_ring_write(ring, 10); /* poll interval */  		/* EVENT_WRITE_EOP - flush caches, send int */  		radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));  		radeon_ring_write(ring, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT_TS) | EVENT_INDEX(5)); -		radeon_ring_write(ring, addr & 0xffffffff); +		radeon_ring_write(ring, lower_32_bits(addr));  		radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | DATA_SEL(1) | INT_SEL(2));  		radeon_ring_write(ring, fence->seq);  		radeon_ring_write(ring, 0);  	} else {  		/* flush read cache over gart */  		radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); -		radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | -					PACKET3_VC_ACTION_ENA | -					PACKET3_SH_ACTION_ENA); +		radeon_ring_write(ring, cp_coher_cntl);  		radeon_ring_write(ring, 0xFFFFFFFF);  		radeon_ring_write(ring, 0);  		radeon_ring_write(ring, 10); /* poll interval */ @@ -2596,7 +2754,7 @@ void r600_fence_ring_emit(struct radeon_device *rdev,  	}  } -void r600_semaphore_ring_emit(struct radeon_device *rdev, +bool r600_semaphore_ring_emit(struct radeon_device *rdev,  			      struct radeon_ring *ring,  			      struct radeon_semaphore *semaphore,  			      bool emit_wait) @@ -2608,8 +2766,10 @@ void r600_semaphore_ring_emit(struct radeon_device *rdev,  		sel |= PACKET3_SEM_WAIT_ON_SIGNAL;  	radeon_ring_write(ring, PACKET3(PACKET3_MEM_SEMAPHORE, 1)); -	radeon_ring_write(ring, addr & 0xffffffff); +	radeon_ring_write(ring, lower_32_bits(addr));  	radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel); + +	return true;  }  /** @@ -2652,13 +2812,8 @@ int r600_copy_cpdma(struct radeon_device *rdev,  		return r;  	} -	if (radeon_fence_need_sync(*fence, ring->idx)) { -		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, -					    ring->idx); -		radeon_fence_note_sync(*fence, ring->idx); -	} else { -		radeon_semaphore_free(rdev, &sem, NULL); -	} +	radeon_semaphore_sync_to(sem, *fence); +	radeon_semaphore_sync_rings(rdev, sem, ring->idx);  	radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));  	radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); @@ -2672,9 +2827,9 @@ int r600_copy_cpdma(struct radeon_device *rdev,  		if (size_in_bytes == 0)  			tmp |= PACKET3_CP_DMA_CP_SYNC;  		radeon_ring_write(ring, PACKET3(PACKET3_CP_DMA, 4)); -		radeon_ring_write(ring, src_offset & 0xffffffff); +		radeon_ring_write(ring, lower_32_bits(src_offset));  		radeon_ring_write(ring, tmp); -		radeon_ring_write(ring, dst_offset & 0xffffffff); +		radeon_ring_write(ring, lower_32_bits(dst_offset));  		radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff);  		radeon_ring_write(ring, cur_size_in_bytes);  		src_offset += cur_size_in_bytes; @@ -2687,6 +2842,7 @@ int r600_copy_cpdma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} @@ -2724,14 +2880,6 @@ static int r600_startup(struct radeon_device *rdev)  	r600_mc_program(rdev); -	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { -		r = r600_init_microcode(rdev); -		if (r) { -			DRM_ERROR("Failed to load firmware!\n"); -			return r; -		} -	} -  	if (rdev->flags & RADEON_IS_AGP) {  		r600_agp_enable(rdev);  	} else { @@ -2752,12 +2900,6 @@ static int r600_startup(struct radeon_device *rdev)  		return r;  	} -	r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX); -	if (r) { -		dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r); -		return r; -	} -  	/* Enable IRQ */  	if (!rdev->irq.installed) {  		r = radeon_irq_kms_init(rdev); @@ -2775,18 +2917,10 @@ static int r600_startup(struct radeon_device *rdev)  	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, -			     R600_CP_RB_RPTR, R600_CP_RB_WPTR,  			     RADEON_CP_PACKET2);  	if (r)  		return r; -	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; -	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, -			     DMA_RB_RPTR, DMA_RB_WPTR, -			     DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); -	if (r) -		return r; -  	r = r600_cp_load_microcode(rdev);  	if (r)  		return r; @@ -2794,10 +2928,6 @@ static int r600_startup(struct radeon_device *rdev)  	if (r)  		return r; -	r = r600_dma_resume(rdev); -	if (r) -		return r; -  	r = radeon_ib_pool_init(rdev);  	if (r) {  		dev_err(rdev->dev, "IB initialization failed (%d).\n", r); @@ -2838,6 +2968,9 @@ int r600_resume(struct radeon_device *rdev)  	/* post card */  	atom_asic_init(rdev->mode_info.atom_context); +	if (rdev->pm.pm_method == PM_METHOD_DPM) +		radeon_pm_resume(rdev); +  	rdev->accel_working = true;  	r = r600_startup(rdev);  	if (r) { @@ -2851,9 +2984,9 @@ int r600_resume(struct radeon_device *rdev)  int r600_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r600_audio_fini(rdev);  	r600_cp_stop(rdev); -	r600_dma_stop(rdev);  	r600_irq_suspend(rdev);  	radeon_wb_disable(rdev);  	r600_pcie_gart_disable(rdev); @@ -2919,12 +3052,20 @@ int r600_init(struct radeon_device *rdev)  	if (r)  		return r; +	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { +		r = r600_init_microcode(rdev); +		if (r) { +			DRM_ERROR("Failed to load firmware!\n"); +			return r; +		} +	} + +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;  	r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); -	rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL; -	r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024); -  	rdev->ih.ring_obj = NULL;  	r600_ih_ring_init(rdev, 64 * 1024); @@ -2937,7 +3078,6 @@ int r600_init(struct radeon_device *rdev)  	if (r) {  		dev_err(rdev->dev, "disabling GPU acceleration\n");  		r600_cp_fini(rdev); -		r600_dma_fini(rdev);  		r600_irq_fini(rdev);  		radeon_wb_fini(rdev);  		radeon_ib_pool_fini(rdev); @@ -2951,9 +3091,9 @@ int r600_init(struct radeon_device *rdev)  void r600_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r600_audio_fini(rdev);  	r600_cp_fini(rdev); -	r600_dma_fini(rdev);  	r600_irq_fini(rdev);  	radeon_wb_fini(rdev);  	radeon_ib_pool_fini(rdev); @@ -3369,7 +3509,6 @@ int r600_irq_set(struct radeon_device *rdev)  	u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;  	u32 grbm_int_cntl = 0;  	u32 hdmi0, hdmi1; -	u32 d1grph = 0, d2grph = 0;  	u32 dma_cntl;  	u32 thermal_int = 0; @@ -3478,8 +3617,8 @@ int r600_irq_set(struct radeon_device *rdev)  	WREG32(CP_INT_CNTL, cp_int_cntl);  	WREG32(DMA_CNTL, dma_cntl);  	WREG32(DxMODE_INT_MASK, mode_int); -	WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph); -	WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph); +	WREG32(D1GRPH_INTERRUPT_CONTROL, DxGRPH_PFLIP_INT_MASK); +	WREG32(D2GRPH_INTERRUPT_CONTROL, DxGRPH_PFLIP_INT_MASK);  	WREG32(GRBM_INT_CNTL, grbm_int_cntl);  	if (ASIC_IS_DCE3(rdev)) {  		WREG32(DC_HPD1_INT_CONTROL, hpd1); @@ -3656,6 +3795,7 @@ static u32 r600_get_ih_wptr(struct radeon_device *rdev)  		tmp = RREG32(IH_RB_CNTL);  		tmp |= IH_WPTR_OVERFLOW_CLEAR;  		WREG32(IH_RB_CNTL, tmp); +		wptr &= ~RB_OVERFLOW;  	}  	return (wptr & rdev->ih.ptr_mask);  } @@ -3740,7 +3880,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[0])) -						radeon_crtc_handle_flip(rdev, 0); +						radeon_crtc_handle_vblank(rdev, 0);  					rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D1 vblank\n");  				} @@ -3766,7 +3906,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[1])) -						radeon_crtc_handle_flip(rdev, 1); +						radeon_crtc_handle_vblank(rdev, 1);  					rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D2 vblank\n");  				} @@ -3782,6 +3922,14 @@ restart_ih:  				break;  			}  			break; +		case 9: /* D1 pflip */ +			DRM_DEBUG("IH: D1 flip\n"); +			radeon_crtc_handle_flip(rdev, 0); +			break; +		case 11: /* D2 pflip */ +			DRM_DEBUG("IH: D2 flip\n"); +			radeon_crtc_handle_flip(rdev, 1); +			break;  		case 19: /* HPD/DAC hotplug */  			switch (src_data) {  			case 0: @@ -3852,6 +4000,10 @@ restart_ih:  				break;  			}  			break; +		case 124: /* UVD */ +			DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); +			radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); +			break;  		case 176: /* CP_INT in ring buffer */  		case 177: /* CP_INT in IB1 */  		case 178: /* CP_INT in IB2 */ diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index 47fc2b88697..bffac10c429 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -142,12 +142,15 @@ void r600_audio_update_hdmi(struct work_struct *work)  }  /* enable the audio stream */ -static void r600_audio_enable(struct radeon_device *rdev, -			      struct r600_audio_pin *pin, -			      bool enable) +void r600_audio_enable(struct radeon_device *rdev, +		       struct r600_audio_pin *pin, +		       bool enable)  {  	u32 value = 0; +	if (!pin) +		return; +  	if (ASIC_IS_DCE4(rdev)) {  		if (enable) {  			value |= 0x81000000; /* Required to enable audio */ @@ -158,7 +161,6 @@ static void r600_audio_enable(struct radeon_device *rdev,  		WREG32_P(R600_AUDIO_ENABLE,  			 enable ? 0x81000000 : 0x0, ~0x81000000);  	} -	DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);  }  /* @@ -178,8 +180,8 @@ int r600_audio_init(struct radeon_device *rdev)  	rdev->audio.pin[0].status_bits = 0;  	rdev->audio.pin[0].category_code = 0;  	rdev->audio.pin[0].id = 0; - -	r600_audio_enable(rdev, &rdev->audio.pin[0], true); +	/* disable audio.  it will be set up later */ +	r600_audio_enable(rdev, &rdev->audio.pin[0], false);  	return 0;  } diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index d8eb48bff0e..8c9b7e26533 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -2515,7 +2515,7 @@ int r600_cp_dispatch_texture(struct drm_device *dev,  		buf = radeon_freelist_get(dev);  		if (!buf) {  			DRM_DEBUG("EAGAIN\n"); -			if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image))) +			if (copy_to_user(tex->image, image, sizeof(*image)))  				return -EFAULT;  			return -EAGAIN;  		} @@ -2528,7 +2528,7 @@ int r600_cp_dispatch_texture(struct drm_device *dev,  		buffer =  		    (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset); -		if (DRM_COPY_FROM_USER(buffer, data, pass_size)) { +		if (copy_from_user(buffer, data, pass_size)) {  			DRM_ERROR("EFAULT on pad, %d bytes\n", pass_size);  			return -EFAULT;  		} diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 01a3ec83f28..12511bb5fd6 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -749,7 +749,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)  		}  		for (i = 0; i < 8; i++) { -			if ((tmp >> (i * 4)) & 0xF) { +			u32 format = G_0280A0_FORMAT(track->cb_color_info[i]); + +			if (format != V_0280A0_COLOR_INVALID && +			    (tmp >> (i * 4)) & 0xF) {  				/* at least one component is enabled */  				if (track->cb_color_bo[i] == NULL) {  					dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n", @@ -887,7 +890,7 @@ int r600_cs_common_vline_parse(struct radeon_cs_parser *p,  	obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);  	if (!obj) {  		DRM_ERROR("cannot find crtc %d\n", crtc_id); -		return -EINVAL; +		return -ENOENT;  	}  	crtc = obj_to_crtc(obj);  	radeon_crtc = to_radeon_crtc(crtc); @@ -1004,8 +1007,22 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  	case R_008C64_SQ_VSTMP_RING_SIZE:  	case R_0288C8_SQ_GS_VERT_ITEMSIZE:  		/* get value to populate the IB don't remove */ -		tmp =radeon_get_ib_value(p, idx); -		ib[idx] = 0; +		/*tmp =radeon_get_ib_value(p, idx); +		  ib[idx] = 0;*/ +		break; +	case SQ_ESGS_RING_BASE: +	case SQ_GSVS_RING_BASE: +	case SQ_ESTMP_RING_BASE: +	case SQ_GSTMP_RING_BASE: +	case SQ_PSTMP_RING_BASE: +	case SQ_VSTMP_RING_BASE: +		r = radeon_cs_packet_next_reloc(p, &reloc, 0); +		if (r) { +			dev_warn(p->dev, "bad SET_CONTEXT_REG " +					"0x%04X\n", reg); +			return -EINVAL; +		} +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		break;  	case SQ_CONFIG:  		track->sq_config = radeon_get_ib_value(p, idx); @@ -1026,7 +1043,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			track->db_depth_info = radeon_get_ib_value(p, idx);  			ib[idx] &= C_028010_ARRAY_MODE;  			track->db_depth_info &= C_028010_ARRAY_MODE; -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { +			if (reloc->tiling_flags & RADEON_TILING_MACRO) {  				ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1);  				track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1);  			} else { @@ -1067,9 +1084,9 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  		}  		tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;  		track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8; -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->vgt_strmout_bo[tmp] = reloc->robj; -		track->vgt_strmout_bo_mc[tmp] = reloc->lobj.gpu_offset; +		track->vgt_strmout_bo_mc[tmp] = reloc->gpu_offset;  		track->streamout_dirty = true;  		break;  	case VGT_STRMOUT_BUFFER_SIZE_0: @@ -1088,7 +1105,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  					"0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		break;  	case R_028238_CB_TARGET_MASK:  		track->cb_target_mask = radeon_get_ib_value(p, idx); @@ -1125,10 +1142,10 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			}  			tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;  			track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); -			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { +			if (reloc->tiling_flags & RADEON_TILING_MACRO) {  				ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1);  				track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1); -			} else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { +			} else if (reloc->tiling_flags & RADEON_TILING_MICRO) {  				ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1);  				track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1);  			} @@ -1197,7 +1214,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			}  			track->cb_color_frag_bo[tmp] = reloc->robj;  			track->cb_color_frag_offset[tmp] = (u64)ib[idx] << 8; -			ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +			ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		}  		if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {  			track->cb_dirty = true; @@ -1228,7 +1245,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			}  			track->cb_color_tile_bo[tmp] = reloc->robj;  			track->cb_color_tile_offset[tmp] = (u64)ib[idx] << 8; -			ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +			ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		}  		if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {  			track->cb_dirty = true; @@ -1264,10 +1281,10 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  		}  		tmp = (reg - CB_COLOR0_BASE) / 4;  		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8; -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->cb_color_base_last[tmp] = ib[idx];  		track->cb_color_bo[tmp] = reloc->robj; -		track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset; +		track->cb_color_bo_mc[tmp] = reloc->gpu_offset;  		track->cb_dirty = true;  		break;  	case DB_DEPTH_BASE: @@ -1278,9 +1295,9 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		track->db_offset = radeon_get_ib_value(p, idx) << 8; -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->db_bo = reloc->robj; -		track->db_bo_mc = reloc->lobj.gpu_offset; +		track->db_bo_mc = reloc->gpu_offset;  		track->db_dirty = true;  		break;  	case DB_HTILE_DATA_BASE: @@ -1291,7 +1308,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  			return -EINVAL;  		}  		track->htile_offset = radeon_get_ib_value(p, idx) << 8; -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		track->htile_bo = reloc->robj;  		track->db_dirty = true;  		break; @@ -1360,7 +1377,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  					"0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		break;  	case SX_MEMORY_EXPORT_BASE:  		r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); @@ -1369,7 +1386,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  					"0x%04X\n", reg);  			return -EINVAL;  		} -		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		break;  	case SX_MISC:  		track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0; @@ -1655,7 +1672,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         (idx_value & 0xfffffff0) +  		         ((u64)(tmp & 0xff) << 32); @@ -1696,7 +1713,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         idx_value +  		         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); @@ -1748,7 +1765,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  				return -EINVAL;  			} -			offset = reloc->lobj.gpu_offset + +			offset = reloc->gpu_offset +  			         (radeon_get_ib_value(p, idx+1) & 0xfffffff0) +  			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); @@ -1788,7 +1805,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  			tmp = radeon_get_ib_value(p, idx) +  				((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); -			offset = reloc->lobj.gpu_offset + tmp; +			offset = reloc->gpu_offset + tmp;  			if ((tmp + size) > radeon_bo_size(reloc->robj)) {  				dev_warn(p->dev, "CP DMA src buffer too small (%llu %lu)\n", @@ -1818,7 +1835,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  			tmp = radeon_get_ib_value(p, idx+2) +  				((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32); -			offset = reloc->lobj.gpu_offset + tmp; +			offset = reloc->gpu_offset + tmp;  			if ((tmp + size) > radeon_bo_size(reloc->robj)) {  				dev_warn(p->dev, "CP DMA dst buffer too small (%llu %lu)\n", @@ -1844,7 +1861,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  				DRM_ERROR("bad SURFACE_SYNC\n");  				return -EINVAL;  			} -			ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +			ib[idx+2] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		}  		break;  	case PACKET3_EVENT_WRITE: @@ -1860,7 +1877,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  				DRM_ERROR("bad EVENT_WRITE\n");  				return -EINVAL;  			} -			offset = reloc->lobj.gpu_offset + +			offset = reloc->gpu_offset +  			         (radeon_get_ib_value(p, idx+1) & 0xfffffff8) +  			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); @@ -1882,7 +1899,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  			return -EINVAL;  		} -		offset = reloc->lobj.gpu_offset + +		offset = reloc->gpu_offset +  		         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +  		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); @@ -1947,11 +1964,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  					DRM_ERROR("bad SET_RESOURCE\n");  					return -EINVAL;  				} -				base_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +				base_offset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  				if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { -					if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +					if (reloc->tiling_flags & RADEON_TILING_MACRO)  						ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); -					else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +					else if (reloc->tiling_flags & RADEON_TILING_MICRO)  						ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);  				}  				texture = reloc->robj; @@ -1961,13 +1978,13 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  					DRM_ERROR("bad SET_RESOURCE\n");  					return -EINVAL;  				} -				mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +				mip_offset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  				mipmap = reloc->robj;  				r = r600_check_texture_resource(p,  idx+(i*7)+1,  								texture, mipmap,  								base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2),  								mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3), -								reloc->lobj.tiling_flags); +								reloc->tiling_flags);  				if (r)  					return r;  				ib[idx+1+(i*7)+2] += base_offset; @@ -1991,7 +2008,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  					ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj) - offset;  				} -				offset64 = reloc->lobj.gpu_offset + offset; +				offset64 = reloc->gpu_offset + offset;  				ib[idx+1+(i*8)+0] = offset64;  				ib[idx+1+(i*8)+2] = (ib[idx+1+(i*8)+2] & 0xffffff00) |  						    (upper_32_bits(offset64) & 0xff); @@ -2101,7 +2118,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			ib[idx+1] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +			ib[idx+1] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);  		}  		break;  	case PACKET3_SURFACE_BASE_UPDATE: @@ -2134,7 +2151,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			offset += reloc->lobj.gpu_offset; +			offset += reloc->gpu_offset;  			ib[idx+1] = offset;  			ib[idx+2] = upper_32_bits(offset) & 0xff;  		} @@ -2153,7 +2170,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			offset += reloc->lobj.gpu_offset; +			offset += reloc->gpu_offset;  			ib[idx+3] = offset;  			ib[idx+4] = upper_32_bits(offset) & 0xff;  		} @@ -2182,7 +2199,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  				  offset + 8, radeon_bo_size(reloc->robj));  			return -EINVAL;  		} -		offset += reloc->lobj.gpu_offset; +		offset += reloc->gpu_offset;  		ib[idx+0] = offset;  		ib[idx+1] = upper_32_bits(offset) & 0xff;  		break; @@ -2207,7 +2224,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			offset += reloc->lobj.gpu_offset; +			offset += reloc->gpu_offset;  			ib[idx+1] = offset;  			ib[idx+2] = upper_32_bits(offset) & 0xff;  		} else { @@ -2231,7 +2248,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,  					  offset + 4, radeon_bo_size(reloc->robj));  				return -EINVAL;  			} -			offset += reloc->lobj.gpu_offset; +			offset += reloc->gpu_offset;  			ib[idx+3] = offset;  			ib[idx+4] = upper_32_bits(offset) & 0xff;  		} else { @@ -2328,13 +2345,8 @@ static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error)  	unsigned i;  	kfree(parser->relocs); -	for (i = 0; i < parser->nchunks; i++) { -		kfree(parser->chunks[i].kdata); -		if (parser->rdev && (parser->rdev->flags & RADEON_IS_AGP)) { -			kfree(parser->chunks[i].kpage[0]); -			kfree(parser->chunks[i].kpage[1]); -		} -	} +	for (i = 0; i < parser->nchunks; i++) +		drm_free_large(parser->chunks[i].kdata);  	kfree(parser->chunks);  	kfree(parser->chunks_array);  } @@ -2391,13 +2403,12 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,  	ib_chunk = &parser.chunks[parser.chunk_ib_idx];  	parser.ib.length_dw = ib_chunk->length_dw;  	*l = parser.ib.length_dw; -	r = r600_cs_parse(&parser); -	if (r) { -		DRM_ERROR("Invalid command stream !\n"); +	if (copy_from_user(ib, ib_chunk->user_ptr, ib_chunk->length_dw * 4)) { +		r = -EFAULT;  		r600_cs_parser_fini(&parser, r);  		return r;  	} -	r = radeon_cs_finish_pages(&parser); +	r = r600_cs_parse(&parser);  	if (r) {  		DRM_ERROR("Invalid command stream !\n");  		r600_cs_parser_fini(&parser, r); @@ -2494,14 +2505,14 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)  				dst_offset = radeon_get_ib_value(p, idx+1);  				dst_offset <<= 8; -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); +				ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);  				p->idx += count + 5;  			} else {  				dst_offset = radeon_get_ib_value(p, idx+1);  				dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; -				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -				ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; +				ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +				ib[idx+2] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;  				p->idx += count + 3;  			}  			if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { @@ -2528,22 +2539,22 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)  					/* tiled src, linear dst */  					src_offset = radeon_get_ib_value(p, idx+1);  					src_offset <<= 8; -					ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); +					ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8);  					dst_offset = radeon_get_ib_value(p, idx+5);  					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32; -					ib[idx+5] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+6] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+5] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +					ib[idx+6] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;  				} else {  					/* linear src, tiled dst */  					src_offset = radeon_get_ib_value(p, idx+5);  					src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32; -					ib[idx+5] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+5] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +					ib[idx+6] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  					dst_offset = radeon_get_ib_value(p, idx+1);  					dst_offset <<= 8; -					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); +					ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);  				}  				p->idx += 7;  			} else { @@ -2553,10 +2564,10 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)  					dst_offset = radeon_get_ib_value(p, idx+1);  					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32; -					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; -					ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; +					ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +					ib[idx+2] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +					ib[idx+3] += upper_32_bits(dst_reloc->gpu_offset) & 0xff; +					ib[idx+4] += upper_32_bits(src_reloc->gpu_offset) & 0xff;  					p->idx += 5;  				} else {  					src_offset = radeon_get_ib_value(p, idx+2); @@ -2564,10 +2575,10 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)  					dst_offset = radeon_get_ib_value(p, idx+1);  					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff0000)) << 16; -					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); -					ib[idx+3] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; -					ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff) << 16; +					ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +					ib[idx+2] += (u32)(src_reloc->gpu_offset & 0xfffffffc); +					ib[idx+3] += upper_32_bits(src_reloc->gpu_offset) & 0xff; +					ib[idx+3] += (upper_32_bits(dst_reloc->gpu_offset) & 0xff) << 16;  					p->idx += 4;  				}  			} @@ -2599,8 +2610,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)  					 dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));  				return -EINVAL;  			} -			ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); -			ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) << 16) & 0x00ff0000; +			ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc); +			ib[idx+3] += (upper_32_bits(dst_reloc->gpu_offset) << 16) & 0x00ff0000;  			p->idx += 4;  			break;  		case DMA_PACKET_NOP: diff --git a/drivers/gpu/drm/radeon/r600_dma.c b/drivers/gpu/drm/radeon/r600_dma.c index 3b317456512..4969cef44a1 100644 --- a/drivers/gpu/drm/radeon/r600_dma.c +++ b/drivers/gpu/drm/radeon/r600_dma.c @@ -51,7 +51,14 @@ u32 r600_gpu_check_soft_reset(struct radeon_device *rdev);  uint32_t r600_dma_get_rptr(struct radeon_device *rdev,  			   struct radeon_ring *ring)  { -	return (radeon_ring_generic_get_rptr(rdev, ring) & 0x3fffc) >> 2; +	u32 rptr; + +	if (rdev->wb.enabled) +		rptr = rdev->wb.wb[ring->rptr_offs/4]; +	else +		rptr = RREG32(DMA_RB_RPTR); + +	return (rptr & 0x3fffc) >> 2;  }  /** @@ -65,7 +72,7 @@ uint32_t r600_dma_get_rptr(struct radeon_device *rdev,  uint32_t r600_dma_get_wptr(struct radeon_device *rdev,  			   struct radeon_ring *ring)  { -	return (RREG32(ring->wptr_reg) & 0x3fffc) >> 2; +	return (RREG32(DMA_RB_WPTR) & 0x3fffc) >> 2;  }  /** @@ -79,7 +86,7 @@ uint32_t r600_dma_get_wptr(struct radeon_device *rdev,  void r600_dma_set_wptr(struct radeon_device *rdev,  		       struct radeon_ring *ring)  { -	WREG32(ring->wptr_reg, (ring->wptr << 2) & 0x3fffc); +	WREG32(DMA_RB_WPTR, (ring->wptr << 2) & 0x3fffc);  }  /** @@ -93,7 +100,8 @@ void r600_dma_stop(struct radeon_device *rdev)  {  	u32 rb_cntl = RREG32(DMA_RB_CNTL); -	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); +	if (rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);  	rb_cntl &= ~DMA_RB_ENABLE;  	WREG32(DMA_RB_CNTL, rb_cntl); @@ -168,8 +176,6 @@ int r600_dma_resume(struct radeon_device *rdev)  	ring->wptr = 0;  	WREG32(DMA_RB_WPTR, ring->wptr << 2); -	ring->rptr = RREG32(DMA_RB_RPTR) >> 2; -  	WREG32(DMA_RB_CNTL, rb_cntl | DMA_RB_ENABLE);  	ring->ready = true; @@ -180,7 +186,8 @@ int r600_dma_resume(struct radeon_device *rdev)  		return r;  	} -	radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); +	if (rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);  	return 0;  } @@ -212,11 +219,9 @@ bool r600_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	u32 reset_mask = r600_gpu_check_soft_reset(rdev);  	if (!(reset_mask & RADEON_RESET_DMA)) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force ring activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -311,7 +316,7 @@ void r600_dma_fence_ring_emit(struct radeon_device *rdev,   * Add a DMA semaphore packet to the ring wait on or signal   * other rings (r6xx-SI).   */ -void r600_dma_semaphore_ring_emit(struct radeon_device *rdev, +bool r600_dma_semaphore_ring_emit(struct radeon_device *rdev,  				  struct radeon_ring *ring,  				  struct radeon_semaphore *semaphore,  				  bool emit_wait) @@ -322,6 +327,8 @@ void r600_dma_semaphore_ring_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SEMAPHORE, 0, s, 0));  	radeon_ring_write(ring, addr & 0xfffffffc);  	radeon_ring_write(ring, upper_32_bits(addr) & 0xff); + +	return true;  }  /** @@ -462,13 +469,8 @@ int r600_copy_dma(struct radeon_device *rdev,  		return r;  	} -	if (radeon_fence_need_sync(*fence, ring->idx)) { -		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, -					    ring->idx); -		radeon_fence_note_sync(*fence, ring->idx); -	} else { -		radeon_semaphore_free(rdev, &sem, NULL); -	} +	radeon_semaphore_sync_to(sem, *fence); +	radeon_semaphore_sync_rings(rdev, sem, ring->idx);  	for (i = 0; i < num_loops; i++) {  		cur_size_in_dw = size_in_dw; @@ -487,6 +489,7 @@ int r600_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 5513d8f0625..9c61b74ef44 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -158,16 +158,18 @@ u32 r600_dpm_get_vblank_time(struct radeon_device *rdev)  	u32 line_time_us, vblank_lines;  	u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ -	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		radeon_crtc = to_radeon_crtc(crtc); -		if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { -			line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) / -				radeon_crtc->hw_mode.clock; -			vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end - -				radeon_crtc->hw_mode.crtc_vdisplay + -				(radeon_crtc->v_border * 2); -			vblank_time_us = vblank_lines * line_time_us; -			break; +	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +			radeon_crtc = to_radeon_crtc(crtc); +			if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { +				line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) / +					radeon_crtc->hw_mode.clock; +				vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end - +					radeon_crtc->hw_mode.crtc_vdisplay + +					(radeon_crtc->v_border * 2); +				vblank_time_us = vblank_lines * line_time_us; +				break; +			}  		}  	} @@ -181,14 +183,15 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev)  	struct radeon_crtc *radeon_crtc;  	u32 vrefresh = 0; -	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		radeon_crtc = to_radeon_crtc(crtc); -		if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { -			vrefresh = radeon_crtc->hw_mode.vrefresh; -			break; +	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +			radeon_crtc = to_radeon_crtc(crtc); +			if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { +				vrefresh = radeon_crtc->hw_mode.vrefresh; +				break; +			}  		}  	} -  	return vrefresh;  } @@ -729,8 +732,8 @@ bool r600_is_uvd_state(u32 class, u32 class2)  	return false;  } -int r600_set_thermal_temperature_range(struct radeon_device *rdev, -				       int min_temp, int max_temp) +static int r600_set_thermal_temperature_range(struct radeon_device *rdev, +					      int min_temp, int max_temp)  {  	int low_temp = 0 * 1000;  	int high_temp = 255 * 1000; @@ -777,6 +780,22 @@ bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor)  	}  } +int r600_dpm_late_enable(struct radeon_device *rdev) +{ +	int ret; + +	if (rdev->irq.installed && +	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { +		ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); +		if (ret) +			return ret; +		rdev->irq.dpm_thermal = true; +		radeon_irq_set(rdev); +	} + +	return 0; +} +  union power_info {  	struct _ATOM_POWERPLAY_INFO info;  	struct _ATOM_POWERPLAY_INFO_V2 info_2; @@ -818,6 +837,26 @@ static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependen  	return 0;  } +int r600_get_platform_caps(struct radeon_device *rdev) +{ +	struct radeon_mode_info *mode_info = &rdev->mode_info; +	union power_info *power_info; +	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); +        u16 data_offset; +	u8 frev, crev; + +	if (!atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) +		return -EINVAL; +	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); + +	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); +	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); +	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime); + +	return 0; +} +  /* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */  #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12  #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14 @@ -1027,7 +1066,15 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)  				(mode_info->atom_context->bios + data_offset +  				 le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +  				 1 + array->ucNumEntries * sizeof(VCEClockInfo)); +			ATOM_PPLIB_VCE_State_Table *states = +				(ATOM_PPLIB_VCE_State_Table *) +				(mode_info->atom_context->bios + data_offset + +				 le16_to_cpu(ext_hdr->usVCETableOffset) + 1 + +				 1 + (array->ucNumEntries * sizeof (VCEClockInfo)) + +				 1 + (limits->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record)));  			ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *entry; +			ATOM_PPLIB_VCE_State_Record *state_entry; +			VCEClockInfo *vce_clk;  			u32 size = limits->numEntries *  				sizeof(struct radeon_vce_clock_voltage_dependency_entry);  			rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries = @@ -1039,8 +1086,9 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)  			rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count =  				limits->numEntries;  			entry = &limits->entries[0]; +			state_entry = &states->entries[0];  			for (i = 0; i < limits->numEntries; i++) { -				VCEClockInfo *vce_clk = (VCEClockInfo *) +				vce_clk = (VCEClockInfo *)  					((u8 *)&array->entries[0] +  					 (entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));  				rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].evclk = @@ -1052,6 +1100,23 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)  				entry = (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *)  					((u8 *)entry + sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record));  			} +			for (i = 0; i < states->numEntries; i++) { +				if (i >= RADEON_MAX_VCE_LEVELS) +					break; +				vce_clk = (VCEClockInfo *) +					((u8 *)&array->entries[0] + +					 (state_entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo))); +				rdev->pm.dpm.vce_states[i].evclk = +					le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16); +				rdev->pm.dpm.vce_states[i].ecclk = +					le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16); +				rdev->pm.dpm.vce_states[i].clk_idx = +					state_entry->ucClockInfoIndex & 0x3f; +				rdev->pm.dpm.vce_states[i].pstate = +					(state_entry->ucClockInfoIndex & 0xc0) >> 6; +				state_entry = (ATOM_PPLIB_VCE_State_Record *) +					((u8 *)state_entry + sizeof(ATOM_PPLIB_VCE_State_Record)); +			}  		}  		if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) &&  			ext_hdr->usUVDTableOffset) { diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h index 1000bf9719f..46b9d2a0301 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.h +++ b/drivers/gpu/drm/radeon/r600_dpm.h @@ -213,10 +213,10 @@ void r600_wait_for_power_level(struct radeon_device *rdev,  void r600_start_dpm(struct radeon_device *rdev);  void r600_stop_dpm(struct radeon_device *rdev); -int r600_set_thermal_temperature_range(struct radeon_device *rdev, -				       int min_temp, int max_temp);  bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor); +int r600_get_platform_caps(struct radeon_device *rdev); +  int r600_parse_extended_power_table(struct radeon_device *rdev);  void r600_free_extended_power_table(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index b0fa6002af3..26ef8ced6f8 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -24,6 +24,7 @@   * Authors: Christian König   */  #include <linux/hdmi.h> +#include <linux/gcd.h>  #include <drm/drmP.h>  #include <drm/radeon_drm.h>  #include "radeon.h" @@ -57,28 +58,57 @@ enum r600_hdmi_iec_status_bits {  static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {      /*	     32kHz	  44.1kHz	48kHz    */      /* Clock      N     CTS      N     CTS      N     CTS */ -    {  25174,  4576,  28125,  7007,  31250,  6864,  28125 }, /*  25,20/1.001 MHz */ +    {  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 */ -    {  74175, 11648, 210937, 17836, 234375, 11648, 140625 }, /*  74.25/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 */ -    { 148351, 11648, 421875,  8918, 234375,  5824, 140625 }, /* 148.50/1.001 MHz */ +    { 148352,  4096, 148352,  5733, 150670,  6144, 148352 }, /* 148.50/1.001 MHz */      { 148500,  4096, 148500,  6272, 165000,  6144, 148500 }, /* 148.50       MHz */ -    {      0,  4096,      0,  6272,      0,  6144,      0 }  /* Other */  }; +  /* - * calculate CTS value if it's not found in the table + * 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) +static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq)  { -	if (*CTS == 0) -		*CTS = clock * N / (128 * freq) * 1000; -	DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n", -		  N, *CTS, 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) @@ -86,15 +116,16 @@ struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)  	struct radeon_hdmi_acr res;  	u8 i; -	for (i = 0; r600_hdmi_predefined_acr[i].clock != clock && -	     r600_hdmi_predefined_acr[i].clock != 0; i++) -		; -	res = r600_hdmi_predefined_acr[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]; +	} -	/* In case some CTS are missing */ -	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); +	/* 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;  } @@ -102,7 +133,7 @@ struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)  /*   * update the N and CTS parameters for a given pixel clock rate   */ -static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) +void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)  {  	struct drm_device *dev = encoder->dev;  	struct radeon_device *rdev = dev->dev_private; @@ -111,21 +142,33 @@ static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)  	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;  	uint32_t offset = dig->afmt->offset; -	WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(acr.cts_32khz)); -	WREG32(HDMI0_ACR_32_1 + offset, acr.n_32khz); - -	WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(acr.cts_44_1khz)); -	WREG32(HDMI0_ACR_44_1 + offset, acr.n_44_1khz); - -	WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(acr.cts_48khz)); -	WREG32(HDMI0_ACR_48_1 + offset, acr.n_48khz); +	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);  }  /*   * build a HDMI Video Info Frame   */ -static void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, -					   void *buffer, size_t size) +void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, +				    size_t size)  {  	struct drm_device *dev = encoder->dev;  	struct radeon_device *rdev = dev->dev_private; @@ -200,7 +243,7 @@ int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder)  /*   * write the audio workaround status to the hardware   */ -static void r600_hdmi_audio_workaround(struct drm_encoder *encoder) +void r600_hdmi_audio_workaround(struct drm_encoder *encoder)  {  	struct drm_device *dev = encoder->dev;  	struct radeon_device *rdev = dev->dev_private; @@ -273,9 +316,9 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)  			WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo);  			WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */  		} -	} else if (ASIC_IS_DCE3(rdev)) { +	} else {  		/* according to the reg specs, this should DCE3.2 only, but in -		 * practice it seems to cover DCE3.0/3.1 as well. +		 * 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); @@ -286,112 +329,7 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)  			WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);  			WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */  		} -	} else { -		/* according to the reg specs, this should be DCE2.0 and DCE3.0/3.1 */ -		WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate / 10) | -		       AUDIO_DTO_MODULE(clock / 10)); -	} -} - -static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) -{ -	struct radeon_device *rdev = encoder->dev->dev_private; -	struct drm_connector *connector; -	struct radeon_connector *radeon_connector = NULL; -	u32 tmp; -	u8 *sadb; -	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); -	} - -	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_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); -		return; -	} - -	/* program the speaker allocation */ -	tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); -	tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); -	/* set HDMI mode */ -	tmp |= HDMI_CONNECTION; -	if (sad_count) -		tmp |= SPEAKER_ALLOCATION(sadb[0]); -	else -		tmp |= SPEAKER_ALLOCATION(5); /* stereo */ -	WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); - -	kfree(sadb); -} - -static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder) -{ -	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; - -	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 }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD }, -		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP }, -		{ 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); -	} - -	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; -		int j; - -		for (j = 0; j < sad_count; j++) { -			struct cea_sad *sad = &sads[j]; - -			if (sad->format == eld_reg_to_type[i][1]) { -				value = MAX_CHANNELS(sad->channels) | -					DESCRIPTOR_BYTE_2(sad->byte2) | -					SUPPORTED_FREQUENCIES(sad->freq); -				if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) -					value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq); -				break; -			} -		} -		WREG32(eld_reg_to_type[i][0], value);  	} - -	kfree(sads);  }  /* @@ -406,6 +344,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod  	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) @@ -416,54 +355,50 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod  		return;  	offset = dig->afmt->offset; -	r600_audio_set_dto(encoder, mode->clock); - -	WREG32(HDMI0_VBI_PACKET_CONTROL + offset, -	       HDMI0_NULL_SEND); /* send null packets when required */ - -	WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000); - -	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 */ -	} 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 */ -	} - -	if (ASIC_IS_DCE32(rdev)) { -		dce3_2_afmt_write_speaker_allocation(encoder); -		dce3_2_afmt_write_sad_regs(encoder); -	} - -	WREG32(HDMI0_ACR_PACKET_CONTROL + offset, -	       HDMI0_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ -	       HDMI0_ACR_SOURCE); /* select SW CTS value */ - -	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 */ +	/* disable audio prior to setting up hw */ +	dig->afmt->pin = r600_audio_get_pin(rdev); +	r600_audio_enable(rdev, dig->afmt->pin, false); -	WREG32(HDMI0_INFOFRAME_CONTROL1 + offset, -	       HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */ -	       HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */ +	r600_audio_set_dto(encoder, mode->clock); -	WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */ +	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 */ + +	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 */ + +	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) { @@ -478,19 +413,45 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod  	}  	r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); + +	/* fglrx duplicates INFOFRAME_CONTROL0 & INFOFRAME_CONTROL1 ops here */ + +	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); +	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)); + +	WREG32_P(HDMI0_60958_1 + offset, +		 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); -	r600_hdmi_audio_workaround(encoder); +	/* enable audio after to setting up hw */ +	r600_audio_enable(rdev, dig->afmt->pin, true);  } -/* - * update settings with current parameters from audio engine +/** + * r600_hdmi_update_audio_settings - Update audio infoframe + * + * @encoder: drm encoder + * + * Gets info about current audio stream and updates audio infoframe.   */  void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)  { @@ -502,7 +463,7 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)  	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];  	struct hdmi_audio_infoframe frame;  	uint32_t offset; -	uint32_t iec; +	uint32_t value;  	ssize_t err;  	if (!dig->afmt || !dig->afmt->enabled) @@ -515,60 +476,6 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)  	DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n",  		  (int)audio.status_bits, (int)audio.category_code); -	iec = 0; -	if (audio.status_bits & AUDIO_STATUS_PROFESSIONAL) -		iec |= 1 << 0; -	if (audio.status_bits & AUDIO_STATUS_NONAUDIO) -		iec |= 1 << 1; -	if (audio.status_bits & AUDIO_STATUS_COPYRIGHT) -		iec |= 1 << 2; -	if (audio.status_bits & AUDIO_STATUS_EMPHASIS) -		iec |= 1 << 3; - -	iec |= HDMI0_60958_CS_CATEGORY_CODE(audio.category_code); - -	switch (audio.rate) { -	case 32000: -		iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x3); -		break; -	case 44100: -		iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x0); -		break; -	case 48000: -		iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x2); -		break; -	case 88200: -		iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x8); -		break; -	case 96000: -		iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xa); -		break; -	case 176400: -		iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xc); -		break; -	case 192000: -		iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xe); -		break; -	} - -	WREG32(HDMI0_60958_0 + offset, iec); - -	iec = 0; -	switch (audio.bits_per_sample) { -	case 16: -		iec |= HDMI0_60958_CS_WORD_LENGTH(0x2); -		break; -	case 20: -		iec |= HDMI0_60958_CS_WORD_LENGTH(0x3); -		break; -	case 24: -		iec |= HDMI0_60958_CS_WORD_LENGTH(0xb); -		break; -	} -	if (audio.status_bits & AUDIO_STATUS_V) -		iec |= 0x5 << 16; -	WREG32_P(HDMI0_60958_1 + offset, iec, ~0x5000f); -  	err = hdmi_audio_infoframe_init(&frame);  	if (err < 0) {  		DRM_ERROR("failed to setup audio infoframe\n"); @@ -583,8 +490,22 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)  		return;  	} +	value = RREG32(HDMI0_AUDIO_PACKET_CONTROL + offset); +	if (value & HDMI0_AUDIO_TEST_EN) +		WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, +		       value & ~HDMI0_AUDIO_TEST_EN); + +	WREG32_OR(HDMI0_CONTROL + offset, +		  HDMI0_ERROR_ACK); + +	WREG32_AND(HDMI0_INFOFRAME_CONTROL0 + offset, +		   ~HDMI0_AUDIO_INFO_SOURCE); +  	r600_hdmi_update_audio_infoframe(encoder, buffer, sizeof(buffer)); -	r600_hdmi_audio_workaround(encoder); + +	WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, +		  HDMI0_AUDIO_INFO_CONT | +		  HDMI0_AUDIO_INFO_UPDATE);  }  /* @@ -607,11 +528,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)  	if (!enable && !dig->afmt->enabled)  		return; -	if (enable) -		dig->afmt->pin = r600_audio_get_pin(rdev); -	else -		dig->afmt->pin = NULL; -  	/* Older chipsets require setting HDMI and routing manually */  	if (!ASIC_IS_DCE3(rdev)) {  		if (enable) diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index e673fe26ea8..f94e7a9afe7 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -701,11 +701,18 @@  #define RLC_UCODE_DATA                                    0x3f30  #define SRBM_SOFT_RESET                                   0xe60 +#       define SOFT_RESET_BIF                             (1 << 1)  #       define SOFT_RESET_DMA                             (1 << 12)  #       define SOFT_RESET_RLC                             (1 << 13)  #       define SOFT_RESET_UVD                             (1 << 18)  #       define RV770_SOFT_RESET_DMA                       (1 << 20) +#define BIF_SCRATCH0                                      0x5438 + +#define BUS_CNTL                                          0x5420 +#       define BIOS_ROM_DIS                               (1 << 1) +#       define VGA_COHE_SPEC_TIMER_DIS                    (1 << 9) +  #define CP_INT_CNTL                                       0xc124  #       define CNTX_BUSY_INT_ENABLE                       (1 << 19)  #       define CNTX_EMPTY_INT_ENABLE                      (1 << 20) @@ -1022,15 +1029,18 @@  #define HDMI0_AUDIO_PACKET_CONTROL   0x7408  #       define HDMI0_AUDIO_SAMPLE_SEND  (1 << 0)  #       define HDMI0_AUDIO_DELAY_EN(x)  (((x) & 3) << 4) +#       define HDMI0_AUDIO_DELAY_EN_MASK	(3 << 4)  #       define HDMI0_AUDIO_SEND_MAX_PACKETS  (1 << 8)  #       define HDMI0_AUDIO_TEST_EN         (1 << 12)  #       define HDMI0_AUDIO_PACKETS_PER_LINE(x)  (((x) & 0x1f) << 16) +#       define HDMI0_AUDIO_PACKETS_PER_LINE_MASK	(0x1f << 16)  #       define HDMI0_AUDIO_CHANNEL_SWAP    (1 << 24)  #       define HDMI0_60958_CS_UPDATE       (1 << 26)  #       define HDMI0_AZ_FORMAT_WTRIG_MASK  (1 << 28)  #       define HDMI0_AZ_FORMAT_WTRIG_ACK   (1 << 29)  #define HDMI0_AUDIO_CRC_CONTROL      0x740c  #       define HDMI0_AUDIO_CRC_EN    (1 << 0) +#define DCE3_HDMI0_ACR_PACKET_CONTROL	0x740c  #define HDMI0_VBI_PACKET_CONTROL     0x7410  #       define HDMI0_NULL_SEND       (1 << 0)  #       define HDMI0_GC_SEND         (1 << 4) @@ -1047,7 +1057,9 @@  #       define HDMI0_MPEG_INFO_UPDATE  (1 << 10)  #define HDMI0_INFOFRAME_CONTROL1     0x7418  #       define HDMI0_AVI_INFO_LINE(x)  (((x) & 0x3f) << 0) +#       define HDMI0_AVI_INFO_LINE_MASK		(0x3f << 0)  #       define HDMI0_AUDIO_INFO_LINE(x)  (((x) & 0x3f) << 8) +#       define HDMI0_AUDIO_INFO_LINE_MASK	(0x3f << 8)  #       define HDMI0_MPEG_INFO_LINE(x)  (((x) & 0x3f) << 16)  #define HDMI0_GENERIC_PACKET_CONTROL 0x741c  #       define HDMI0_GENERIC0_SEND   (1 << 0) @@ -1056,7 +1068,9 @@  #       define HDMI0_GENERIC1_SEND   (1 << 4)  #       define HDMI0_GENERIC1_CONT   (1 << 5)  #       define HDMI0_GENERIC0_LINE(x)  (((x) & 0x3f) << 16) +#       define HDMI0_GENERIC0_LINE_MASK		(0x3f << 16)  #       define HDMI0_GENERIC1_LINE(x)  (((x) & 0x3f) << 24) +#       define HDMI0_GENERIC1_LINE_MASK		(0x3f << 24)  #define HDMI0_GC                     0x7428  #       define HDMI0_GC_AVMUTE       (1 << 0)  #define HDMI0_AVI_INFO0              0x7454 @@ -1112,16 +1126,22 @@  #define HDMI0_GENERIC1_6             0x74a8  #define HDMI0_ACR_32_0               0x74ac  #       define HDMI0_ACR_CTS_32(x)   (((x) & 0xfffff) << 12) +#       define HDMI0_ACR_CTS_32_MASK		(0xfffff << 12)  #define HDMI0_ACR_32_1               0x74b0  #       define HDMI0_ACR_N_32(x)   (((x) & 0xfffff) << 0) +#       define HDMI0_ACR_N_32_MASK		(0xfffff << 0)  #define HDMI0_ACR_44_0               0x74b4  #       define HDMI0_ACR_CTS_44(x)   (((x) & 0xfffff) << 12) +#       define HDMI0_ACR_CTS_44_MASK		(0xfffff << 12)  #define HDMI0_ACR_44_1               0x74b8  #       define HDMI0_ACR_N_44(x)   (((x) & 0xfffff) << 0) +#       define HDMI0_ACR_N_44_MASK		(0xfffff << 0)  #define HDMI0_ACR_48_0               0x74bc  #       define HDMI0_ACR_CTS_48(x)   (((x) & 0xfffff) << 12) +#       define HDMI0_ACR_CTS_48_MASK		(0xfffff << 12)  #define HDMI0_ACR_48_1               0x74c0  #       define HDMI0_ACR_N_48(x)   (((x) & 0xfffff) << 0) +#       define HDMI0_ACR_N_48_MASK		(0xfffff << 0)  #define HDMI0_ACR_STATUS_0           0x74c4  #define HDMI0_ACR_STATUS_1           0x74c8  #define HDMI0_AUDIO_INFO0            0x74cc @@ -1141,14 +1161,17 @@  #       define HDMI0_60958_CS_CATEGORY_CODE(x)      (((x) & 0xff) << 8)  #       define HDMI0_60958_CS_SOURCE_NUMBER(x)      (((x) & 0xf) << 16)  #       define HDMI0_60958_CS_CHANNEL_NUMBER_L(x)   (((x) & 0xf) << 20) +#       define HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK	(0xf << 20)  #       define HDMI0_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)  #       define HDMI0_60958_CS_CLOCK_ACCURACY(x)     (((x) & 3) << 28) +#       define HDMI0_60958_CS_CLOCK_ACCURACY_MASK	(3 << 28)  #define HDMI0_60958_1                0x74d8  #       define HDMI0_60958_CS_WORD_LENGTH(x)        (((x) & 0xf) << 0)  #       define HDMI0_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x)   (((x) & 0xf) << 4)  #       define HDMI0_60958_CS_VALID_L(x)   (((x) & 1) << 16)  #       define HDMI0_60958_CS_VALID_R(x)   (((x) & 1) << 18)  #       define HDMI0_60958_CS_CHANNEL_NUMBER_R(x)   (((x) & 0xf) << 20) +#       define HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK	(0xf << 20)  #define HDMI0_ACR_PACKET_CONTROL     0x74dc  #       define HDMI0_ACR_SEND        (1 << 0)  #       define HDMI0_ACR_CONT        (1 << 1) @@ -1159,6 +1182,7 @@  #       define HDMI0_ACR_48          3  #       define HDMI0_ACR_SOURCE      (1 << 8) /* 0 - hw; 1 - cts value */  #       define HDMI0_ACR_AUTO_SEND   (1 << 12) +#define DCE3_HDMI0_AUDIO_CRC_CONTROL	0x74dc  #define HDMI0_RAMP_CONTROL0          0x74e0  #       define HDMI0_RAMP_MAX_COUNT(x)   (((x) & 0xffffff) << 0)  #define HDMI0_RAMP_CONTROL1          0x74e4 @@ -1199,6 +1223,34 @@  #       define AFMT_AZ_FORMAT_WTRIG_ACK      (1 << 29)  #       define AFMT_AZ_AUDIO_ENABLE_CHG_ACK  (1 << 30) +/* DCE3 FMT blocks */ +#define FMT_CONTROL                          0x6700 +#       define FMT_PIXEL_ENCODING            (1 << 16) +        /* 0 = RGB 4:4:4 or YCbCr 4:4:4, 1 = YCbCr 4:2:2 */ +#define FMT_BIT_DEPTH_CONTROL                0x6710 +#       define FMT_TRUNCATE_EN               (1 << 0) +#       define FMT_TRUNCATE_DEPTH            (1 << 4) +#       define FMT_SPATIAL_DITHER_EN         (1 << 8) +#       define FMT_SPATIAL_DITHER_MODE(x)    ((x) << 9) +#       define FMT_SPATIAL_DITHER_DEPTH      (1 << 12) +#       define FMT_FRAME_RANDOM_ENABLE       (1 << 13) +#       define FMT_RGB_RANDOM_ENABLE         (1 << 14) +#       define FMT_HIGHPASS_RANDOM_ENABLE    (1 << 15) +#       define FMT_TEMPORAL_DITHER_EN        (1 << 16) +#       define FMT_TEMPORAL_DITHER_DEPTH     (1 << 20) +#       define FMT_TEMPORAL_DITHER_OFFSET(x) ((x) << 21) +#       define FMT_TEMPORAL_LEVEL            (1 << 24) +#       define FMT_TEMPORAL_DITHER_RESET     (1 << 25) +#       define FMT_25FRC_SEL(x)              ((x) << 26) +#       define FMT_50FRC_SEL(x)              ((x) << 28) +#       define FMT_75FRC_SEL(x)              ((x) << 30) +#define FMT_CLAMP_CONTROL                    0x672c +#       define FMT_CLAMP_DATA_EN             (1 << 0) +#       define FMT_CLAMP_COLOR_FORMAT(x)     ((x) << 16) +#       define FMT_CLAMP_6BPC                0 +#       define FMT_CLAMP_8BPC                1 +#       define FMT_CLAMP_10BPC               2 +  /* Power management */  #define CG_SPLL_FUNC_CNTL                                 0x600  #       define SPLL_RESET                                (1 << 0) @@ -1523,7 +1575,7 @@   */  #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)  /* COMMAND */ -#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23) +#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)                  /* 0 - none  		 * 1 - 8 in 16  		 * 2 - 8 in 32 @@ -1547,6 +1599,7 @@  #              define PACKET3_CP_DMA_CMD_DAIC      (1 << 29)  #define	PACKET3_SURFACE_SYNC				0x43  #              define PACKET3_CB0_DEST_BASE_ENA    (1 << 6) +#              define PACKET3_FULL_CACHE_ENA       (1 << 20) /* r7xx+ only */  #              define PACKET3_TC_ACTION_ENA        (1 << 23)  #              define PACKET3_VC_ACTION_ENA        (1 << 24)  #              define PACKET3_CB_ACTION_ENA        (1 << 25) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a400ac1c414..60c47f82912 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -98,6 +98,11 @@ extern int radeon_lockup_timeout;  extern int radeon_fastfb;  extern int radeon_dpm;  extern int radeon_aspm; +extern int radeon_runtime_pm; +extern int radeon_hard_reset; +extern int radeon_vm_size; +extern int radeon_vm_block_size; +extern int radeon_deep_color;  /*   * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -111,19 +116,16 @@ extern int radeon_aspm;  #define RADEONFB_CONN_LIMIT			4  #define RADEON_BIOS_NUM_SCRATCH			8 -/* max number of rings */ -#define RADEON_NUM_RINGS			6 -  /* fence seq are set to this number when signaled */  #define RADEON_FENCE_SIGNALED_SEQ		0LL  /* internal ring indices */  /* r1xx+ has gfx CP ring */ -#define RADEON_RING_TYPE_GFX_INDEX	0 +#define RADEON_RING_TYPE_GFX_INDEX		0  /* cayman has 2 compute CP rings */ -#define CAYMAN_RING_TYPE_CP1_INDEX	1 -#define CAYMAN_RING_TYPE_CP2_INDEX	2 +#define CAYMAN_RING_TYPE_CP1_INDEX		1 +#define CAYMAN_RING_TYPE_CP2_INDEX		2  /* R600+ has an async dma ring */  #define R600_RING_TYPE_DMA_INDEX		3 @@ -131,13 +133,29 @@ extern int radeon_aspm;  #define CAYMAN_RING_TYPE_DMA1_INDEX		4  /* R600+ */ -#define R600_RING_TYPE_UVD_INDEX	5 +#define R600_RING_TYPE_UVD_INDEX		5 + +/* TN+ */ +#define TN_RING_TYPE_VCE1_INDEX			6 +#define TN_RING_TYPE_VCE2_INDEX			7 + +/* max number of rings */ +#define RADEON_NUM_RINGS			8 + +/* number of hw syncs before falling back on blocking */ +#define RADEON_NUM_SYNCS			4 + +/* number of hw syncs before falling back on blocking */ +#define RADEON_NUM_SYNCS			4  /* hardcode those limit for now */  #define RADEON_VA_IB_OFFSET			(1 << 20)  #define RADEON_VA_RESERVED_SIZE			(8 << 20)  #define RADEON_IB_VM_MAX_SIZE			(64 << 10) +/* hard reset data */ +#define RADEON_ASIC_RESET_DATA                  0x39d5e86b +  /* reset flags */  #define RADEON_RESET_GFX			(1 << 0)  #define RADEON_RESET_COMPUTE			(1 << 1) @@ -251,6 +269,7 @@ struct radeon_clock {   * Power management   */  int radeon_pm_init(struct radeon_device *rdev); +int radeon_pm_late_init(struct radeon_device *rdev);  void radeon_pm_fini(struct radeon_device *rdev);  void radeon_pm_compute_clocks(struct radeon_device *rdev);  void radeon_pm_suspend(struct radeon_device *rdev); @@ -327,7 +346,6 @@ struct radeon_fence_driver {  	/* sync_seq is protected by ring emission lock */  	uint64_t			sync_seq[RADEON_NUM_RINGS];  	atomic64_t			last_seq; -	unsigned long			last_activity;  	bool				initialized;  }; @@ -348,8 +366,8 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, i  void radeon_fence_process(struct radeon_device *rdev, int ring);  bool radeon_fence_signaled(struct radeon_fence *fence);  int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); -int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring); -int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); +int radeon_fence_wait_next(struct radeon_device *rdev, int ring); +int radeon_fence_wait_empty(struct radeon_device *rdev, int ring);  int radeon_fence_wait_any(struct radeon_device *rdev,  			  struct radeon_fence **fences,  			  bool intr); @@ -412,6 +430,11 @@ struct radeon_mman {  	struct ttm_bo_device		bdev;  	bool				mem_global_referenced;  	bool				initialized; + +#if defined(CONFIG_DEBUG_FS) +	struct dentry			*vram; +	struct dentry			*gtt; +#endif  };  /* bo virtual address in a specific vm */ @@ -426,6 +449,7 @@ struct radeon_bo_va {  	/* protected by vm mutex */  	struct list_head		vm_list; +	struct list_head		vm_status;  	/* constant after initialization */  	struct radeon_vm		*vm; @@ -436,6 +460,7 @@ struct radeon_bo {  	/* Protected by gem.mutex */  	struct list_head		list;  	/* Protected by tbo.reserved */ +	u32				initial_domain;  	u32				placements[3];  	struct ttm_placement		placement;  	struct ttm_buffer_object	tbo; @@ -458,16 +483,6 @@ struct radeon_bo {  };  #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) -struct radeon_bo_list { -	struct ttm_validate_buffer tv; -	struct radeon_bo	*bo; -	uint64_t		gpu_offset; -	bool			written; -	unsigned		domain; -	unsigned		alt_domain; -	u32			tiling_flags; -}; -  int radeon_gem_debugfs_init(struct radeon_device *rdev);  /* sub-allocation manager, it has to be protected by another lock. @@ -543,22 +558,24 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,  /*   * Semaphores.   */ -/* everything here is constant */  struct radeon_semaphore {  	struct radeon_sa_bo		*sa_bo;  	signed				waiters;  	uint64_t			gpu_addr; +	struct radeon_fence		*sync_to[RADEON_NUM_RINGS];  };  int radeon_semaphore_create(struct radeon_device *rdev,  			    struct radeon_semaphore **semaphore); -void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring, +bool radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,  				  struct radeon_semaphore *semaphore); -void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring, +bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,  				struct radeon_semaphore *semaphore); +void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore, +			      struct radeon_fence *fence);  int radeon_semaphore_sync_rings(struct radeon_device *rdev,  				struct radeon_semaphore *semaphore, -				int signaler, int waiter); +				int waiting_ring);  void radeon_semaphore_free(struct radeon_device *rdev,  			   struct radeon_semaphore **semaphore,  			   struct radeon_fence *fence); @@ -645,13 +662,15 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);  /*   * GPU doorbell structures, functions & helpers   */ +#define RADEON_MAX_DOORBELLS 1024	/* Reserve at most 1024 doorbell slots for radeon-owned rings. */ +  struct radeon_doorbell { -	u32			num_pages; -	bool			free[1024];  	/* doorbell mmio */ -	resource_size_t			base; -	resource_size_t			size; -	void __iomem			*ptr; +	resource_size_t		base; +	resource_size_t		size; +	u32 __iomem		*ptr; +	u32			num_doorbells;	/* Number of doorbells actually reserved for radeon. */ +	unsigned long		used[DIV_ROUND_UP(RADEON_MAX_DOORBELLS, BITS_PER_LONG)];  };  int radeon_doorbell_get(struct radeon_device *rdev, u32 *page); @@ -661,14 +680,15 @@ void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);   * IRQS.   */ -struct radeon_unpin_work { -	struct work_struct work; -	struct radeon_device *rdev; -	int crtc_id; -	struct radeon_fence *fence; +struct radeon_flip_work { +	struct work_struct		flip_work; +	struct work_struct		unpin_work; +	struct radeon_device		*rdev; +	int				crtc_id; +	uint64_t			base;  	struct drm_pending_vblank_event *event; -	struct radeon_bo *old_rbo; -	u64 new_crtc_base; +	struct radeon_bo		*old_rbo; +	struct radeon_fence		*fence;  };  struct r500_irq_stat_regs { @@ -715,6 +735,12 @@ struct cik_irq_stat_regs {  	u32 disp_int_cont4;  	u32 disp_int_cont5;  	u32 disp_int_cont6; +	u32 d1grph_int; +	u32 d2grph_int; +	u32 d3grph_int; +	u32 d4grph_int; +	u32 d5grph_int; +	u32 d6grph_int;  };  union radeon_irq_stat_regs { @@ -724,10 +750,6 @@ union radeon_irq_stat_regs {  	struct cik_irq_stat_regs cik;  }; -#define RADEON_MAX_HPD_PINS 6 -#define RADEON_MAX_CRTCS 6 -#define RADEON_MAX_AFMT_BLOCKS 7 -  struct radeon_irq {  	bool				installed;  	spinlock_t			lock; @@ -765,27 +787,23 @@ struct radeon_ib {  	struct radeon_fence		*fence;  	struct radeon_vm		*vm;  	bool				is_const_ib; -	struct radeon_fence		*sync_to[RADEON_NUM_RINGS];  	struct radeon_semaphore		*semaphore;  };  struct radeon_ring {  	struct radeon_bo	*ring_obj;  	volatile uint32_t	*ring; -	unsigned		rptr;  	unsigned		rptr_offs; -	unsigned		rptr_reg;  	unsigned		rptr_save_reg;  	u64			next_rptr_gpu_addr;  	volatile u32		*next_rptr_cpu_addr;  	unsigned		wptr;  	unsigned		wptr_old; -	unsigned		wptr_reg;  	unsigned		ring_size;  	unsigned		ring_free_dw;  	int			count_dw; -	unsigned long		last_activity; -	unsigned		last_rptr; +	atomic_t		last_rptr; +	atomic64_t		last_activity;  	uint64_t		gpu_addr;  	uint32_t		align_mask;  	uint32_t		ptr_mask; @@ -799,8 +817,7 @@ struct radeon_ring {  	u32 pipe;  	u32 queue;  	struct radeon_bo	*mqd_obj; -	u32 doorbell_page_num; -	u32 doorbell_offset; +	u32 doorbell_index;  	unsigned		wptr_offs;  }; @@ -819,43 +836,62 @@ struct radeon_mec {  /* maximum number of VMIDs */  #define RADEON_NUM_VM	16 -/* defines number of bits in page table versus page directory, - * a page is 4KB so we have 12 bits offset, 9 bits in the page - * table and the remaining 19 bits are in the page directory */ -#define RADEON_VM_BLOCK_SIZE   9 -  /* number of entries in page table */ -#define RADEON_VM_PTE_COUNT (1 << RADEON_VM_BLOCK_SIZE) +#define RADEON_VM_PTE_COUNT (1 << radeon_vm_block_size)  /* PTBs (Page Table Blocks) need to be aligned to 32K */  #define RADEON_VM_PTB_ALIGN_SIZE   32768  #define RADEON_VM_PTB_ALIGN_MASK (RADEON_VM_PTB_ALIGN_SIZE - 1)  #define RADEON_VM_PTB_ALIGN(a) (((a) + RADEON_VM_PTB_ALIGN_MASK) & ~RADEON_VM_PTB_ALIGN_MASK) +#define R600_PTE_VALID		(1 << 0) +#define R600_PTE_SYSTEM		(1 << 1) +#define R600_PTE_SNOOPED	(1 << 2) +#define R600_PTE_READABLE	(1 << 5) +#define R600_PTE_WRITEABLE	(1 << 6) + +/* PTE (Page Table Entry) fragment field for different page sizes */ +#define R600_PTE_FRAG_4KB	(0 << 7) +#define R600_PTE_FRAG_64KB	(4 << 7) +#define R600_PTE_FRAG_256KB	(6 << 7) + +/* flags used for GART page table entries on R600+ */ +#define R600_PTE_GART	( R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED \ +			| R600_PTE_READABLE | R600_PTE_WRITEABLE) + +struct radeon_vm_pt { +	struct radeon_bo		*bo; +	uint64_t			addr; +}; +  struct radeon_vm { -	struct list_head		list;  	struct list_head		va;  	unsigned			id; +	/* BOs freed, but not yet updated in the PT */ +	struct list_head		freed; +  	/* contains the page directory */ -	struct radeon_sa_bo		*page_directory; +	struct radeon_bo		*page_directory;  	uint64_t			pd_gpu_addr; +	unsigned			max_pde_used;  	/* array of page tables, one for each page directory entry */ -	struct radeon_sa_bo		**page_tables; +	struct radeon_vm_pt		*page_tables; + +	struct radeon_bo_va		*ib_bo_va;  	struct mutex			mutex;  	/* last fence for cs using this vm */  	struct radeon_fence		*fence;  	/* last flush or NULL if we still need to flush */  	struct radeon_fence		*last_flush; +	/* last use of vmid */ +	struct radeon_fence		*last_id_use;  };  struct radeon_vm_manager { -	struct mutex			lock; -	struct list_head		lru_vm;  	struct radeon_fence		*active[RADEON_NUM_VM]; -	struct radeon_sa_manager	sa_manager;  	uint32_t			max_pfn;  	/* number of VMIDs */  	unsigned			nvm; @@ -915,7 +951,6 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,  		  struct radeon_ib *ib, struct radeon_vm *vm,  		  unsigned size);  void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib); -void radeon_ib_sync_to(struct radeon_ib *ib, struct radeon_fence *fence);  int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,  		       struct radeon_ib *const_ib);  int radeon_ib_pool_init(struct radeon_device *rdev); @@ -932,15 +967,15 @@ void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *c  void radeon_ring_undo(struct radeon_ring *ring);  void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp);  int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); -void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring); -void radeon_ring_lockup_update(struct radeon_ring *ring); +void radeon_ring_lockup_update(struct radeon_device *rdev, +			       struct radeon_ring *ring);  bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring);  unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring,  			    uint32_t **data);  int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring,  			unsigned size, uint32_t *data);  int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size, -		     unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, u32 nop); +		     unsigned rptr_offs, u32 nop);  void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *cp); @@ -959,20 +994,19 @@ void cayman_dma_fini(struct radeon_device *rdev);  struct radeon_cs_reloc {  	struct drm_gem_object		*gobj;  	struct radeon_bo		*robj; -	struct radeon_bo_list		lobj; +	struct ttm_validate_buffer	tv; +	uint64_t			gpu_offset; +	unsigned			prefered_domains; +	unsigned			allowed_domains; +	uint32_t			tiling_flags;  	uint32_t			handle; -	uint32_t			flags;  };  struct radeon_cs_chunk {  	uint32_t		chunk_id;  	uint32_t		length_dw; -	int			kpage_idx[2]; -	uint32_t		*kpage[2];  	uint32_t		*kdata;  	void __user		*user_ptr; -	int			last_copied_page; -	int			last_page_index;  };  struct radeon_cs_parser { @@ -989,6 +1023,7 @@ struct radeon_cs_parser {  	unsigned		nrelocs;  	struct radeon_cs_reloc	*relocs;  	struct radeon_cs_reloc	**relocs_ptr; +	struct radeon_cs_reloc	*vm_bos;  	struct list_head	validated;  	unsigned		dma_reloc_idx;  	/* indices of various chunks */ @@ -1007,8 +1042,15 @@ struct radeon_cs_parser {  	struct ww_acquire_ctx	ticket;  }; -extern int radeon_cs_finish_pages(struct radeon_cs_parser *p); -extern u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx); +static inline u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx) +{ +	struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; + +	if (ibc->kdata) +		return ibc->kdata[idx]; +	return p->ib.ptr[idx]; +} +  struct radeon_cs_packet {  	unsigned	idx; @@ -1231,6 +1273,17 @@ enum radeon_dpm_event_src {  	RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL = 4  }; +#define RADEON_MAX_VCE_LEVELS 6 + +enum radeon_vce_level { +	RADEON_VCE_LEVEL_AC_ALL = 0,     /* AC, All cases */ +	RADEON_VCE_LEVEL_DC_EE = 1,      /* DC, entropy encoding */ +	RADEON_VCE_LEVEL_DC_LL_LOW = 2,  /* DC, low latency queue, res <= 720 */ +	RADEON_VCE_LEVEL_DC_LL_HIGH = 3, /* DC, low latency queue, 1080 >= res > 720 */ +	RADEON_VCE_LEVEL_DC_GP_LOW = 4,  /* DC, general purpose queue, res <= 720 */ +	RADEON_VCE_LEVEL_DC_GP_HIGH = 5, /* DC, general purpose queue, 1080 >= res > 720 */ +}; +  struct radeon_ps {  	u32 caps; /* vbios flags */  	u32 class; /* vbios flags */ @@ -1241,6 +1294,8 @@ struct radeon_ps {  	/* VCE clocks */  	u32 evclk;  	u32 ecclk; +	bool vce_active; +	enum radeon_vce_level vce_level;  	/* asic priv */  	void *ps_priv;  }; @@ -1272,8 +1327,8 @@ struct radeon_blacklist_clocks  struct radeon_clock_and_voltage_limits {  	u32 sclk;  	u32 mclk; -	u32 vddc; -	u32 vddci; +	u16 vddc; +	u16 vddci;  };  struct radeon_clock_array { @@ -1415,6 +1470,17 @@ enum radeon_dpm_forced_level {  	RADEON_DPM_FORCED_LEVEL_HIGH = 2,  }; +struct radeon_vce_state { +	/* vce clocks */ +	u32 evclk; +	u32 ecclk; +	/* gpu clocks */ +	u32 sclk; +	u32 mclk; +	u8 clk_idx; +	u8 pstate; +}; +  struct radeon_dpm {  	struct radeon_ps        *ps;  	/* number of valid power states */ @@ -1427,6 +1493,9 @@ struct radeon_dpm {  	struct radeon_ps        *boot_ps;  	/* default uvd power state */  	struct radeon_ps        *uvd_ps; +	/* vce requirements */ +	struct radeon_vce_state vce_states[RADEON_MAX_VCE_LEVELS]; +	enum radeon_vce_level vce_level;  	enum radeon_pm_state_type state;  	enum radeon_pm_state_type user_state;  	u32                     platform_caps; @@ -1452,6 +1521,7 @@ struct radeon_dpm {  	/* special states active */  	bool                    thermal_active;  	bool                    uvd_active; +	bool                    vce_active;  	/* thermal handling */  	struct radeon_dpm_thermal thermal;  	/* forced levels */ @@ -1462,6 +1532,7 @@ struct radeon_dpm {  };  void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable); +void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable);  struct radeon_pm {  	struct mutex		mutex; @@ -1567,6 +1638,46 @@ int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev,  int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev,                                  unsigned cg_upll_func_cntl); +/* + * VCE + */ +#define RADEON_MAX_VCE_HANDLES	16 +#define RADEON_VCE_STACK_SIZE	(1024*1024) +#define RADEON_VCE_HEAP_SIZE	(4*1024*1024) + +struct radeon_vce { +	struct radeon_bo	*vcpu_bo; +	uint64_t		gpu_addr; +	unsigned		fw_version; +	unsigned		fb_version; +	atomic_t		handles[RADEON_MAX_VCE_HANDLES]; +	struct drm_file		*filp[RADEON_MAX_VCE_HANDLES]; +	unsigned		img_size[RADEON_MAX_VCE_HANDLES]; +	struct delayed_work	idle_work; +}; + +int radeon_vce_init(struct radeon_device *rdev); +void radeon_vce_fini(struct radeon_device *rdev); +int radeon_vce_suspend(struct radeon_device *rdev); +int radeon_vce_resume(struct radeon_device *rdev); +int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, +			      uint32_t handle, struct radeon_fence **fence); +int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, +			       uint32_t handle, struct radeon_fence **fence); +void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp); +void radeon_vce_note_usage(struct radeon_device *rdev); +int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, unsigned size); +int radeon_vce_cs_parse(struct radeon_cs_parser *p); +bool radeon_vce_semaphore_emit(struct radeon_device *rdev, +			       struct radeon_ring *ring, +			       struct radeon_semaphore *semaphore, +			       bool emit_wait); +void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); +void radeon_vce_fence_emit(struct radeon_device *rdev, +			   struct radeon_fence *fence); +int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); +int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); +  struct r600_audio_pin {  	int			channels;  	int			rate; @@ -1629,7 +1740,7 @@ struct radeon_asic_ring {  	/* command emmit functions */  	void (*ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib);  	void (*emit_fence)(struct radeon_device *rdev, struct radeon_fence *fence); -	void (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp, +	bool (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp,  			       struct radeon_semaphore *semaphore, bool emit_wait);  	void (*vm_flush)(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); @@ -1670,13 +1781,12 @@ struct radeon_asic {  	/* gart */  	struct {  		void (*tlb_flush)(struct radeon_device *rdev); -		int (*set_page)(struct radeon_device *rdev, int i, uint64_t addr); +		void (*set_page)(struct radeon_device *rdev, unsigned i, +				 uint64_t addr);  	} gart;  	struct {  		int (*init)(struct radeon_device *rdev);  		void (*fini)(struct radeon_device *rdev); - -		u32 pt_ring_index;  		void (*set_page)(struct radeon_device *rdev,  				 struct radeon_ib *ib,  				 uint64_t pe, @@ -1758,6 +1868,7 @@ struct radeon_asic {  		void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);  		void (*set_clock_gating)(struct radeon_device *rdev, int enable);  		int (*set_uvd_clocks)(struct radeon_device *rdev, u32 vclk, u32 dclk); +		int (*set_vce_clocks)(struct radeon_device *rdev, u32 evclk, u32 ecclk);  		int (*get_temperature)(struct radeon_device *rdev);  	} pm;  	/* dynamic power management */ @@ -1765,6 +1876,7 @@ struct radeon_asic {  		int (*init)(struct radeon_device *rdev);  		void (*setup_asic)(struct radeon_device *rdev);  		int (*enable)(struct radeon_device *rdev); +		int (*late_enable)(struct radeon_device *rdev);  		void (*disable)(struct radeon_device *rdev);  		int (*pre_set_power_state)(struct radeon_device *rdev);  		int (*set_power_state)(struct radeon_device *rdev); @@ -1782,9 +1894,8 @@ struct radeon_asic {  	} dpm;  	/* pageflipping */  	struct { -		void (*pre_page_flip)(struct radeon_device *rdev, int crtc); -		u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base); -		void (*post_page_flip)(struct radeon_device *rdev, int crtc); +		void (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base); +		bool (*page_flip_pending)(struct radeon_device *rdev, int crtc);  	} pflip;  }; @@ -1823,6 +1934,7 @@ struct r600_asic {  	unsigned		tiling_group_size;  	unsigned		tile_config;  	unsigned		backend_map; +	unsigned		active_simds;  };  struct rv770_asic { @@ -1848,6 +1960,7 @@ struct rv770_asic {  	unsigned		tiling_group_size;  	unsigned		tile_config;  	unsigned		backend_map; +	unsigned		active_simds;  };  struct evergreen_asic { @@ -1874,6 +1987,7 @@ struct evergreen_asic {  	unsigned tiling_group_size;  	unsigned tile_config;  	unsigned backend_map; +	unsigned active_simds;  };  struct cayman_asic { @@ -1912,6 +2026,7 @@ struct cayman_asic {  	unsigned multi_gpu_tile_size;  	unsigned tile_config; +	unsigned active_simds;  };  struct si_asic { @@ -1930,7 +2045,7 @@ struct si_asic {  	unsigned sc_earlyz_tile_fifo_size;  	unsigned num_tile_pipes; -	unsigned num_backends_per_se; +	unsigned backend_enable_mask;  	unsigned backend_disable_mask_per_asic;  	unsigned backend_map;  	unsigned num_texture_channel_caches; @@ -1942,6 +2057,7 @@ struct si_asic {  	unsigned tile_config;  	uint32_t tile_mode_array[32]; +	uint32_t active_cus;  };  struct cik_asic { @@ -1960,7 +2076,7 @@ struct cik_asic {  	unsigned sc_earlyz_tile_fifo_size;  	unsigned num_tile_pipes; -	unsigned num_backends_per_se; +	unsigned backend_enable_mask;  	unsigned backend_disable_mask_per_asic;  	unsigned backend_map;  	unsigned num_texture_channel_caches; @@ -1972,6 +2088,8 @@ struct cik_asic {  	unsigned tile_config;  	uint32_t tile_mode_array[32]; +	uint32_t macrotile_mode_array[16]; +	uint32_t active_cus;  };  union radeon_asic_config { @@ -2017,6 +2135,8 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,  			      struct drm_file *filp);  int radeon_gem_va_ioctl(struct drm_device *dev, void *data,  			  struct drm_file *filp); +int radeon_gem_op_ioctl(struct drm_device *dev, void *data, +			struct drm_file *filp);  int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);  int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,  				struct drm_file *filp); @@ -2162,6 +2282,7 @@ struct radeon_device {  	struct radeon_gem		gem;  	struct radeon_pm		pm;  	struct radeon_uvd		uvd; +	struct radeon_vce		vce;  	uint32_t			bios_scratch[RADEON_BIOS_NUM_SCRATCH];  	struct radeon_wb		wb;  	struct radeon_dummy_page	dummy_page; @@ -2170,6 +2291,7 @@ struct radeon_device {  	bool				need_dma32;  	bool				accel_working;  	bool				fastfb_working; /* IGP feature*/ +	bool				needs_reset;  	struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES];  	const struct firmware *me_fw;	/* all family ME firmware */  	const struct firmware *pfp_fw;	/* r6/700 PFP firmware */ @@ -2180,6 +2302,7 @@ struct radeon_device {  	const struct firmware *sdma_fw;	/* CIK SDMA firmware */  	const struct firmware *smc_fw;	/* SMC firmware */  	const struct firmware *uvd_fw;	/* UVD firmware */ +	const struct firmware *vce_fw;	/* VCE firmware */  	struct r600_vram_scratch vram_scratch;  	int msi_enabled; /* msi enabled */  	struct r600_ih ih; /* r6/700 interrupt ring */ @@ -2204,6 +2327,10 @@ struct radeon_device {  	/* virtual memory */  	struct radeon_vm_manager	vm_manager;  	struct mutex			gpu_clock_mutex; +	/* memory stats */ +	atomic64_t			vram_usage; +	atomic64_t			gtt_usage; +	atomic64_t			num_bytes_moved;  	/* ACPI interface */  	struct radeon_atif		atif;  	struct radeon_atcs		atcs; @@ -2212,8 +2339,12 @@ struct radeon_device {  	/* clock, powergating flags */  	u32 cg_flags;  	u32 pg_flags; + +	struct dev_pm_domain vga_pm_domain; +	bool have_disp_power_ref;  }; +bool radeon_is_px(struct drm_device *dev);  int radeon_device_init(struct radeon_device *rdev,  		       struct drm_device *ddev,  		       struct pci_dev *pdev, @@ -2228,8 +2359,8 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,  u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);  void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); -u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset); -void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v); +u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 index); +void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v);  /*   * Cast helper @@ -2292,8 +2423,8 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);  #define RREG32_IO(reg) r100_io_rreg(rdev, (reg))  #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v)) -#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset)) -#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v)) +#define RDOORBELL32(index) cik_mm_rdoorbell(rdev, (index)) +#define WDOORBELL32(index, v) cik_mm_wdoorbell(rdev, (index), (v))  /*   * Indirect registers accessor @@ -2524,6 +2655,10 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);  #define ASIC_IS_DCE64(rdev) ((rdev->family == CHIP_OLAND))  #define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN))  #define ASIC_IS_DCE8(rdev) ((rdev->family >= CHIP_BONAIRE)) +#define ASIC_IS_DCE81(rdev) ((rdev->family == CHIP_KAVERI)) +#define ASIC_IS_DCE82(rdev) ((rdev->family == CHIP_BONAIRE)) +#define ASIC_IS_DCE83(rdev) ((rdev->family == CHIP_KABINI) || \ +			     (rdev->family == CHIP_MULLINS))  #define ASIC_IS_LOMBOK(rdev) ((rdev->ddev->pdev->device == 0x6849) || \  			      (rdev->ddev->pdev->device == 0x6850) || \ @@ -2611,6 +2746,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);  #define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->pm.set_pcie_lanes((rdev), (l))  #define radeon_set_clock_gating(rdev, e) (rdev)->asic->pm.set_clock_gating((rdev), (e))  #define radeon_set_uvd_clocks(rdev, v, d) (rdev)->asic->pm.set_uvd_clocks((rdev), (v), (d)) +#define radeon_set_vce_clocks(rdev, ev, ec) (rdev)->asic->pm.set_vce_clocks((rdev), (ev), (ec))  #define radeon_get_temperature(rdev) (rdev)->asic->pm.get_temperature((rdev))  #define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->surface.set_reg((rdev), (r), (f), (p), (o), (s)))  #define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->surface.clear_reg((rdev), (r))) @@ -2625,9 +2761,8 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);  #define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev))  #define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev))  #define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm.get_dynpm_state((rdev)) -#define radeon_pre_page_flip(rdev, crtc) (rdev)->asic->pflip.pre_page_flip((rdev), (crtc))  #define radeon_page_flip(rdev, crtc, base) (rdev)->asic->pflip.page_flip((rdev), (crtc), (base)) -#define radeon_post_page_flip(rdev, crtc) (rdev)->asic->pflip.post_page_flip((rdev), (crtc)) +#define radeon_page_flip_pending(rdev, crtc) (rdev)->asic->pflip.page_flip_pending((rdev), (crtc))  #define radeon_wait_for_vblank(rdev, crtc) (rdev)->asic->display.wait_for_vblank((rdev), (crtc))  #define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))  #define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev)) @@ -2635,6 +2770,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);  #define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))  #define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))  #define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev)) +#define radeon_dpm_late_enable(rdev) rdev->asic->dpm.late_enable((rdev))  #define radeon_dpm_disable(rdev) rdev->asic->dpm.disable((rdev))  #define radeon_dpm_pre_set_power_state(rdev) rdev->asic->dpm.pre_set_power_state((rdev))  #define radeon_dpm_set_power_state(rdev) rdev->asic->dpm.set_power_state((rdev)) @@ -2653,6 +2789,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);  /* Common functions */  /* AGP */  extern int radeon_gpu_reset(struct radeon_device *rdev); +extern void radeon_pci_config_reset(struct radeon_device *rdev);  extern void r600_set_bios_scratch_engine_hung(struct radeon_device *rdev, bool hung);  extern void radeon_agp_disable(struct radeon_device *rdev);  extern int radeon_modeset_init(struct radeon_device *rdev); @@ -2673,8 +2810,8 @@ extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);  extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);  extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);  extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); -extern int radeon_resume_kms(struct drm_device *dev); -extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); +extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); +extern int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon);  extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size);  extern void radeon_program_register_sequence(struct radeon_device *rdev,  					     const u32 *registers, @@ -2685,20 +2822,27 @@ extern void radeon_program_register_sequence(struct radeon_device *rdev,   */  int radeon_vm_manager_init(struct radeon_device *rdev);  void radeon_vm_manager_fini(struct radeon_device *rdev); -void radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm); +int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm);  void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm); -int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm); -void radeon_vm_add_to_lru(struct radeon_device *rdev, struct radeon_vm *vm); +struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, +					  struct radeon_vm *vm, +                                          struct list_head *head);  struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,  				       struct radeon_vm *vm, int ring); +void radeon_vm_flush(struct radeon_device *rdev, +                     struct radeon_vm *vm, +                     int ring);  void radeon_vm_fence(struct radeon_device *rdev,  		     struct radeon_vm *vm,  		     struct radeon_fence *fence);  uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr); -int radeon_vm_bo_update_pte(struct radeon_device *rdev, -			    struct radeon_vm *vm, -			    struct radeon_bo *bo, -			    struct ttm_mem_reg *mem); +int radeon_vm_update_page_directory(struct radeon_device *rdev, +				    struct radeon_vm *vm); +int radeon_vm_clear_freed(struct radeon_device *rdev, +			  struct radeon_vm *vm); +int radeon_vm_bo_update(struct radeon_device *rdev, +			struct radeon_bo_va *bo_va, +			struct ttm_mem_reg *mem);  void radeon_vm_bo_invalidate(struct radeon_device *rdev,  			     struct radeon_bo *bo);  struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, @@ -2710,13 +2854,19 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,  			  struct radeon_bo_va *bo_va,  			  uint64_t offset,  			  uint32_t flags); -int radeon_vm_bo_rmv(struct radeon_device *rdev, -		     struct radeon_bo_va *bo_va); +void radeon_vm_bo_rmv(struct radeon_device *rdev, +		      struct radeon_bo_va *bo_va);  /* audio */  void r600_audio_update_hdmi(struct work_struct *work);  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 r600_audio_enable(struct radeon_device *rdev, +		       struct r600_audio_pin *pin, +		       bool enable); +void dce6_audio_enable(struct radeon_device *rdev, +		       struct r600_audio_pin *pin, +		       bool enable);  /*   * R600 vram scratch functions diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 10f98c7742d..77e9d07c55b 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -25,18 +25,14 @@  #include <linux/acpi.h>  #include <linux/slab.h>  #include <linux/power_supply.h> -#include <acpi/acpi_drivers.h> -#include <acpi/acpi_bus.h> +#include <linux/vga_switcheroo.h>  #include <acpi/video.h> -  #include <drm/drmP.h>  #include <drm/drm_crtc_helper.h>  #include "radeon.h"  #include "radeon_acpi.h"  #include "atom.h" -#include <linux/vga_switcheroo.h> -  #define ACPI_AC_CLASS           "ac_adapter"  extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); @@ -369,7 +365,7 @@ int radeon_atif_handler(struct radeon_device *rdev,  		return NOTIFY_DONE;  	/* Check pending SBIOS requests */ -	handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); +	handle = ACPI_HANDLE(&rdev->pdev->dev);  	count = radeon_atif_get_sbios_requests(handle, &req);  	if (count <= 0) @@ -556,7 +552,7 @@ int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev)  	struct radeon_atcs *atcs = &rdev->atcs;  	/* Get the device handle */ -	handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); +	handle = ACPI_HANDLE(&rdev->pdev->dev);  	if (!handle)  		return -EINVAL; @@ -596,7 +592,7 @@ int radeon_acpi_pcie_performance_request(struct radeon_device *rdev,  	u32 retry = 3;  	/* Get the device handle */ -	handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); +	handle = ACPI_HANDLE(&rdev->pdev->dev);  	if (!handle)  		return -EINVAL; @@ -699,7 +695,7 @@ int radeon_acpi_init(struct radeon_device *rdev)  	int ret;  	/* Get the device handle */ -	handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); +	handle = ACPI_HANDLE(&rdev->pdev->dev);  	/* No need to proceed if we're sure that ATIF is not supported */  	if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle) diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index 42433344cb1..a9297b2c352 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -117,9 +117,6 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = {  	/* ATI Host Bridge / RV280 [M9+] Needs AGPMode 1 (phoronix forum) */  	{ PCI_VENDOR_ID_ATI, 0xcbb2, PCI_VENDOR_ID_ATI, 0x5c61,  		PCI_VENDOR_ID_SONY, 0x8175, 1}, -	/* HP Host Bridge / R300 [FireGL X1] Needs AGPMode 2 (fdo #7770) */ -	{ PCI_VENDOR_ID_HP, 0x122e, PCI_VENDOR_ID_ATI, 0x4e47, -		PCI_VENDOR_ID_ATI, 0x0152, 2},  	{ 0, 0, 0, 0, 0, 0, 0 },  };  #endif diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 8f7e04538fd..34b9aa9e3c0 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -182,9 +182,9 @@ static struct radeon_asic_ring r100_gfx_ring = {  	.ring_test = &r100_ring_test,  	.ib_test = &r100_ib_test,  	.is_lockup = &r100_gpu_is_lockup, -	.get_rptr = &radeon_ring_generic_get_rptr, -	.get_wptr = &radeon_ring_generic_get_wptr, -	.set_wptr = &radeon_ring_generic_set_wptr, +	.get_rptr = &r100_gfx_get_rptr, +	.get_wptr = &r100_gfx_get_wptr, +	.set_wptr = &r100_gfx_set_wptr,  };  static struct radeon_asic r100_asic = { @@ -248,9 +248,8 @@ static struct radeon_asic r100_asic = {  		.set_clock_gating = &radeon_legacy_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &r100_pre_page_flip,  		.page_flip = &r100_page_flip, -		.post_page_flip = &r100_post_page_flip, +		.page_flip_pending = &r100_page_flip_pending,  	},  }; @@ -315,9 +314,8 @@ static struct radeon_asic r200_asic = {  		.set_clock_gating = &radeon_legacy_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &r100_pre_page_flip,  		.page_flip = &r100_page_flip, -		.post_page_flip = &r100_post_page_flip, +		.page_flip_pending = &r100_page_flip_pending,  	},  }; @@ -330,9 +328,9 @@ static struct radeon_asic_ring r300_gfx_ring = {  	.ring_test = &r100_ring_test,  	.ib_test = &r100_ib_test,  	.is_lockup = &r100_gpu_is_lockup, -	.get_rptr = &radeon_ring_generic_get_rptr, -	.get_wptr = &radeon_ring_generic_get_wptr, -	.set_wptr = &radeon_ring_generic_set_wptr, +	.get_rptr = &r100_gfx_get_rptr, +	.get_wptr = &r100_gfx_get_wptr, +	.set_wptr = &r100_gfx_set_wptr,  };  static struct radeon_asic r300_asic = { @@ -396,9 +394,8 @@ static struct radeon_asic r300_asic = {  		.set_clock_gating = &radeon_legacy_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &r100_pre_page_flip,  		.page_flip = &r100_page_flip, -		.post_page_flip = &r100_post_page_flip, +		.page_flip_pending = &r100_page_flip_pending,  	},  }; @@ -463,9 +460,8 @@ static struct radeon_asic r300_asic_pcie = {  		.set_clock_gating = &radeon_legacy_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &r100_pre_page_flip,  		.page_flip = &r100_page_flip, -		.post_page_flip = &r100_post_page_flip, +		.page_flip_pending = &r100_page_flip_pending,  	},  }; @@ -530,9 +526,8 @@ static struct radeon_asic r420_asic = {  		.set_clock_gating = &radeon_atom_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &r100_pre_page_flip,  		.page_flip = &r100_page_flip, -		.post_page_flip = &r100_post_page_flip, +		.page_flip_pending = &r100_page_flip_pending,  	},  }; @@ -597,9 +592,8 @@ static struct radeon_asic rs400_asic = {  		.set_clock_gating = &radeon_legacy_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &r100_pre_page_flip,  		.page_flip = &r100_page_flip, -		.post_page_flip = &r100_post_page_flip, +		.page_flip_pending = &r100_page_flip_pending,  	},  }; @@ -666,9 +660,8 @@ static struct radeon_asic rs600_asic = {  		.set_clock_gating = &radeon_atom_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &rs600_pre_page_flip,  		.page_flip = &rs600_page_flip, -		.post_page_flip = &rs600_post_page_flip, +		.page_flip_pending = &rs600_page_flip_pending,  	},  }; @@ -735,9 +728,8 @@ static struct radeon_asic rs690_asic = {  		.set_clock_gating = &radeon_atom_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &rs600_pre_page_flip,  		.page_flip = &rs600_page_flip, -		.post_page_flip = &rs600_post_page_flip, +		.page_flip_pending = &rs600_page_flip_pending,  	},  }; @@ -802,9 +794,8 @@ static struct radeon_asic rv515_asic = {  		.set_clock_gating = &radeon_atom_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &rs600_pre_page_flip,  		.page_flip = &rs600_page_flip, -		.post_page_flip = &rs600_post_page_flip, +		.page_flip_pending = &rs600_page_flip_pending,  	},  }; @@ -869,9 +860,8 @@ static struct radeon_asic r520_asic = {  		.set_clock_gating = &radeon_atom_set_clock_gating,  	},  	.pflip = { -		.pre_page_flip = &rs600_pre_page_flip,  		.page_flip = &rs600_page_flip, -		.post_page_flip = &rs600_post_page_flip, +		.page_flip_pending = &rs600_page_flip_pending,  	},  }; @@ -883,9 +873,9 @@ static struct radeon_asic_ring r600_gfx_ring = {  	.ring_test = &r600_ring_test,  	.ib_test = &r600_ib_test,  	.is_lockup = &r600_gfx_is_lockup, -	.get_rptr = &radeon_ring_generic_get_rptr, -	.get_wptr = &radeon_ring_generic_get_wptr, -	.set_wptr = &radeon_ring_generic_set_wptr, +	.get_rptr = &r600_gfx_get_rptr, +	.get_wptr = &r600_gfx_get_wptr, +	.set_wptr = &r600_gfx_set_wptr,  };  static struct radeon_asic_ring r600_dma_ring = { @@ -968,9 +958,8 @@ static struct radeon_asic r600_asic = {  		.get_temperature = &rv6xx_get_temp,  	},  	.pflip = { -		.pre_page_flip = &rs600_pre_page_flip,  		.page_flip = &rs600_page_flip, -		.post_page_flip = &rs600_post_page_flip, +		.page_flip_pending = &rs600_page_flip_pending,  	},  }; @@ -1045,6 +1034,7 @@ static struct radeon_asic rv6xx_asic = {  		.init = &rv6xx_dpm_init,  		.setup_asic = &rv6xx_setup_asic,  		.enable = &rv6xx_dpm_enable, +		.late_enable = &r600_dpm_late_enable,  		.disable = &rv6xx_dpm_disable,  		.pre_set_power_state = &r600_dpm_pre_set_power_state,  		.set_power_state = &rv6xx_dpm_set_power_state, @@ -1058,9 +1048,8 @@ static struct radeon_asic rv6xx_asic = {  		.force_performance_level = &rv6xx_dpm_force_performance_level,  	},  	.pflip = { -		.pre_page_flip = &rs600_pre_page_flip,  		.page_flip = &rs600_page_flip, -		.post_page_flip = &rs600_post_page_flip, +		.page_flip_pending = &rs600_page_flip_pending,  	},  }; @@ -1135,6 +1124,7 @@ static struct radeon_asic rs780_asic = {  		.init = &rs780_dpm_init,  		.setup_asic = &rs780_dpm_setup_asic,  		.enable = &rs780_dpm_enable, +		.late_enable = &r600_dpm_late_enable,  		.disable = &rs780_dpm_disable,  		.pre_set_power_state = &r600_dpm_pre_set_power_state,  		.set_power_state = &rs780_dpm_set_power_state, @@ -1148,9 +1138,8 @@ static struct radeon_asic rs780_asic = {  		.force_performance_level = &rs780_dpm_force_performance_level,  	},  	.pflip = { -		.pre_page_flip = &rs600_pre_page_flip,  		.page_flip = &rs600_page_flip, -		.post_page_flip = &rs600_post_page_flip, +		.page_flip_pending = &rs600_page_flip_pending,  	},  }; @@ -1199,7 +1188,7 @@ static struct radeon_asic rv770_asic = {  		.set_backlight_level = &atombios_set_backlight_level,  		.get_backlight_level = &atombios_get_backlight_level,  		.hdmi_enable = &r600_hdmi_enable, -		.hdmi_setmode = &r600_hdmi_setmode, +		.hdmi_setmode = &dce3_1_hdmi_setmode,  	},  	.copy = {  		.blit = &r600_copy_cpdma, @@ -1239,6 +1228,7 @@ static struct radeon_asic rv770_asic = {  		.init = &rv770_dpm_init,  		.setup_asic = &rv770_dpm_setup_asic,  		.enable = &rv770_dpm_enable, +		.late_enable = &rv770_dpm_late_enable,  		.disable = &rv770_dpm_disable,  		.pre_set_power_state = &r600_dpm_pre_set_power_state,  		.set_power_state = &rv770_dpm_set_power_state, @@ -1253,9 +1243,8 @@ static struct radeon_asic rv770_asic = {  		.vblank_too_short = &rv770_dpm_vblank_too_short,  	},  	.pflip = { -		.pre_page_flip = &rs600_pre_page_flip,  		.page_flip = &rv770_page_flip, -		.post_page_flip = &rs600_post_page_flip, +		.page_flip_pending = &rv770_page_flip_pending,  	},  }; @@ -1267,9 +1256,9 @@ static struct radeon_asic_ring evergreen_gfx_ring = {  	.ring_test = &r600_ring_test,  	.ib_test = &r600_ib_test,  	.is_lockup = &evergreen_gfx_is_lockup, -	.get_rptr = &radeon_ring_generic_get_rptr, -	.get_wptr = &radeon_ring_generic_get_wptr, -	.set_wptr = &radeon_ring_generic_set_wptr, +	.get_rptr = &r600_gfx_get_rptr, +	.get_wptr = &r600_gfx_get_wptr, +	.set_wptr = &r600_gfx_set_wptr,  };  static struct radeon_asic_ring evergreen_dma_ring = { @@ -1357,6 +1346,7 @@ static struct radeon_asic evergreen_asic = {  		.init = &cypress_dpm_init,  		.setup_asic = &cypress_dpm_setup_asic,  		.enable = &cypress_dpm_enable, +		.late_enable = &rv770_dpm_late_enable,  		.disable = &cypress_dpm_disable,  		.pre_set_power_state = &r600_dpm_pre_set_power_state,  		.set_power_state = &cypress_dpm_set_power_state, @@ -1371,9 +1361,8 @@ static struct radeon_asic evergreen_asic = {  		.vblank_too_short = &cypress_dpm_vblank_too_short,  	},  	.pflip = { -		.pre_page_flip = &evergreen_pre_page_flip,  		.page_flip = &evergreen_page_flip, -		.post_page_flip = &evergreen_post_page_flip, +		.page_flip_pending = &evergreen_page_flip_pending,  	},  }; @@ -1449,6 +1438,7 @@ static struct radeon_asic sumo_asic = {  		.init = &sumo_dpm_init,  		.setup_asic = &sumo_dpm_setup_asic,  		.enable = &sumo_dpm_enable, +		.late_enable = &sumo_dpm_late_enable,  		.disable = &sumo_dpm_disable,  		.pre_set_power_state = &sumo_dpm_pre_set_power_state,  		.set_power_state = &sumo_dpm_set_power_state, @@ -1462,9 +1452,8 @@ static struct radeon_asic sumo_asic = {  		.force_performance_level = &sumo_dpm_force_performance_level,  	},  	.pflip = { -		.pre_page_flip = &evergreen_pre_page_flip,  		.page_flip = &evergreen_page_flip, -		.post_page_flip = &evergreen_post_page_flip, +		.page_flip_pending = &evergreen_page_flip_pending,  	},  }; @@ -1540,6 +1529,7 @@ static struct radeon_asic btc_asic = {  		.init = &btc_dpm_init,  		.setup_asic = &btc_dpm_setup_asic,  		.enable = &btc_dpm_enable, +		.late_enable = &rv770_dpm_late_enable,  		.disable = &btc_dpm_disable,  		.pre_set_power_state = &btc_dpm_pre_set_power_state,  		.set_power_state = &btc_dpm_set_power_state, @@ -1549,14 +1539,13 @@ static struct radeon_asic btc_asic = {  		.get_sclk = &btc_dpm_get_sclk,  		.get_mclk = &btc_dpm_get_mclk,  		.print_power_state = &rv770_dpm_print_power_state, -		.debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, +		.debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level,  		.force_performance_level = &rv770_dpm_force_performance_level,  		.vblank_too_short = &btc_dpm_vblank_too_short,  	},  	.pflip = { -		.pre_page_flip = &evergreen_pre_page_flip,  		.page_flip = &evergreen_page_flip, -		.post_page_flip = &evergreen_post_page_flip, +		.page_flip_pending = &evergreen_page_flip_pending,  	},  }; @@ -1570,9 +1559,9 @@ static struct radeon_asic_ring cayman_gfx_ring = {  	.ib_test = &r600_ib_test,  	.is_lockup = &cayman_gfx_is_lockup,  	.vm_flush = &cayman_vm_flush, -	.get_rptr = &radeon_ring_generic_get_rptr, -	.get_wptr = &radeon_ring_generic_get_wptr, -	.set_wptr = &radeon_ring_generic_set_wptr, +	.get_rptr = &cayman_gfx_get_rptr, +	.get_wptr = &cayman_gfx_get_wptr, +	.set_wptr = &cayman_gfx_set_wptr,  };  static struct radeon_asic_ring cayman_dma_ring = { @@ -1585,9 +1574,9 @@ static struct radeon_asic_ring cayman_dma_ring = {  	.ib_test = &r600_dma_ib_test,  	.is_lockup = &cayman_dma_is_lockup,  	.vm_flush = &cayman_dma_vm_flush, -	.get_rptr = &r600_dma_get_rptr, -	.get_wptr = &r600_dma_get_wptr, -	.set_wptr = &r600_dma_set_wptr +	.get_rptr = &cayman_dma_get_rptr, +	.get_wptr = &cayman_dma_get_wptr, +	.set_wptr = &cayman_dma_set_wptr  };  static struct radeon_asic_ring cayman_uvd_ring = { @@ -1622,8 +1611,7 @@ static struct radeon_asic cayman_asic = {  	.vm = {  		.init = &cayman_vm_init,  		.fini = &cayman_vm_fini, -		.pt_ring_index = R600_RING_TYPE_DMA_INDEX, -		.set_page = &cayman_vm_set_page, +		.set_page = &cayman_dma_vm_set_page,  	},  	.ring = {  		[RADEON_RING_TYPE_GFX_INDEX] = &cayman_gfx_ring, @@ -1684,6 +1672,7 @@ static struct radeon_asic cayman_asic = {  		.init = &ni_dpm_init,  		.setup_asic = &ni_dpm_setup_asic,  		.enable = &ni_dpm_enable, +		.late_enable = &rv770_dpm_late_enable,  		.disable = &ni_dpm_disable,  		.pre_set_power_state = &ni_dpm_pre_set_power_state,  		.set_power_state = &ni_dpm_set_power_state, @@ -1698,9 +1687,8 @@ static struct radeon_asic cayman_asic = {  		.vblank_too_short = &ni_dpm_vblank_too_short,  	},  	.pflip = { -		.pre_page_flip = &evergreen_pre_page_flip,  		.page_flip = &evergreen_page_flip, -		.post_page_flip = &evergreen_post_page_flip, +		.page_flip_pending = &evergreen_page_flip_pending,  	},  }; @@ -1723,8 +1711,7 @@ static struct radeon_asic trinity_asic = {  	.vm = {  		.init = &cayman_vm_init,  		.fini = &cayman_vm_fini, -		.pt_ring_index = R600_RING_TYPE_DMA_INDEX, -		.set_page = &cayman_vm_set_page, +		.set_page = &cayman_dma_vm_set_page,  	},  	.ring = {  		[RADEON_RING_TYPE_GFX_INDEX] = &cayman_gfx_ring, @@ -1785,6 +1772,7 @@ static struct radeon_asic trinity_asic = {  		.init = &trinity_dpm_init,  		.setup_asic = &trinity_dpm_setup_asic,  		.enable = &trinity_dpm_enable, +		.late_enable = &trinity_dpm_late_enable,  		.disable = &trinity_dpm_disable,  		.pre_set_power_state = &trinity_dpm_pre_set_power_state,  		.set_power_state = &trinity_dpm_set_power_state, @@ -1799,9 +1787,8 @@ static struct radeon_asic trinity_asic = {  		.enable_bapm = &trinity_dpm_enable_bapm,  	},  	.pflip = { -		.pre_page_flip = &evergreen_pre_page_flip,  		.page_flip = &evergreen_page_flip, -		.post_page_flip = &evergreen_post_page_flip, +		.page_flip_pending = &evergreen_page_flip_pending,  	},  }; @@ -1815,9 +1802,9 @@ static struct radeon_asic_ring si_gfx_ring = {  	.ib_test = &r600_ib_test,  	.is_lockup = &si_gfx_is_lockup,  	.vm_flush = &si_vm_flush, -	.get_rptr = &radeon_ring_generic_get_rptr, -	.get_wptr = &radeon_ring_generic_get_wptr, -	.set_wptr = &radeon_ring_generic_set_wptr, +	.get_rptr = &cayman_gfx_get_rptr, +	.get_wptr = &cayman_gfx_get_wptr, +	.set_wptr = &cayman_gfx_set_wptr,  };  static struct radeon_asic_ring si_dma_ring = { @@ -1830,9 +1817,9 @@ static struct radeon_asic_ring si_dma_ring = {  	.ib_test = &r600_dma_ib_test,  	.is_lockup = &si_dma_is_lockup,  	.vm_flush = &si_dma_vm_flush, -	.get_rptr = &r600_dma_get_rptr, -	.get_wptr = &r600_dma_get_wptr, -	.set_wptr = &r600_dma_set_wptr, +	.get_rptr = &cayman_dma_get_rptr, +	.get_wptr = &cayman_dma_get_wptr, +	.set_wptr = &cayman_dma_set_wptr,  };  static struct radeon_asic si_asic = { @@ -1854,8 +1841,7 @@ static struct radeon_asic si_asic = {  	.vm = {  		.init = &si_vm_init,  		.fini = &si_vm_fini, -		.pt_ring_index = R600_RING_TYPE_DMA_INDEX, -		.set_page = &si_vm_set_page, +		.set_page = &si_dma_vm_set_page,  	},  	.ring = {  		[RADEON_RING_TYPE_GFX_INDEX] = &si_gfx_ring, @@ -1879,7 +1865,7 @@ static struct radeon_asic si_asic = {  		.hdmi_setmode = &evergreen_hdmi_setmode,  	},  	.copy = { -		.blit = NULL, +		.blit = &r600_copy_cpdma,  		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,  		.dma = &si_copy_dma,  		.dma_ring_index = R600_RING_TYPE_DMA_INDEX, @@ -1916,6 +1902,7 @@ static struct radeon_asic si_asic = {  		.init = &si_dpm_init,  		.setup_asic = &si_dpm_setup_asic,  		.enable = &si_dpm_enable, +		.late_enable = &si_dpm_late_enable,  		.disable = &si_dpm_disable,  		.pre_set_power_state = &si_dpm_pre_set_power_state,  		.set_power_state = &si_dpm_set_power_state, @@ -1930,9 +1917,8 @@ static struct radeon_asic si_asic = {  		.vblank_too_short = &ni_dpm_vblank_too_short,  	},  	.pflip = { -		.pre_page_flip = &evergreen_pre_page_flip,  		.page_flip = &evergreen_page_flip, -		.post_page_flip = &evergreen_post_page_flip, +		.page_flip_pending = &evergreen_page_flip_pending,  	},  }; @@ -1946,9 +1932,9 @@ static struct radeon_asic_ring ci_gfx_ring = {  	.ib_test = &cik_ib_test,  	.is_lockup = &cik_gfx_is_lockup,  	.vm_flush = &cik_vm_flush, -	.get_rptr = &radeon_ring_generic_get_rptr, -	.get_wptr = &radeon_ring_generic_get_wptr, -	.set_wptr = &radeon_ring_generic_set_wptr, +	.get_rptr = &cik_gfx_get_rptr, +	.get_wptr = &cik_gfx_get_wptr, +	.set_wptr = &cik_gfx_set_wptr,  };  static struct radeon_asic_ring ci_cp_ring = { @@ -1961,9 +1947,9 @@ static struct radeon_asic_ring ci_cp_ring = {  	.ib_test = &cik_ib_test,  	.is_lockup = &cik_gfx_is_lockup,  	.vm_flush = &cik_vm_flush, -	.get_rptr = &cik_compute_ring_get_rptr, -	.get_wptr = &cik_compute_ring_get_wptr, -	.set_wptr = &cik_compute_ring_set_wptr, +	.get_rptr = &cik_compute_get_rptr, +	.get_wptr = &cik_compute_get_wptr, +	.set_wptr = &cik_compute_set_wptr,  };  static struct radeon_asic_ring ci_dma_ring = { @@ -1976,9 +1962,22 @@ static struct radeon_asic_ring ci_dma_ring = {  	.ib_test = &cik_sdma_ib_test,  	.is_lockup = &cik_sdma_is_lockup,  	.vm_flush = &cik_dma_vm_flush, -	.get_rptr = &r600_dma_get_rptr, -	.get_wptr = &r600_dma_get_wptr, -	.set_wptr = &r600_dma_set_wptr, +	.get_rptr = &cik_sdma_get_rptr, +	.get_wptr = &cik_sdma_get_wptr, +	.set_wptr = &cik_sdma_set_wptr, +}; + +static struct radeon_asic_ring ci_vce_ring = { +	.ib_execute = &radeon_vce_ib_execute, +	.emit_fence = &radeon_vce_fence_emit, +	.emit_semaphore = &radeon_vce_semaphore_emit, +	.cs_parse = &radeon_vce_cs_parse, +	.ring_test = &radeon_vce_ring_test, +	.ib_test = &radeon_vce_ib_test, +	.is_lockup = &radeon_ring_test_lockup, +	.get_rptr = &vce_v1_0_get_rptr, +	.get_wptr = &vce_v1_0_get_wptr, +	.set_wptr = &vce_v1_0_set_wptr,  };  static struct radeon_asic ci_asic = { @@ -2000,8 +1999,7 @@ static struct radeon_asic ci_asic = {  	.vm = {  		.init = &cik_vm_init,  		.fini = &cik_vm_fini, -		.pt_ring_index = R600_RING_TYPE_DMA_INDEX, -		.set_page = &cik_vm_set_page, +		.set_page = &cik_sdma_vm_set_page,  	},  	.ring = {  		[RADEON_RING_TYPE_GFX_INDEX] = &ci_gfx_ring, @@ -2010,6 +2008,8 @@ static struct radeon_asic ci_asic = {  		[R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring,  		[CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring,  		[R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, +		[TN_RING_TYPE_VCE1_INDEX] = &ci_vce_ring, +		[TN_RING_TYPE_VCE2_INDEX] = &ci_vce_ring,  	},  	.irq = {  		.set = &cik_irq_set, @@ -2019,11 +2019,13 @@ static struct radeon_asic ci_asic = {  		.bandwidth_update = &dce8_bandwidth_update,  		.get_vblank_counter = &evergreen_get_vblank_counter,  		.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 = NULL, +		.blit = &cik_copy_cpdma,  		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,  		.dma = &cik_copy_dma,  		.dma_ring_index = R600_RING_TYPE_DMA_INDEX, @@ -2054,12 +2056,14 @@ static struct radeon_asic ci_asic = {  		.set_pcie_lanes = NULL,  		.set_clock_gating = NULL,  		.set_uvd_clocks = &cik_set_uvd_clocks, +		.set_vce_clocks = &cik_set_vce_clocks,  		.get_temperature = &ci_get_temp,  	},  	.dpm = {  		.init = &ci_dpm_init,  		.setup_asic = &ci_dpm_setup_asic,  		.enable = &ci_dpm_enable, +		.late_enable = &ci_dpm_late_enable,  		.disable = &ci_dpm_disable,  		.pre_set_power_state = &ci_dpm_pre_set_power_state,  		.set_power_state = &ci_dpm_set_power_state, @@ -2075,9 +2079,8 @@ static struct radeon_asic ci_asic = {  		.powergate_uvd = &ci_dpm_powergate_uvd,  	},  	.pflip = { -		.pre_page_flip = &evergreen_pre_page_flip,  		.page_flip = &evergreen_page_flip, -		.post_page_flip = &evergreen_post_page_flip, +		.page_flip_pending = &evergreen_page_flip_pending,  	},  }; @@ -2100,8 +2103,7 @@ static struct radeon_asic kv_asic = {  	.vm = {  		.init = &cik_vm_init,  		.fini = &cik_vm_fini, -		.pt_ring_index = R600_RING_TYPE_DMA_INDEX, -		.set_page = &cik_vm_set_page, +		.set_page = &cik_sdma_vm_set_page,  	},  	.ring = {  		[RADEON_RING_TYPE_GFX_INDEX] = &ci_gfx_ring, @@ -2110,6 +2112,8 @@ static struct radeon_asic kv_asic = {  		[R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring,  		[CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring,  		[R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, +		[TN_RING_TYPE_VCE1_INDEX] = &ci_vce_ring, +		[TN_RING_TYPE_VCE2_INDEX] = &ci_vce_ring,  	},  	.irq = {  		.set = &cik_irq_set, @@ -2119,11 +2123,13 @@ static struct radeon_asic kv_asic = {  		.bandwidth_update = &dce8_bandwidth_update,  		.get_vblank_counter = &evergreen_get_vblank_counter,  		.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 = NULL, +		.blit = &cik_copy_cpdma,  		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,  		.dma = &cik_copy_dma,  		.dma_ring_index = R600_RING_TYPE_DMA_INDEX, @@ -2154,12 +2160,14 @@ static struct radeon_asic kv_asic = {  		.set_pcie_lanes = NULL,  		.set_clock_gating = NULL,  		.set_uvd_clocks = &cik_set_uvd_clocks, +		.set_vce_clocks = &cik_set_vce_clocks,  		.get_temperature = &kv_get_temp,  	},  	.dpm = {  		.init = &kv_dpm_init,  		.setup_asic = &kv_dpm_setup_asic,  		.enable = &kv_dpm_enable, +		.late_enable = &kv_dpm_late_enable,  		.disable = &kv_dpm_disable,  		.pre_set_power_state = &kv_dpm_pre_set_power_state,  		.set_power_state = &kv_dpm_set_power_state, @@ -2175,9 +2183,8 @@ static struct radeon_asic kv_asic = {  		.enable_bapm = &kv_dpm_enable_bapm,  	},  	.pflip = { -		.pre_page_flip = &evergreen_pre_page_flip,  		.page_flip = &evergreen_page_flip, -		.post_page_flip = &evergreen_post_page_flip, +		.page_flip_pending = &evergreen_page_flip_pending,  	},  }; @@ -2442,30 +2449,52 @@ int radeon_asic_init(struct radeon_device *rdev)  		}  		break;  	case CHIP_BONAIRE: +	case CHIP_HAWAII:  		rdev->asic = &ci_asic;  		rdev->num_crtc = 6;  		rdev->has_uvd = true; -		rdev->cg_flags = -			RADEON_CG_SUPPORT_GFX_MGCG | -			RADEON_CG_SUPPORT_GFX_MGLS | -			/*RADEON_CG_SUPPORT_GFX_CGCG |*/ -			RADEON_CG_SUPPORT_GFX_CGLS | -			RADEON_CG_SUPPORT_GFX_CGTS | -			RADEON_CG_SUPPORT_GFX_CGTS_LS | -			RADEON_CG_SUPPORT_GFX_CP_LS | -			RADEON_CG_SUPPORT_MC_LS | -			RADEON_CG_SUPPORT_MC_MGCG | -			RADEON_CG_SUPPORT_SDMA_MGCG | -			RADEON_CG_SUPPORT_SDMA_LS | -			RADEON_CG_SUPPORT_BIF_LS | -			RADEON_CG_SUPPORT_VCE_MGCG | -			RADEON_CG_SUPPORT_UVD_MGCG | -			RADEON_CG_SUPPORT_HDP_LS | -			RADEON_CG_SUPPORT_HDP_MGCG; -		rdev->pg_flags = 0; +		if (rdev->family == CHIP_BONAIRE) { +			rdev->cg_flags = +				RADEON_CG_SUPPORT_GFX_MGCG | +				RADEON_CG_SUPPORT_GFX_MGLS | +				RADEON_CG_SUPPORT_GFX_CGCG | +				RADEON_CG_SUPPORT_GFX_CGLS | +				RADEON_CG_SUPPORT_GFX_CGTS | +				RADEON_CG_SUPPORT_GFX_CGTS_LS | +				RADEON_CG_SUPPORT_GFX_CP_LS | +				RADEON_CG_SUPPORT_MC_LS | +				RADEON_CG_SUPPORT_MC_MGCG | +				RADEON_CG_SUPPORT_SDMA_MGCG | +				RADEON_CG_SUPPORT_SDMA_LS | +				RADEON_CG_SUPPORT_BIF_LS | +				RADEON_CG_SUPPORT_VCE_MGCG | +				RADEON_CG_SUPPORT_UVD_MGCG | +				RADEON_CG_SUPPORT_HDP_LS | +				RADEON_CG_SUPPORT_HDP_MGCG; +			rdev->pg_flags = 0; +		} else { +			rdev->cg_flags = +				RADEON_CG_SUPPORT_GFX_MGCG | +				RADEON_CG_SUPPORT_GFX_MGLS | +				RADEON_CG_SUPPORT_GFX_CGCG | +				RADEON_CG_SUPPORT_GFX_CGLS | +				RADEON_CG_SUPPORT_GFX_CGTS | +				RADEON_CG_SUPPORT_GFX_CP_LS | +				RADEON_CG_SUPPORT_MC_LS | +				RADEON_CG_SUPPORT_MC_MGCG | +				RADEON_CG_SUPPORT_SDMA_MGCG | +				RADEON_CG_SUPPORT_SDMA_LS | +				RADEON_CG_SUPPORT_BIF_LS | +				RADEON_CG_SUPPORT_VCE_MGCG | +				RADEON_CG_SUPPORT_UVD_MGCG | +				RADEON_CG_SUPPORT_HDP_LS | +				RADEON_CG_SUPPORT_HDP_MGCG; +			rdev->pg_flags = 0; +		}  		break;  	case CHIP_KAVERI:  	case CHIP_KABINI: +	case CHIP_MULLINS:  		rdev->asic = &kv_asic;  		/* set num crtcs */  		if (rdev->family == CHIP_KAVERI) { @@ -2473,7 +2502,7 @@ int radeon_asic_init(struct radeon_device *rdev)  			rdev->cg_flags =  				RADEON_CG_SUPPORT_GFX_MGCG |  				RADEON_CG_SUPPORT_GFX_MGLS | -				/*RADEON_CG_SUPPORT_GFX_CGCG |*/ +				RADEON_CG_SUPPORT_GFX_CGCG |  				RADEON_CG_SUPPORT_GFX_CGLS |  				RADEON_CG_SUPPORT_GFX_CGTS |  				RADEON_CG_SUPPORT_GFX_CGTS_LS | @@ -2501,7 +2530,7 @@ int radeon_asic_init(struct radeon_device *rdev)  			rdev->cg_flags =  				RADEON_CG_SUPPORT_GFX_MGCG |  				RADEON_CG_SUPPORT_GFX_MGLS | -				/*RADEON_CG_SUPPORT_GFX_CGCG |*/ +				RADEON_CG_SUPPORT_GFX_CGCG |  				RADEON_CG_SUPPORT_GFX_CGLS |  				RADEON_CG_SUPPORT_GFX_CGTS |  				RADEON_CG_SUPPORT_GFX_CGTS_LS | diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 70c29d5e080..01e7c0ad8f0 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -47,13 +47,6 @@ u8 atombios_get_backlight_level(struct radeon_encoder *radeon_encoder);  void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level);  u8 radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder); -u32 radeon_ring_generic_get_rptr(struct radeon_device *rdev, -				 struct radeon_ring *ring); -u32 radeon_ring_generic_get_wptr(struct radeon_device *rdev, -				 struct radeon_ring *ring); -void radeon_ring_generic_set_wptr(struct radeon_device *rdev, -				  struct radeon_ring *ring); -  /*   * r100,rv100,rs100,rv200,rs200   */ @@ -74,13 +67,14 @@ 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); -int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, +			    uint64_t addr);  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);  void r100_fence_ring_emit(struct radeon_device *rdev,  			  struct radeon_fence *fence); -void r100_semaphore_ring_emit(struct radeon_device *rdev, +bool r100_semaphore_ring_emit(struct radeon_device *rdev,  			      struct radeon_ring *cp,  			      struct radeon_semaphore *semaphore,  			      bool emit_wait); @@ -142,12 +136,19 @@ extern void r100_pm_prepare(struct radeon_device *rdev);  extern void r100_pm_finish(struct radeon_device *rdev);  extern void r100_pm_init_profile(struct radeon_device *rdev);  extern void r100_pm_get_dynpm_state(struct radeon_device *rdev); -extern void r100_pre_page_flip(struct radeon_device *rdev, int crtc); -extern u32 r100_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); -extern void r100_post_page_flip(struct radeon_device *rdev, int crtc); +extern void r100_page_flip(struct radeon_device *rdev, int crtc, +			   u64 crtc_base); +extern bool r100_page_flip_pending(struct radeon_device *rdev, int crtc);  extern void r100_wait_for_vblank(struct radeon_device *rdev, int crtc);  extern int r100_mc_wait_for_idle(struct radeon_device *rdev); +u32 r100_gfx_get_rptr(struct radeon_device *rdev, +		      struct radeon_ring *ring); +u32 r100_gfx_get_wptr(struct radeon_device *rdev, +		      struct radeon_ring *ring); +void r100_gfx_set_wptr(struct radeon_device *rdev, +		       struct radeon_ring *ring); +  /*   * r200,rv250,rs300,rv280   */ @@ -171,7 +172,8 @@ 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 int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +extern void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, +				     uint64_t addr);  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); @@ -206,7 +208,8 @@ 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); -int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, +			 uint64_t addr);  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); @@ -229,7 +232,8 @@ 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); -int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, +			 uint64_t addr);  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); @@ -241,9 +245,9 @@ void rs600_hpd_set_polarity(struct radeon_device *rdev,  extern void rs600_pm_misc(struct radeon_device *rdev);  extern void rs600_pm_prepare(struct radeon_device *rdev);  extern void rs600_pm_finish(struct radeon_device *rdev); -extern void rs600_pre_page_flip(struct radeon_device *rdev, int crtc); -extern u32 rs600_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); -extern void rs600_post_page_flip(struct radeon_device *rdev, int crtc); +extern void rs600_page_flip(struct radeon_device *rdev, int crtc, +			    u64 crtc_base); +extern bool rs600_page_flip_pending(struct radeon_device *rdev, int crtc);  void rs600_set_safe_registers(struct radeon_device *rdev);  extern void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc);  extern int rs600_mc_wait_for_idle(struct radeon_device *rdev); @@ -313,13 +317,13 @@ int r600_cs_parse(struct radeon_cs_parser *p);  int r600_dma_cs_parse(struct radeon_cs_parser *p);  void r600_fence_ring_emit(struct radeon_device *rdev,  			  struct radeon_fence *fence); -void r600_semaphore_ring_emit(struct radeon_device *rdev, +bool r600_semaphore_ring_emit(struct radeon_device *rdev,  			      struct radeon_ring *cp,  			      struct radeon_semaphore *semaphore,  			      bool emit_wait);  void r600_dma_fence_ring_emit(struct radeon_device *rdev,  			      struct radeon_fence *fence); -void r600_dma_semaphore_ring_emit(struct radeon_device *rdev, +bool r600_dma_semaphore_ring_emit(struct radeon_device *rdev,  				  struct radeon_ring *ring,  				  struct radeon_semaphore *semaphore,  				  bool emit_wait); @@ -368,6 +372,12 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);  int r600_pcie_gart_init(struct radeon_device *rdev);  void r600_scratch_init(struct radeon_device *rdev);  int r600_init_microcode(struct radeon_device *rdev); +u32 r600_gfx_get_rptr(struct radeon_device *rdev, +		      struct radeon_ring *ring); +u32 r600_gfx_get_wptr(struct radeon_device *rdev, +		      struct radeon_ring *ring); +void r600_gfx_set_wptr(struct radeon_device *rdev, +		       struct radeon_ring *ring);  /* r600 irq */  int r600_irq_process(struct radeon_device *rdev);  int r600_irq_init(struct radeon_device *rdev); @@ -381,6 +391,11 @@ void r600_rlc_stop(struct radeon_device *rdev);  int r600_audio_init(struct radeon_device *rdev);  struct r600_audio_pin r600_audio_status(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, +				    size_t size); +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); @@ -392,6 +407,7 @@ int rv6xx_get_temp(struct radeon_device *rdev);  int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);  int r600_dpm_pre_set_power_state(struct radeon_device *rdev);  void r600_dpm_post_set_power_state(struct radeon_device *rdev); +int r600_dpm_late_enable(struct radeon_device *rdev);  /* r600 dma */  uint32_t r600_dma_get_rptr(struct radeon_device *rdev,  			   struct radeon_ring *ring); @@ -440,7 +456,8 @@ void rv770_fini(struct radeon_device *rdev);  int rv770_suspend(struct radeon_device *rdev);  int rv770_resume(struct radeon_device *rdev);  void rv770_pm_misc(struct radeon_device *rdev); -u32 rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); +void rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); +bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc);  void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);  void r700_cp_stop(struct radeon_device *rdev);  void r700_cp_fini(struct radeon_device *rdev); @@ -451,9 +468,12 @@ int 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); +int rv770_dpm_late_enable(struct radeon_device *rdev);  void rv770_dpm_disable(struct radeon_device *rdev);  int rv770_dpm_set_power_state(struct radeon_device *rdev);  void rv770_dpm_setup_asic(struct radeon_device *rdev); @@ -505,9 +525,9 @@ extern void sumo_pm_init_profile(struct radeon_device *rdev);  extern void btc_pm_init_profile(struct radeon_device *rdev);  int sumo_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);  int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); -extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc); -extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); -extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc); +extern void evergreen_page_flip(struct radeon_device *rdev, int crtc, +				u64 crtc_base); +extern bool evergreen_page_flip_pending(struct radeon_device *rdev, int crtc);  extern void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc);  void evergreen_disable_interrupt_state(struct radeon_device *rdev);  int evergreen_mc_wait_for_idle(struct radeon_device *rdev); @@ -543,8 +563,11 @@ void btc_dpm_fini(struct radeon_device *rdev);  u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low);  u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);  bool btc_dpm_vblank_too_short(struct radeon_device *rdev); +void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, +						     struct seq_file *m);  int sumo_dpm_init(struct radeon_device *rdev);  int sumo_dpm_enable(struct radeon_device *rdev); +int sumo_dpm_late_enable(struct radeon_device *rdev);  void sumo_dpm_disable(struct radeon_device *rdev);  int sumo_dpm_pre_set_power_state(struct radeon_device *rdev);  int sumo_dpm_set_power_state(struct radeon_device *rdev); @@ -566,10 +589,6 @@ int sumo_dpm_force_performance_level(struct radeon_device *rdev,   */  void cayman_fence_ring_emit(struct radeon_device *rdev,  			    struct radeon_fence *fence); -void cayman_uvd_semaphore_emit(struct radeon_device *rdev, -			       struct radeon_ring *ring, -			       struct radeon_semaphore *semaphore, -			       bool emit_wait);  void cayman_pcie_gart_tlb_flush(struct radeon_device *rdev);  int cayman_init(struct radeon_device *rdev);  void cayman_fini(struct radeon_device *rdev); @@ -581,19 +600,33 @@ int cayman_vm_init(struct radeon_device *rdev);  void cayman_vm_fini(struct radeon_device *rdev);  void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);  uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags); -void cayman_vm_set_page(struct radeon_device *rdev, -			struct radeon_ib *ib, -			uint64_t pe, -			uint64_t addr, unsigned count, -			uint32_t incr, uint32_t flags);  int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);  int evergreen_dma_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);  void cayman_dma_ring_ib_execute(struct radeon_device *rdev,  				struct radeon_ib *ib);  bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);  bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring); +void cayman_dma_vm_set_page(struct radeon_device *rdev, +			    struct radeon_ib *ib, +			    uint64_t pe, +			    uint64_t addr, unsigned count, +			    uint32_t incr, uint32_t flags); +  void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); +u32 cayman_gfx_get_rptr(struct radeon_device *rdev, +			struct radeon_ring *ring); +u32 cayman_gfx_get_wptr(struct radeon_device *rdev, +			struct radeon_ring *ring); +void cayman_gfx_set_wptr(struct radeon_device *rdev, +			 struct radeon_ring *ring); +uint32_t cayman_dma_get_rptr(struct radeon_device *rdev, +			     struct radeon_ring *ring); +uint32_t cayman_dma_get_wptr(struct radeon_device *rdev, +			     struct radeon_ring *ring); +void cayman_dma_set_wptr(struct radeon_device *rdev, +			 struct radeon_ring *ring); +  int ni_dpm_init(struct radeon_device *rdev);  void ni_dpm_setup_asic(struct radeon_device *rdev);  int ni_dpm_enable(struct radeon_device *rdev); @@ -613,6 +646,7 @@ int ni_dpm_force_performance_level(struct radeon_device *rdev,  bool ni_dpm_vblank_too_short(struct radeon_device *rdev);  int trinity_dpm_init(struct radeon_device *rdev);  int trinity_dpm_enable(struct radeon_device *rdev); +int trinity_dpm_late_enable(struct radeon_device *rdev);  void trinity_dpm_disable(struct radeon_device *rdev);  int trinity_dpm_pre_set_power_state(struct radeon_device *rdev);  int trinity_dpm_set_power_state(struct radeon_device *rdev); @@ -653,17 +687,17 @@ int si_irq_set(struct radeon_device *rdev);  int si_irq_process(struct radeon_device *rdev);  int si_vm_init(struct radeon_device *rdev);  void si_vm_fini(struct radeon_device *rdev); -void si_vm_set_page(struct radeon_device *rdev, -		    struct radeon_ib *ib, -		    uint64_t pe, -		    uint64_t addr, unsigned count, -		    uint32_t incr, uint32_t flags);  void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);  int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);  int si_copy_dma(struct radeon_device *rdev,  		uint64_t src_offset, uint64_t dst_offset,  		unsigned num_gpu_pages,  		struct radeon_fence **fence); +void si_dma_vm_set_page(struct radeon_device *rdev, +			struct radeon_ib *ib, +			uint64_t pe, +			uint64_t addr, unsigned count, +			uint32_t incr, uint32_t flags);  void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);  u32 si_get_xclk(struct radeon_device *rdev);  uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev); @@ -672,6 +706,7 @@ int si_get_temp(struct radeon_device *rdev);  int si_dpm_init(struct radeon_device *rdev);  void si_dpm_setup_asic(struct radeon_device *rdev);  int si_dpm_enable(struct radeon_device *rdev); +int si_dpm_late_enable(struct radeon_device *rdev);  void si_dpm_disable(struct radeon_device *rdev);  int si_dpm_pre_set_power_state(struct radeon_device *rdev);  int si_dpm_set_power_state(struct radeon_device *rdev); @@ -694,9 +729,10 @@ u32 cik_get_xclk(struct radeon_device *rdev);  uint32_t cik_pciep_rreg(struct radeon_device *rdev, uint32_t reg);  void cik_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);  int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); +int cik_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk);  void cik_sdma_fence_ring_emit(struct radeon_device *rdev,  			      struct radeon_fence *fence); -void cik_sdma_semaphore_ring_emit(struct radeon_device *rdev, +bool cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,  				  struct radeon_ring *ring,  				  struct radeon_semaphore *semaphore,  				  bool emit_wait); @@ -705,6 +741,10 @@ int cik_copy_dma(struct radeon_device *rdev,  		 uint64_t src_offset, uint64_t dst_offset,  		 unsigned num_gpu_pages,  		 struct radeon_fence **fence); +int cik_copy_cpdma(struct radeon_device *rdev, +		   uint64_t src_offset, uint64_t dst_offset, +		   unsigned num_gpu_pages, +		   struct radeon_fence **fence);  int cik_sdma_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);  int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);  bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring); @@ -712,7 +752,7 @@ void cik_fence_gfx_ring_emit(struct radeon_device *rdev,  			     struct radeon_fence *fence);  void cik_fence_compute_ring_emit(struct radeon_device *rdev,  				 struct radeon_fence *fence); -void cik_semaphore_ring_emit(struct radeon_device *rdev, +bool cik_semaphore_ring_emit(struct radeon_device *rdev,  			     struct radeon_ring *cp,  			     struct radeon_semaphore *semaphore,  			     bool emit_wait); @@ -731,24 +771,37 @@ int cik_irq_process(struct radeon_device *rdev);  int cik_vm_init(struct radeon_device *rdev);  void cik_vm_fini(struct radeon_device *rdev);  void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); -void cik_vm_set_page(struct radeon_device *rdev, -		     struct radeon_ib *ib, -		     uint64_t pe, -		     uint64_t addr, unsigned count, -		     uint32_t incr, uint32_t flags); +void cik_sdma_vm_set_page(struct radeon_device *rdev, +			  struct radeon_ib *ib, +			  uint64_t pe, +			  uint64_t addr, unsigned count, +			  uint32_t incr, uint32_t flags);  void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);  int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); -u32 cik_compute_ring_get_rptr(struct radeon_device *rdev, -			      struct radeon_ring *ring); -u32 cik_compute_ring_get_wptr(struct radeon_device *rdev, -			      struct radeon_ring *ring); -void cik_compute_ring_set_wptr(struct radeon_device *rdev, -			       struct radeon_ring *ring); +u32 cik_gfx_get_rptr(struct radeon_device *rdev, +		     struct radeon_ring *ring); +u32 cik_gfx_get_wptr(struct radeon_device *rdev, +		     struct radeon_ring *ring); +void cik_gfx_set_wptr(struct radeon_device *rdev, +		      struct radeon_ring *ring); +u32 cik_compute_get_rptr(struct radeon_device *rdev, +			 struct radeon_ring *ring); +u32 cik_compute_get_wptr(struct radeon_device *rdev, +			 struct radeon_ring *ring); +void cik_compute_set_wptr(struct radeon_device *rdev, +			  struct radeon_ring *ring); +u32 cik_sdma_get_rptr(struct radeon_device *rdev, +		      struct radeon_ring *ring); +u32 cik_sdma_get_wptr(struct radeon_device *rdev, +		      struct radeon_ring *ring); +void cik_sdma_set_wptr(struct radeon_device *rdev, +		       struct radeon_ring *ring);  int ci_get_temp(struct radeon_device *rdev);  int kv_get_temp(struct radeon_device *rdev);  int ci_dpm_init(struct radeon_device *rdev);  int ci_dpm_enable(struct radeon_device *rdev); +int ci_dpm_late_enable(struct radeon_device *rdev);  void ci_dpm_disable(struct radeon_device *rdev);  int ci_dpm_pre_set_power_state(struct radeon_device *rdev);  int ci_dpm_set_power_state(struct radeon_device *rdev); @@ -769,6 +822,7 @@ void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);  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);  void kv_dpm_disable(struct radeon_device *rdev);  int kv_dpm_pre_set_power_state(struct radeon_device *rdev);  int kv_dpm_set_power_state(struct radeon_device *rdev); @@ -802,7 +856,7 @@ void uvd_v1_0_stop(struct radeon_device *rdev);  int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);  int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); -void uvd_v1_0_semaphore_emit(struct radeon_device *rdev, +bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,  			     struct radeon_ring *ring,  			     struct radeon_semaphore *semaphore,  			     bool emit_wait); @@ -814,7 +868,7 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev,  			 struct radeon_fence *fence);  /* uvd v3.1 */ -void uvd_v3_1_semaphore_emit(struct radeon_device *rdev, +bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev,  			     struct radeon_ring *ring,  			     struct radeon_semaphore *semaphore,  			     bool emit_wait); @@ -822,4 +876,17 @@ void uvd_v3_1_semaphore_emit(struct radeon_device *rdev,  /* uvd v4.2 */  int uvd_v4_2_resume(struct radeon_device *rdev); +/* vce v1.0 */ +uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev, +			   struct radeon_ring *ring); +uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev, +			   struct radeon_ring *ring); +void vce_v1_0_set_wptr(struct radeon_device *rdev, +		       struct radeon_ring *ring); +int vce_v1_0_init(struct radeon_device *rdev); +int vce_v1_0_start(struct radeon_device *rdev); + +/* vce v2.0 */ +int vce_v2_0_resume(struct radeon_device *rdev); +  #endif diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f79ee184ffd..173f378428a 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -30,27 +30,10 @@  #include "atom.h"  #include "atom-bits.h" -/* from radeon_encoder.c */ -extern uint32_t -radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, -			uint8_t dac); -extern void radeon_link_encoder_connector(struct drm_device *dev);  extern void  radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum,  			uint32_t supported_device, u16 caps); -/* from radeon_connector.c */ -extern void -radeon_add_atom_connector(struct drm_device *dev, -			  uint32_t connector_id, -			  uint32_t supported_device, -			  int connector_type, -			  struct radeon_i2c_bus_rec *i2c_bus, -			  uint32_t igp_lane_info, -			  uint16_t connector_object_id, -			  struct radeon_hpd *hpd, -			  struct radeon_router *router); -  /* from radeon_legacy_encoder.c */  extern void  radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, @@ -1244,11 +1227,19 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)  			rdev->clock.default_dispclk =  				le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);  			if (rdev->clock.default_dispclk == 0) { -				if (ASIC_IS_DCE5(rdev)) +				if (ASIC_IS_DCE6(rdev)) +					rdev->clock.default_dispclk = 60000; /* 600 Mhz */ +				else if (ASIC_IS_DCE5(rdev))  					rdev->clock.default_dispclk = 54000; /* 540 Mhz */  				else  					rdev->clock.default_dispclk = 60000; /* 600 Mhz */  			} +			/* set a reasonable default for DP */ +			if (ASIC_IS_DCE6(rdev) && (rdev->clock.default_dispclk < 53900)) { +				DRM_INFO("Changing default dispclk from %dMhz to 600Mhz\n", +					 rdev->clock.default_dispclk / 100); +				rdev->clock.default_dispclk = 60000; +			}  			rdev->clock.dp_extclk =  				le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);  			rdev->clock.current_dispclk = rdev->clock.default_dispclk; @@ -1528,6 +1519,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,  						le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage);  					ss->type = ss_assign->v1.ucSpreadSpectrumMode;  					ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz); +					ss->percentage_divider = 100;  					return true;  				}  				ss_assign = (union asic_ss_assignment *) @@ -1545,6 +1537,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,  						le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage);  					ss->type = ss_assign->v2.ucSpreadSpectrumMode;  					ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz); +					ss->percentage_divider = 100;  					if ((crev == 2) &&  					    ((id == ASIC_INTERNAL_ENGINE_SS) ||  					     (id == ASIC_INTERNAL_MEMORY_SS))) @@ -1566,6 +1559,11 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,  						le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage);  					ss->type = ss_assign->v3.ucSpreadSpectrumMode;  					ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz); +					if (ss_assign->v3.ucSpreadSpectrumMode & +					    SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK) +						ss->percentage_divider = 1000; +					else +						ss->percentage_divider = 100;  					if ((id == ASIC_INTERNAL_ENGINE_SS) ||  					    (id == ASIC_INTERNAL_MEMORY_SS))  						ss->rate /= 100; @@ -1809,7 +1807,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,  		if (misc & ATOM_DOUBLE_CLOCK_MODE)  			mode->flags |= DRM_MODE_FLAG_DBLSCAN; -		mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10; +		mode->crtc_clock = mode->clock = +			le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;  		if (index == 1) {  			/* PAL timings appear to have wrong values for totals */ @@ -1852,7 +1851,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,  		if (misc & ATOM_DOUBLE_CLOCK_MODE)  			mode->flags |= DRM_MODE_FLAG_DBLSCAN; -		mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10; +		mode->crtc_clock = mode->clock = +			le16_to_cpu(dtd_timings->usPixClk) * 10;  		break;  	}  	return true; @@ -2918,7 +2918,7 @@ int radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev,  			mpll_param->dll_speed = args.ucDllSpeed;  			mpll_param->bwcntl = args.ucBWCntl;  			mpll_param->vco_mode = -				(args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK) ? 1 : 0; +				(args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK);  			mpll_param->yclk_sel =  				(args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0;  			mpll_param->qdr = @@ -3884,16 +3884,18 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,  							((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));  					}  					reg_table->last = i; -					while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) && +					while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) &&  					       (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) { -						t_mem_id = (u8)((*(u32 *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT); +						t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK) +								>> MEM_ID_SHIFT);  						if (module_index == t_mem_id) {  							reg_table->mc_reg_table_entry[num_ranges].mclk_max = -								(u32)((*(u32 *)reg_data & CLOCK_RANGE_MASK) >> CLOCK_RANGE_SHIFT); +								(u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK) +								      >> CLOCK_RANGE_SHIFT);  							for (i = 0, j = 1; i < reg_table->last; i++) {  								if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {  									reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = -										(u32)*((u32 *)reg_data + j); +										(u32)le32_to_cpu(*((u32 *)reg_data + j));  									j++;  								} else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {  									reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = @@ -3905,7 +3907,7 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,  						reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)  							((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));  					} -					if (*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) +					if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK)  						return -EINVAL;  					reg_table->num_entries = num_ranges;  				} else @@ -3944,6 +3946,10 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)  	/* tell the bios not to handle mode switching */  	bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH; +	/* clear the vbios dpms state */ +	if (ASIC_IS_DCE4(rdev)) +		bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE; +  	if (rdev->family >= CHIP_R600) {  		WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);  		WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index d96070bf838..a9fb0d016d3 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -8,8 +8,7 @@   */  #include <linux/vga_switcheroo.h>  #include <linux/slab.h> -#include <acpi/acpi.h> -#include <acpi/acpi_bus.h> +#include <linux/acpi.h>  #include <linux/pci.h>  #include "radeon_acpi.h" @@ -34,6 +33,7 @@ static struct radeon_atpx_priv {  	bool atpx_detected;  	/* handle for device - and atpx */  	acpi_handle dhandle; +	acpi_handle other_handle;  	struct radeon_atpx atpx;  } radeon_atpx_priv; @@ -59,6 +59,10 @@ struct atpx_mux {  	u16 mux;  } __packed; +bool radeon_has_atpx(void) { +	return radeon_atpx_priv.atpx_detected; +} +  /**   * radeon_atpx_call - call an ATPX method   * @@ -215,7 +219,8 @@ static int radeon_atpx_verify_interface(struct radeon_atpx *atpx)  	memcpy(&output, info->buffer.pointer, size);  	/* TODO: check version? */ -	printk("ATPX version %u\n", output.version); +	printk("ATPX version %u, functions 0x%08x\n", +	       output.version, output.function_bits);  	radeon_atpx_parse_functions(&atpx->functions, output.function_bits); @@ -443,14 +448,15 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)  	acpi_handle dhandle, atpx_handle;  	acpi_status status; -	dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); +	dhandle = ACPI_HANDLE(&pdev->dev);  	if (!dhandle)  		return false;  	status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); -	if (ACPI_FAILURE(status)) +	if (ACPI_FAILURE(status)) { +		radeon_atpx_priv.other_handle = dhandle;  		return false; - +	}  	radeon_atpx_priv.dhandle = dhandle;  	radeon_atpx_priv.atpx.handle = atpx_handle;  	return true; @@ -489,7 +495,7 @@ static int radeon_atpx_init(void)   */  static int radeon_atpx_get_client_id(struct pci_dev *pdev)  { -	if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) +	if (radeon_atpx_priv.dhandle == ACPI_HANDLE(&pdev->dev))  		return VGA_SWITCHEROO_IGD;  	else  		return VGA_SWITCHEROO_DIS; @@ -522,11 +528,28 @@ static bool radeon_atpx_detect(void)  		has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);  	} +	/* some newer PX laptops mark the dGPU as a non-VGA display device */ +	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { +		vga_count++; + +		has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true); +	} +  	if (has_atpx && vga_count == 2) {  		acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);  		printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",  		       acpi_method_name);  		radeon_atpx_priv.atpx_detected = true; +		/* +		 * On some systems hotplug events are generated for the device +		 * being switched off when ATPX is executed.  They cause ACPI +		 * hotplug to trigger and attempt to remove the device from +		 * the system, which causes it to break down.  Prevent that from +		 * happening by setting the no_hotplug flag for the involved +		 * ACPI device objects. +		 */ +		acpi_bus_no_hotplug(radeon_atpx_priv.dhandle); +		acpi_bus_no_hotplug(radeon_atpx_priv.other_handle);  		return true;  	}  	return false; diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 061b227dae0..6a03624fada 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -185,7 +185,7 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)  		return false;  	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { -		dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); +		dhandle = ACPI_HANDLE(&pdev->dev);  		if (!dhandle)  			continue; @@ -196,6 +196,20 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)  		}  	} +	if (!found) { +		while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { +			dhandle = ACPI_HANDLE(&pdev->dev); +			if (!dhandle) +				continue; + +			status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); +			if (!ACPI_FAILURE(status)) { +				found = true; +				break; +			} +		} +	} +  	if (!found)  		return false; @@ -499,7 +513,7 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)  	crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);  	fp2_gen_cntl = 0; -	if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) { +	if (rdev->ddev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {  		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);  	} @@ -536,7 +550,7 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)  		(RADEON_CRTC_SYNC_TRISTAT |  		 RADEON_CRTC_DISPLAY_DIS))); -	if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) { +	if (rdev->ddev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {  		WREG32(RADEON_FP2_GEN_CNTL, (fp2_gen_cntl & ~RADEON_FP2_ON));  	} @@ -554,7 +568,7 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)  		WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);  	}  	WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); -	if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) { +	if (rdev->ddev->pdev->device == PCI_DEVICE_ID_ATI_RADEON_QY) {  		WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);  	}  	return r; @@ -612,7 +626,7 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)  	    vhdr->DeviceID != rdev->pdev->device) {  		DRM_INFO("ACPI VFCT table is not for this card\n");  		goto out_unmap; -	}; +	}  	if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) {  		DRM_ERROR("ACPI VFCT image truncated\n"); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 68ce3605601..6651177110f 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -37,22 +37,6 @@  #include <asm/pci-bridge.h>  #endif /* CONFIG_PPC_PMAC */ -/* from radeon_encoder.c */ -extern uint32_t -radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, -			uint8_t dac); -extern void radeon_link_encoder_connector(struct drm_device *dev); - -/* from radeon_connector.c */ -extern void -radeon_add_legacy_connector(struct drm_device *dev, -			    uint32_t connector_id, -			    uint32_t supported_device, -			    int connector_type, -			    struct radeon_i2c_bus_rec *i2c_bus, -			    uint16_t connector_object_id, -			    struct radeon_hpd *hpd); -  /* from radeon_legacy_encoder.c */  extern void  radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 79159b5da05..44831197e82 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -31,14 +31,7 @@  #include "radeon.h"  #include "atom.h" -extern void -radeon_combios_connected_scratch_regs(struct drm_connector *connector, -				      struct drm_encoder *encoder, -				      bool connected); -extern void -radeon_atombios_connected_scratch_regs(struct drm_connector *connector, -				       struct drm_encoder *encoder, -				       bool connected); +#include <linux/pm_runtime.h>  void radeon_connector_hotplug(struct drm_connector *connector)  { @@ -55,6 +48,7 @@ void radeon_connector_hotplug(struct drm_connector *connector)  	radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);  	/* if the connector is already off, don't turn it back on */ +	/* FIXME: This access isn't protected by any locks. */  	if (connector->dpms != DRM_MODE_DPMS_ON)  		return; @@ -96,7 +90,7 @@ static void radeon_property_change_mode(struct drm_encoder *encoder)  	if (crtc && crtc->enabled) {  		drm_crtc_helper_set_mode(crtc, &crtc->mode, -					 crtc->x, crtc->y, crtc->fb); +					 crtc->x, crtc->y, crtc->primary->fb);  	}  } @@ -107,6 +101,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)  	struct radeon_connector *radeon_connector = to_radeon_connector(connector);  	struct radeon_connector_atom_dig *dig_connector;  	int bpc = 8; +	int mode_clock, max_tmds_clock;  	switch (connector->connector_type) {  	case DRM_MODE_CONNECTOR_DVII: @@ -152,6 +147,64 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)  		}  		break;  	} + +	if (drm_detect_hdmi_monitor(radeon_connector->edid)) { +		/* hdmi deep color only implemented on DCE4+ */ +		if ((bpc > 8) && !ASIC_IS_DCE4(rdev)) { +			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 8 bpc.\n", +					  connector->name, bpc); +			bpc = 8; +		} + +		/* +		 * Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make +		 * much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at +		 * 12 bpc is always supported on hdmi deep color sinks, as this is +		 * required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum. +		 */ +		if (bpc > 12) { +			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n", +					  connector->name, bpc); +			bpc = 12; +		} + +		/* Any defined maximum tmds clock limit we must not exceed? */ +		if (connector->max_tmds_clock > 0) { +			/* mode_clock is clock in kHz for mode to be modeset on this connector */ +			mode_clock = radeon_connector->pixelclock_for_modeset; + +			/* Maximum allowable input clock in kHz */ +			max_tmds_clock = connector->max_tmds_clock * 1000; + +			DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", +					  connector->name, mode_clock, max_tmds_clock); + +			/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ +			if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { +				if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && +					(mode_clock * 5/4 <= max_tmds_clock)) +					bpc = 10; +				else +					bpc = 8; + +				DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n", +						  connector->name, bpc); +			} + +			if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) { +				bpc = 8; +				DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n", +						  connector->name, bpc); +			} +		} +	} + +	if ((radeon_deep_color == 0) && (bpc > 8)) +		bpc = 8; + +	DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n", +			  connector->name, connector->display_info.bpc, bpc); +  	return bpc;  } @@ -267,13 +320,17 @@ radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,  					continue;  				if (priority == true) { -					DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict)); -					DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(connector)); +					DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", +						      conflict->name); +					DRM_DEBUG_KMS("in favor of %s\n", +						      connector->name);  					conflict->status = connector_status_disconnected;  					radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);  				} else { -					DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector)); -					DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(conflict)); +					DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", +						      connector->name); +					DRM_DEBUG_KMS("in favor of %s\n", +						      conflict->name);  					current_status = connector_status_disconnected;  				}  				break; @@ -411,6 +468,21 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct  		}  	} +	if (property == rdev->mode_info.dither_property) { +		struct radeon_connector *radeon_connector = to_radeon_connector(connector); +		/* need to find digital encoder on connector */ +		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); +		if (!encoder) +			return 0; + +		radeon_encoder = to_radeon_encoder(encoder); + +		if (radeon_connector->dither != val) { +			radeon_connector->dither = val; +			radeon_property_change_mode(&radeon_encoder->base); +		} +	} +  	if (property == rdev->mode_info.underscan_property) {  		/* need to find digital encoder on connector */  		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); @@ -626,6 +698,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)  	struct radeon_connector *radeon_connector = to_radeon_connector(connector);  	struct drm_encoder *encoder = radeon_best_single_encoder(connector);  	enum drm_connector_status ret = connector_status_disconnected; +	int r; + +	r = pm_runtime_get_sync(connector->dev->dev); +	if (r < 0) +		return connector_status_disconnected;  	if (encoder) {  		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -651,6 +728,8 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)  	/* check acpi lid status ??? */  	radeon_connector_update_scratch_regs(connector, ret); +	pm_runtime_mark_last_busy(connector->dev->dev); +	pm_runtime_put_autosuspend(connector->dev->dev);  	return ret;  } @@ -750,6 +829,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force)  	struct drm_encoder_helper_funcs *encoder_funcs;  	bool dret = false;  	enum drm_connector_status ret = connector_status_disconnected; +	int r; + +	r = pm_runtime_get_sync(connector->dev->dev); +	if (r < 0) +		return connector_status_disconnected;  	encoder = radeon_best_single_encoder(connector);  	if (!encoder) @@ -767,7 +851,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force)  		if (!radeon_connector->edid) {  			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", -					drm_get_connector_name(connector)); +					connector->name);  			ret = connector_status_connected;  		} else {  			radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); @@ -790,9 +874,8 @@ radeon_vga_detect(struct drm_connector *connector, bool force)  			 * detected a monitor via load.  			 */  			if (radeon_connector->detected_by_load) -				return connector->status; -			else -				return ret; +				ret = connector->status; +			goto out;  		}  		if (radeon_connector->dac_load_detect && encoder) { @@ -817,6 +900,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force)  	}  	radeon_connector_update_scratch_regs(connector, ret); + +out: +	pm_runtime_mark_last_busy(connector->dev->dev); +	pm_runtime_put_autosuspend(connector->dev->dev); +  	return ret;  } @@ -873,10 +961,15 @@ radeon_tv_detect(struct drm_connector *connector, bool force)  	struct drm_encoder_helper_funcs *encoder_funcs;  	struct radeon_connector *radeon_connector = to_radeon_connector(connector);  	enum drm_connector_status ret = connector_status_disconnected; +	int r;  	if (!radeon_connector->dac_load_detect)  		return ret; +	r = pm_runtime_get_sync(connector->dev->dev); +	if (r < 0) +		return connector_status_disconnected; +  	encoder = radeon_best_single_encoder(connector);  	if (!encoder)  		ret = connector_status_disconnected; @@ -887,6 +980,8 @@ radeon_tv_detect(struct drm_connector *connector, bool force)  	if (ret == connector_status_connected)  		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);  	radeon_connector_update_scratch_regs(connector, ret); +	pm_runtime_mark_last_busy(connector->dev->dev); +	pm_runtime_put_autosuspend(connector->dev->dev);  	return ret;  } @@ -954,12 +1049,18 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)  	struct drm_encoder *encoder = NULL;  	struct drm_encoder_helper_funcs *encoder_funcs;  	struct drm_mode_object *obj; -	int i; +	int i, r;  	enum drm_connector_status ret = connector_status_disconnected;  	bool dret = false, broken_edid = false; -	if (!force && radeon_check_hpd_status_unchanged(connector)) -		return connector->status; +	r = pm_runtime_get_sync(connector->dev->dev); +	if (r < 0) +		return connector_status_disconnected; + +	if (!force && radeon_check_hpd_status_unchanged(connector)) { +		ret = connector->status; +		goto exit; +	}  	if (radeon_connector->ddc_bus)  		dret = radeon_ddc_probe(radeon_connector, false); @@ -973,12 +1074,13 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)  		if (!radeon_connector->edid) {  			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", -					drm_get_connector_name(connector)); +					connector->name);  			/* rs690 seems to have a problem with connectors not existing and always  			 * return a block of 0's. If we see this just stop polling on this output */  			if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && radeon_connector->base.null_edid_counter) {  				ret = connector_status_disconnected; -				DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", drm_get_connector_name(connector)); +				DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", +					  connector->name);  				radeon_connector->ddc_bus = NULL;  			} else {  				ret = connector_status_connected; @@ -1110,6 +1212,11 @@ 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); + +exit: +	pm_runtime_mark_last_busy(connector->dev->dev); +	pm_runtime_put_autosuspend(connector->dev->dev); +  	return ret;  } @@ -1184,17 +1291,15 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector,  		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||  		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))  			return MODE_OK; -		else if (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_A) { -			if (ASIC_IS_DCE6(rdev)) { -				/* HDMI 1.3+ supports max clock of 340 Mhz */ -				if (mode->clock > 340000) -					return MODE_CLOCK_HIGH; -				else -					return MODE_OK; -			} else +		else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { +			/* HDMI 1.3+ supports max clock of 340 Mhz */ +			if (mode->clock > 340000)  				return MODE_CLOCK_HIGH; -		} else +			else +				return MODE_OK; +		} else {  			return MODE_CLOCK_HIGH; +		}  	}  	/* check against the max pixel clock */ @@ -1219,21 +1324,6 @@ static const struct drm_connector_funcs radeon_dvi_connector_funcs = {  	.force = radeon_dvi_force,  }; -static void radeon_dp_connector_destroy(struct drm_connector *connector) -{ -	struct radeon_connector *radeon_connector = to_radeon_connector(connector); -	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - -	if (radeon_connector->edid) -		kfree(radeon_connector->edid); -	if (radeon_dig_connector->dp_i2c_bus) -		radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); -	kfree(radeon_connector->con_priv); -	drm_sysfs_connector_remove(connector); -	drm_connector_cleanup(connector); -	kfree(connector); -} -  static int radeon_dp_get_modes(struct drm_connector *connector)  {  	struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -1360,7 +1450,7 @@ bool radeon_connector_is_dp12_capable(struct drm_connector *connector)  	struct radeon_device *rdev = dev->dev_private;  	if (ASIC_IS_DCE5(rdev) && -	    (rdev->clock.dp_extclk >= 53900) && +	    (rdev->clock.default_dispclk >= 53900) &&  	    radeon_connector_encoder_is_hbr2(connector)) {  		return true;  	} @@ -1377,9 +1467,16 @@ radeon_dp_detect(struct drm_connector *connector, bool force)  	enum drm_connector_status ret = connector_status_disconnected;  	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;  	struct drm_encoder *encoder = radeon_best_single_encoder(connector); +	int r; -	if (!force && radeon_check_hpd_status_unchanged(connector)) -		return connector->status; +	r = pm_runtime_get_sync(connector->dev->dev); +	if (r < 0) +		return connector_status_disconnected; + +	if (!force && radeon_check_hpd_status_unchanged(connector)) { +		ret = connector->status; +		goto out; +	}  	if (radeon_connector->edid) {  		kfree(radeon_connector->edid); @@ -1443,12 +1540,18 @@ radeon_dp_detect(struct drm_connector *connector, bool force)  	}  	radeon_connector_update_scratch_regs(connector, ret); +out: +	pm_runtime_mark_last_busy(connector->dev->dev); +	pm_runtime_put_autosuspend(connector->dev->dev); +  	return ret;  }  static int radeon_dp_mode_valid(struct drm_connector *connector,  				  struct drm_display_mode *mode)  { +	struct drm_device *dev = connector->dev; +	struct radeon_device *rdev = dev->dev_private;  	struct radeon_connector *radeon_connector = to_radeon_connector(connector);  	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; @@ -1479,14 +1582,23 @@ static int radeon_dp_mode_valid(struct drm_connector *connector,  					return MODE_PANEL;  			}  		} -		return MODE_OK;  	} else {  		if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || -		    (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) +		    (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {  			return radeon_dp_mode_valid_helper(connector, mode); -		else -			return MODE_OK; +		} else { +			if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { +				/* HDMI 1.3+ supports max clock of 340 Mhz */ +				if (mode->clock > 340000) +					return MODE_CLOCK_HIGH; +			} else { +				if (mode->clock > 165000) +					return MODE_CLOCK_HIGH; +			} +		}  	} + +	return MODE_OK;  }  static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { @@ -1500,7 +1612,7 @@ static const struct drm_connector_funcs radeon_dp_connector_funcs = {  	.detect = radeon_dp_detect,  	.fill_modes = drm_helper_probe_single_connector_modes,  	.set_property = radeon_connector_set_property, -	.destroy = radeon_dp_connector_destroy, +	.destroy = radeon_connector_destroy,  	.force = radeon_dvi_force,  }; @@ -1509,7 +1621,7 @@ static const struct drm_connector_funcs radeon_edp_connector_funcs = {  	.detect = radeon_dp_detect,  	.fill_modes = drm_helper_probe_single_connector_modes,  	.set_property = radeon_lvds_set_property, -	.destroy = radeon_dp_connector_destroy, +	.destroy = radeon_connector_destroy,  	.force = radeon_dvi_force,  }; @@ -1518,7 +1630,7 @@ static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {  	.detect = radeon_dp_detect,  	.fill_modes = drm_helper_probe_single_connector_modes,  	.set_property = radeon_lvds_set_property, -	.destroy = radeon_dp_connector_destroy, +	.destroy = radeon_connector_destroy,  	.force = radeon_dvi_force,  }; @@ -1542,6 +1654,7 @@ radeon_add_atom_connector(struct drm_device *dev,  	uint32_t subpixel_order = SubPixelNone;  	bool shared_ddc = false;  	bool is_dp_bridge = false; +	bool has_aux = false;  	if (connector_type == DRM_MODE_CONNECTOR_Unknown)  		return; @@ -1614,15 +1727,10 @@ radeon_add_atom_connector(struct drm_device *dev,  		radeon_dig_connector->igp_lane_info = igp_lane_info;  		radeon_connector->con_priv = radeon_dig_connector;  		if (i2c_bus->valid) { -			/* add DP i2c bus */ -			if (connector_type == DRM_MODE_CONNECTOR_eDP) -				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); -			else -				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); -			if (!radeon_dig_connector->dp_i2c_bus) -				DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");  			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); -			if (!radeon_connector->ddc_bus) +			if (radeon_connector->ddc_bus) +				has_aux = true; +			else  				DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");  		}  		switch (connector_type) { @@ -1658,9 +1766,16 @@ radeon_add_atom_connector(struct drm_device *dev,  			drm_object_attach_property(&radeon_connector->base.base,  						      rdev->mode_info.underscan_vborder_property,  						      0); +  			drm_object_attach_property(&radeon_connector->base.base, -						   rdev->mode_info.audio_property, -						   RADEON_AUDIO_DISABLE); +						   rdev->mode_info.dither_property, +						   RADEON_FMT_DITHER_DISABLE); + +			if (radeon_audio != 0) +				drm_object_attach_property(&radeon_connector->base.base, +							   rdev->mode_info.audio_property, +							   RADEON_AUDIO_AUTO); +  			subpixel_order = SubPixelHorizontalRGB;  			connector->interlace_allowed = true;  			if (connector_type == DRM_MODE_CONNECTOR_HDMIB) @@ -1754,10 +1869,15 @@ radeon_add_atom_connector(struct drm_device *dev,  							      rdev->mode_info.underscan_vborder_property,  							      0);  			} -			if (ASIC_IS_DCE2(rdev)) { +			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { +				drm_object_attach_property(&radeon_connector->base.base, +							   rdev->mode_info.audio_property, +							   RADEON_AUDIO_AUTO); +			} +			if (ASIC_IS_AVIVO(rdev)) {  				drm_object_attach_property(&radeon_connector->base.base, -							      rdev->mode_info.audio_property, -							      RADEON_AUDIO_DISABLE); +							   rdev->mode_info.dither_property, +							   RADEON_FMT_DITHER_DISABLE);  			}  			if (connector_type == DRM_MODE_CONNECTOR_DVII) {  				radeon_connector->dac_load_detect = true; @@ -1799,10 +1919,15 @@ radeon_add_atom_connector(struct drm_device *dev,  							      rdev->mode_info.underscan_vborder_property,  							      0);  			} -			if (ASIC_IS_DCE2(rdev)) { +			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {  				drm_object_attach_property(&radeon_connector->base.base, -							      rdev->mode_info.audio_property, -							      RADEON_AUDIO_DISABLE); +							   rdev->mode_info.audio_property, +							   RADEON_AUDIO_AUTO); +			} +			if (ASIC_IS_AVIVO(rdev)) { +				drm_object_attach_property(&radeon_connector->base.base, +							   rdev->mode_info.dither_property, +							   RADEON_FMT_DITHER_DISABLE);  			}  			subpixel_order = SubPixelHorizontalRGB;  			connector->interlace_allowed = true; @@ -1820,12 +1945,10 @@ radeon_add_atom_connector(struct drm_device *dev,  			drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);  			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);  			if (i2c_bus->valid) { -				/* add DP i2c bus */ -				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); -				if (!radeon_dig_connector->dp_i2c_bus) -					DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");  				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); -				if (!radeon_connector->ddc_bus) +				if (radeon_connector->ddc_bus) +					has_aux = true; +				else  					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");  			}  			subpixel_order = SubPixelHorizontalRGB; @@ -1843,10 +1966,16 @@ radeon_add_atom_connector(struct drm_device *dev,  							      rdev->mode_info.underscan_vborder_property,  							      0);  			} -			if (ASIC_IS_DCE2(rdev)) { +			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {  				drm_object_attach_property(&radeon_connector->base.base, -							      rdev->mode_info.audio_property, -							      RADEON_AUDIO_DISABLE); +							   rdev->mode_info.audio_property, +							   RADEON_AUDIO_AUTO); +			} +			if (ASIC_IS_AVIVO(rdev)) { +				drm_object_attach_property(&radeon_connector->base.base, +							   rdev->mode_info.dither_property, +							   RADEON_FMT_DITHER_DISABLE); +  			}  			connector->interlace_allowed = true;  			/* in theory with a DP to VGA converter... */ @@ -1861,12 +1990,10 @@ radeon_add_atom_connector(struct drm_device *dev,  			drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);  			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);  			if (i2c_bus->valid) { -				/* add DP i2c bus */ -				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); -				if (!radeon_dig_connector->dp_i2c_bus) -					DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");  				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); -				if (!radeon_connector->ddc_bus) +				if (radeon_connector->ddc_bus) +					has_aux = true; +				else  					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");  			}  			drm_object_attach_property(&radeon_connector->base.base, @@ -1924,6 +2051,10 @@ radeon_add_atom_connector(struct drm_device *dev,  	connector->display_info.subpixel_order = subpixel_order;  	drm_sysfs_connector_add(connector); + +	if (has_aux) +		radeon_dp_aux_init(radeon_connector); +  	return;  failed: diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 3cae2bbc185..bb0d5c3a831 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -2020,10 +2020,10 @@ static int radeon_cp_get_buffers(struct drm_device *dev,  		buf->file_priv = file_priv; -		if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, +		if (copy_to_user(&d->request_indices[i], &buf->idx,  				     sizeof(buf->idx)))  			return -EFAULT; -		if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, +		if (copy_to_user(&d->request_sizes[i], &buf->total,  				     sizeof(buf->total)))  			return -EFAULT; @@ -2228,7 +2228,7 @@ void radeon_commit_ring(drm_radeon_private_t *dev_priv)  	dev_priv->ring.tail &= dev_priv->ring.tail_mask; -	DRM_MEMORYBARRIER(); +	mb();  	GET_RING_HEAD( dev_priv );  	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) { diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 66c22283663..ae763f60c8a 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -24,16 +24,59 @@   * Authors:   *    Jerome Glisse <glisse@freedesktop.org>   */ +#include <linux/list_sort.h>  #include <drm/drmP.h>  #include <drm/radeon_drm.h>  #include "radeon_reg.h"  #include "radeon.h"  #include "radeon_trace.h" +#define RADEON_CS_MAX_PRIORITY		32u +#define RADEON_CS_NUM_BUCKETS		(RADEON_CS_MAX_PRIORITY + 1) + +/* This is based on the bucket sort with O(n) time complexity. + * An item with priority "i" is added to bucket[i]. The lists are then + * concatenated in descending order. + */ +struct radeon_cs_buckets { +	struct list_head bucket[RADEON_CS_NUM_BUCKETS]; +}; + +static void radeon_cs_buckets_init(struct radeon_cs_buckets *b) +{ +	unsigned i; + +	for (i = 0; i < RADEON_CS_NUM_BUCKETS; i++) +		INIT_LIST_HEAD(&b->bucket[i]); +} + +static void radeon_cs_buckets_add(struct radeon_cs_buckets *b, +				  struct list_head *item, unsigned priority) +{ +	/* Since buffers which appear sooner in the relocation list are +	 * likely to be used more often than buffers which appear later +	 * in the list, the sort mustn't change the ordering of buffers +	 * with the same priority, i.e. it must be stable. +	 */ +	list_add_tail(item, &b->bucket[min(priority, RADEON_CS_MAX_PRIORITY)]); +} + +static void radeon_cs_buckets_get_list(struct radeon_cs_buckets *b, +				       struct list_head *out_list) +{ +	unsigned i; + +	/* Connect the sorted buckets in the output list. */ +	for (i = 0; i < RADEON_CS_NUM_BUCKETS; i++) { +		list_splice(&b->bucket[i], out_list); +	} +} +  static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)  {  	struct drm_device *ddev = p->rdev->ddev;  	struct radeon_cs_chunk *chunk; +	struct radeon_cs_buckets buckets;  	unsigned i, j;  	bool duplicate; @@ -52,8 +95,12 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)  	if (p->relocs == NULL) {  		return -ENOMEM;  	} + +	radeon_cs_buckets_init(&buckets); +  	for (i = 0; i < p->nrelocs; i++) {  		struct drm_radeon_cs_reloc *r; +		unsigned priority;  		duplicate = false;  		r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4]; @@ -78,39 +125,59 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)  		}  		p->relocs_ptr[i] = &p->relocs[i];  		p->relocs[i].robj = gem_to_radeon_bo(p->relocs[i].gobj); -		p->relocs[i].lobj.bo = p->relocs[i].robj; -		p->relocs[i].lobj.written = !!r->write_domain; + +		/* The userspace buffer priorities are from 0 to 15. A higher +		 * number means the buffer is more important. +		 * Also, the buffers used for write have a higher priority than +		 * the buffers used for read only, which doubles the range +		 * to 0 to 31. 32 is reserved for the kernel driver. +		 */ +		priority = (r->flags & 0xf) * 2 + !!r->write_domain;  		/* the first reloc of an UVD job is the msg and that must be in  		   VRAM, also but everything into VRAM on AGP cards to avoid  		   image corruptions */  		if (p->ring == R600_RING_TYPE_UVD_INDEX && -		    p->rdev->family < CHIP_PALM &&  		    (i == 0 || drm_pci_device_is_agp(p->rdev->ddev))) { - -			p->relocs[i].lobj.domain = +			/* TODO: is this still needed for NI+ ? */ +			p->relocs[i].prefered_domains =  				RADEON_GEM_DOMAIN_VRAM; -			p->relocs[i].lobj.alt_domain = +			p->relocs[i].allowed_domains =  				RADEON_GEM_DOMAIN_VRAM; +			/* prioritize this over any other relocation */ +			priority = RADEON_CS_MAX_PRIORITY;  		} else {  			uint32_t domain = r->write_domain ?  				r->write_domain : r->read_domains; -			p->relocs[i].lobj.domain = domain; +			if (domain & RADEON_GEM_DOMAIN_CPU) { +				DRM_ERROR("RADEON_GEM_DOMAIN_CPU is not valid " +					  "for command submission\n"); +				return -EINVAL; +			} + +			p->relocs[i].prefered_domains = domain;  			if (domain == RADEON_GEM_DOMAIN_VRAM)  				domain |= RADEON_GEM_DOMAIN_GTT; -			p->relocs[i].lobj.alt_domain = domain; +			p->relocs[i].allowed_domains = domain;  		} -		p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo; +		p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;  		p->relocs[i].handle = r->handle; -		radeon_bo_list_add_object(&p->relocs[i].lobj, -					  &p->validated); +		radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head, +				      priority);  	} -	return radeon_bo_list_validate(&p->ticket, &p->validated, p->ring); + +	radeon_cs_buckets_get_list(&buckets, &p->validated); + +	if (p->cs_flags & RADEON_CS_USE_VM) +		p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm, +					      &p->validated); + +	return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);  }  static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority) @@ -139,7 +206,7 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority  				p->ring = R600_RING_TYPE_DMA_INDEX;  			else  				p->ring = CAYMAN_RING_TYPE_DMA1_INDEX; -		} else if (p->rdev->family >= CHIP_R600) { +		} else if (p->rdev->family >= CHIP_RV770) {  			p->ring = R600_RING_TYPE_DMA_INDEX;  		} else {  			return -EINVAL; @@ -148,6 +215,10 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority  	case RADEON_CS_RING_UVD:  		p->ring = R600_RING_TYPE_UVD_INDEX;  		break; +	case RADEON_CS_RING_VCE: +		/* TODO: only use the low priority ring for now */ +		p->ring = TN_RING_TYPE_VCE1_INDEX; +		break;  	}  	return 0;  } @@ -160,7 +231,8 @@ static void radeon_cs_sync_rings(struct radeon_cs_parser *p)  		if (!p->relocs[i].robj)  			continue; -		radeon_ib_sync_to(&p->ib, p->relocs[i].robj->tbo.sync_obj); +		radeon_semaphore_sync_to(p->ib.semaphore, +					 p->relocs[i].robj->tbo.sync_obj);  	}  } @@ -192,7 +264,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)  		return -ENOMEM;  	}  	chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks); -	if (DRM_COPY_FROM_USER(p->chunks_array, chunk_array_ptr, +	if (copy_from_user(p->chunks_array, chunk_array_ptr,  			       sizeof(uint64_t)*cs->num_chunks)) {  		return -EFAULT;  	} @@ -208,14 +280,12 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)  		uint32_t __user *cdata;  		chunk_ptr = (void __user*)(unsigned long)p->chunks_array[i]; -		if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr, +		if (copy_from_user(&user_chunk, chunk_ptr,  				       sizeof(struct drm_radeon_cs_chunk))) {  			return -EFAULT;  		}  		p->chunks[i].length_dw = user_chunk.length_dw; -		p->chunks[i].kdata = NULL;  		p->chunks[i].chunk_id = user_chunk.chunk_id; -		p->chunks[i].user_ptr = (void __user *)(unsigned long)user_chunk.chunk_data;  		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) {  			p->chunk_relocs_idx = i;  		} @@ -238,25 +308,31 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)  				return -EINVAL;  		} -		cdata = (uint32_t *)(unsigned long)user_chunk.chunk_data; -		if ((p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) || -		    (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS)) { -			size = p->chunks[i].length_dw * sizeof(uint32_t); -			p->chunks[i].kdata = kmalloc(size, GFP_KERNEL); -			if (p->chunks[i].kdata == NULL) { -				return -ENOMEM; -			} -			if (DRM_COPY_FROM_USER(p->chunks[i].kdata, -					       p->chunks[i].user_ptr, size)) { -				return -EFAULT; -			} -			if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) { -				p->cs_flags = p->chunks[i].kdata[0]; -				if (p->chunks[i].length_dw > 1) -					ring = p->chunks[i].kdata[1]; -				if (p->chunks[i].length_dw > 2) -					priority = (s32)p->chunks[i].kdata[2]; -			} +		size = p->chunks[i].length_dw; +		cdata = (void __user *)(unsigned long)user_chunk.chunk_data; +		p->chunks[i].user_ptr = cdata; +		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_CONST_IB) +			continue; + +		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) { +			if (!p->rdev || !(p->rdev->flags & RADEON_IS_AGP)) +				continue; +		} + +		p->chunks[i].kdata = drm_malloc_ab(size, sizeof(uint32_t)); +		size *= sizeof(uint32_t); +		if (p->chunks[i].kdata == NULL) { +			return -ENOMEM; +		} +		if (copy_from_user(p->chunks[i].kdata, cdata, size)) { +			return -EFAULT; +		} +		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) { +			p->cs_flags = p->chunks[i].kdata[0]; +			if (p->chunks[i].length_dw > 1) +				ring = p->chunks[i].kdata[1]; +			if (p->chunks[i].length_dw > 2) +				priority = (s32)p->chunks[i].kdata[2];  		}  	} @@ -272,44 +348,33 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)  			return -EINVAL;  		/* we only support VM on some SI+ rings */ -		if ((p->rdev->asic->ring[p->ring]->cs_parse == NULL) && -		   ((p->cs_flags & RADEON_CS_USE_VM) == 0)) { -			DRM_ERROR("Ring %d requires VM!\n", p->ring); -			return -EINVAL; -		} -	} - -	/* deal with non-vm */ -	if ((p->chunk_ib_idx != -1) && -	    ((p->cs_flags & RADEON_CS_USE_VM) == 0) && -	    (p->chunks[p->chunk_ib_idx].chunk_id == RADEON_CHUNK_ID_IB)) { -		if (p->chunks[p->chunk_ib_idx].length_dw > (16 * 1024)) { -			DRM_ERROR("cs IB too big: %d\n", -				  p->chunks[p->chunk_ib_idx].length_dw); -			return -EINVAL; -		} -		if (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) { -			p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL); -			p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL); -			if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL || -			    p->chunks[p->chunk_ib_idx].kpage[1] == NULL) { -				kfree(p->chunks[p->chunk_ib_idx].kpage[0]); -				kfree(p->chunks[p->chunk_ib_idx].kpage[1]); -				p->chunks[p->chunk_ib_idx].kpage[0] = NULL; -				p->chunks[p->chunk_ib_idx].kpage[1] = NULL; -				return -ENOMEM; +		if ((p->cs_flags & RADEON_CS_USE_VM) == 0) { +			if (p->rdev->asic->ring[p->ring]->cs_parse == NULL) { +				DRM_ERROR("Ring %d requires VM!\n", p->ring); +				return -EINVAL; +			} +		} else { +			if (p->rdev->asic->ring[p->ring]->ib_parse == NULL) { +				DRM_ERROR("VM not supported on ring %d!\n", +					  p->ring); +				return -EINVAL;  			}  		} -		p->chunks[p->chunk_ib_idx].kpage_idx[0] = -1; -		p->chunks[p->chunk_ib_idx].kpage_idx[1] = -1; -		p->chunks[p->chunk_ib_idx].last_copied_page = -1; -		p->chunks[p->chunk_ib_idx].last_page_index = -			((p->chunks[p->chunk_ib_idx].length_dw * 4) - 1) / PAGE_SIZE;  	}  	return 0;  } +static int cmp_size_smaller_first(void *priv, struct list_head *a, +				  struct list_head *b) +{ +	struct radeon_cs_reloc *la = list_entry(a, struct radeon_cs_reloc, tv.head); +	struct radeon_cs_reloc *lb = list_entry(b, struct radeon_cs_reloc, tv.head); + +	/* Sort A before B if A is smaller. */ +	return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages; +} +  /**   * cs_parser_fini() - clean parser states   * @parser:	parser structure holding parsing context. @@ -323,6 +388,18 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo  	unsigned i;  	if (!error) { +		/* Sort the buffer list from the smallest to largest buffer, +		 * which affects the order of buffers in the LRU list. +		 * This assures that the smallest buffers are added first +		 * to the LRU list, so they are likely to be later evicted +		 * first, instead of large buffers whose eviction is more +		 * expensive. +		 * +		 * This slightly lowers the number of bytes moved by TTM +		 * per frame under memory pressure. +		 */ +		list_sort(NULL, &parser->validated, cmp_size_smaller_first); +  		ttm_eu_fence_buffer_objects(&parser->ticket,  					    &parser->validated,  					    parser->ib.fence); @@ -340,13 +417,9 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo  	kfree(parser->track);  	kfree(parser->relocs);  	kfree(parser->relocs_ptr); -	for (i = 0; i < parser->nchunks; i++) { -		kfree(parser->chunks[i].kdata); -		if ((parser->rdev->flags & RADEON_IS_AGP)) { -			kfree(parser->chunks[i].kpage[0]); -			kfree(parser->chunks[i].kpage[1]); -		} -	} +	kfree(parser->vm_bos); +	for (i = 0; i < parser->nchunks; i++) +		drm_free_large(parser->chunks[i].kdata);  	kfree(parser->chunks);  	kfree(parser->chunks_array);  	radeon_ib_free(parser->rdev, &parser->ib); @@ -356,7 +429,6 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo  static int radeon_cs_ib_chunk(struct radeon_device *rdev,  			      struct radeon_cs_parser *parser)  { -	struct radeon_cs_chunk *ib_chunk;  	int r;  	if (parser->chunk_ib_idx == -1) @@ -365,31 +437,17 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,  	if (parser->cs_flags & RADEON_CS_USE_VM)  		return 0; -	ib_chunk = &parser->chunks[parser->chunk_ib_idx]; -	/* Copy the packet into the IB, the parser will read from the -	 * input memory (cached) and write to the IB (which can be -	 * uncached). -	 */ -	r =  radeon_ib_get(rdev, parser->ring, &parser->ib, -			   NULL, ib_chunk->length_dw * 4); -	if (r) { -		DRM_ERROR("Failed to get ib !\n"); -		return r; -	} -	parser->ib.length_dw = ib_chunk->length_dw;  	r = radeon_cs_parse(rdev, parser->ring, parser);  	if (r || parser->parser_error) {  		DRM_ERROR("Invalid command stream !\n");  		return r;  	} -	r = radeon_cs_finish_pages(parser); -	if (r) { -		DRM_ERROR("Invalid command stream !\n"); -		return r; -	}  	if (parser->ring == R600_RING_TYPE_UVD_INDEX)  		radeon_uvd_note_usage(rdev); +	else if ((parser->ring == TN_RING_TYPE_VCE1_INDEX) || +		 (parser->ring == TN_RING_TYPE_VCE2_INDEX)) +		radeon_vce_note_usage(rdev);  	radeon_cs_sync_rings(parser);  	r = radeon_ib_schedule(rdev, &parser->ib, NULL); @@ -399,24 +457,48 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,  	return r;  } -static int radeon_bo_vm_update_pte(struct radeon_cs_parser *parser, +static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,  				   struct radeon_vm *vm)  { -	struct radeon_device *rdev = parser->rdev; -	struct radeon_bo_list *lobj; -	struct radeon_bo *bo; -	int r; +	struct radeon_device *rdev = p->rdev; +	struct radeon_bo_va *bo_va; +	int i, r; -	r = radeon_vm_bo_update_pte(rdev, vm, rdev->ring_tmp_bo.bo, &rdev->ring_tmp_bo.bo->tbo.mem); -	if (r) { +	r = radeon_vm_update_page_directory(rdev, vm); +	if (r) +		return r; + +	r = radeon_vm_clear_freed(rdev, vm); +	if (r)  		return r; + +	if (vm->ib_bo_va == NULL) { +		DRM_ERROR("Tmp BO not in VM!\n"); +		return -EINVAL;  	} -	list_for_each_entry(lobj, &parser->validated, tv.head) { -		bo = lobj->bo; -		r = radeon_vm_bo_update_pte(parser->rdev, vm, bo, &bo->tbo.mem); -		if (r) { -			return r; + +	r = radeon_vm_bo_update(rdev, vm->ib_bo_va, +				&rdev->ring_tmp_bo.bo->tbo.mem); +	if (r) +		return r; + +	for (i = 0; i < p->nrelocs; i++) { +		struct radeon_bo *bo; + +		/* ignore duplicates */ +		if (p->relocs_ptr[i] != &p->relocs[i]) +			continue; + +		bo = p->relocs[i].robj; +		bo_va = radeon_vm_bo_find(vm, bo); +		if (bo_va == NULL) { +			dev_err(rdev->dev, "bo %p not in vm %p\n", bo, vm); +			return -EINVAL;  		} + +		r = radeon_vm_bo_update(rdev, bo_va, &bo->tbo.mem); +		if (r) +			return r;  	}  	return 0;  } @@ -424,7 +506,6 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *parser,  static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,  				 struct radeon_cs_parser *parser)  { -	struct radeon_cs_chunk *ib_chunk;  	struct radeon_fpriv *fpriv = parser->filp->driver_priv;  	struct radeon_vm *vm = &fpriv->vm;  	int r; @@ -434,49 +515,13 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,  	if ((parser->cs_flags & RADEON_CS_USE_VM) == 0)  		return 0; -	if ((rdev->family >= CHIP_TAHITI) && -	    (parser->chunk_const_ib_idx != -1)) { -		ib_chunk = &parser->chunks[parser->chunk_const_ib_idx]; -		if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) { -			DRM_ERROR("cs IB CONST too big: %d\n", ib_chunk->length_dw); -			return -EINVAL; -		} -		r =  radeon_ib_get(rdev, parser->ring, &parser->const_ib, -				   vm, ib_chunk->length_dw * 4); -		if (r) { -			DRM_ERROR("Failed to get const ib !\n"); -			return r; -		} -		parser->const_ib.is_const_ib = true; -		parser->const_ib.length_dw = ib_chunk->length_dw; -		/* Copy the packet into the IB */ -		if (DRM_COPY_FROM_USER(parser->const_ib.ptr, ib_chunk->user_ptr, -				       ib_chunk->length_dw * 4)) { -			return -EFAULT; -		} +	if (parser->const_ib.length_dw) {  		r = radeon_ring_ib_parse(rdev, parser->ring, &parser->const_ib);  		if (r) {  			return r;  		}  	} -	ib_chunk = &parser->chunks[parser->chunk_ib_idx]; -	if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) { -		DRM_ERROR("cs IB too big: %d\n", ib_chunk->length_dw); -		return -EINVAL; -	} -	r =  radeon_ib_get(rdev, parser->ring, &parser->ib, -			   vm, ib_chunk->length_dw * 4); -	if (r) { -		DRM_ERROR("Failed to get ib !\n"); -		return r; -	} -	parser->ib.length_dw = ib_chunk->length_dw; -	/* Copy the packet into the IB */ -	if (DRM_COPY_FROM_USER(parser->ib.ptr, ib_chunk->user_ptr, -			       ib_chunk->length_dw * 4)) { -		return -EFAULT; -	}  	r = radeon_ring_ib_parse(rdev, parser->ring, &parser->ib);  	if (r) {  		return r; @@ -485,20 +530,13 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,  	if (parser->ring == R600_RING_TYPE_UVD_INDEX)  		radeon_uvd_note_usage(rdev); -	mutex_lock(&rdev->vm_manager.lock);  	mutex_lock(&vm->mutex); -	r = radeon_vm_alloc_pt(rdev, vm); -	if (r) { -		goto out; -	}  	r = radeon_bo_vm_update_pte(parser, vm);  	if (r) {  		goto out;  	}  	radeon_cs_sync_rings(parser); -	radeon_ib_sync_to(&parser->ib, vm->fence); -	radeon_ib_sync_to(&parser->ib, radeon_vm_grab_id( -		rdev, vm, parser->ring)); +	radeon_semaphore_sync_to(parser->ib.semaphore, vm->fence);  	if ((rdev->family >= CHIP_TAHITI) &&  	    (parser->chunk_const_ib_idx != -1)) { @@ -507,14 +545,8 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,  		r = radeon_ib_schedule(rdev, &parser->ib, NULL);  	} -	if (!r) { -		radeon_vm_fence(rdev, vm, parser->ib.fence); -	} -  out: -	radeon_vm_add_to_lru(rdev, vm);  	mutex_unlock(&vm->mutex); -	mutex_unlock(&rdev->vm_manager.lock);  	return r;  } @@ -528,6 +560,62 @@ static int radeon_cs_handle_lockup(struct radeon_device *rdev, int r)  	return r;  } +static int radeon_cs_ib_fill(struct radeon_device *rdev, struct radeon_cs_parser *parser) +{ +	struct radeon_cs_chunk *ib_chunk; +	struct radeon_vm *vm = NULL; +	int r; + +	if (parser->chunk_ib_idx == -1) +		return 0; + +	if (parser->cs_flags & RADEON_CS_USE_VM) { +		struct radeon_fpriv *fpriv = parser->filp->driver_priv; +		vm = &fpriv->vm; + +		if ((rdev->family >= CHIP_TAHITI) && +		    (parser->chunk_const_ib_idx != -1)) { +			ib_chunk = &parser->chunks[parser->chunk_const_ib_idx]; +			if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) { +				DRM_ERROR("cs IB CONST too big: %d\n", ib_chunk->length_dw); +				return -EINVAL; +			} +			r =  radeon_ib_get(rdev, parser->ring, &parser->const_ib, +					   vm, ib_chunk->length_dw * 4); +			if (r) { +				DRM_ERROR("Failed to get const ib !\n"); +				return r; +			} +			parser->const_ib.is_const_ib = true; +			parser->const_ib.length_dw = ib_chunk->length_dw; +			if (copy_from_user(parser->const_ib.ptr, +					       ib_chunk->user_ptr, +					       ib_chunk->length_dw * 4)) +				return -EFAULT; +		} + +		ib_chunk = &parser->chunks[parser->chunk_ib_idx]; +		if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) { +			DRM_ERROR("cs IB too big: %d\n", ib_chunk->length_dw); +			return -EINVAL; +		} +	} +	ib_chunk = &parser->chunks[parser->chunk_ib_idx]; + +	r =  radeon_ib_get(rdev, parser->ring, &parser->ib, +			   vm, ib_chunk->length_dw * 4); +	if (r) { +		DRM_ERROR("Failed to get ib !\n"); +		return r; +	} +	parser->ib.length_dw = ib_chunk->length_dw; +	if (ib_chunk->kdata) +		memcpy(parser->ib.ptr, ib_chunk->kdata, ib_chunk->length_dw * 4); +	else if (copy_from_user(parser->ib.ptr, ib_chunk->user_ptr, ib_chunk->length_dw * 4)) +		return -EFAULT; +	return 0; +} +  int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  {  	struct radeon_device *rdev = dev->dev_private; @@ -553,10 +641,15 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  		r = radeon_cs_handle_lockup(rdev, r);  		return r;  	} -	r = radeon_cs_parser_relocs(&parser); -	if (r) { -		if (r != -ERESTARTSYS) + +	r = radeon_cs_ib_fill(rdev, &parser); +	if (!r) { +		r = radeon_cs_parser_relocs(&parser); +		if (r && r != -ERESTARTSYS)  			DRM_ERROR("Failed to parse relocation %d!\n", r); +	} + +	if (r) {  		radeon_cs_parser_fini(&parser, r, false);  		up_read(&rdev->exclusive_lock);  		r = radeon_cs_handle_lockup(rdev, r); @@ -580,97 +673,6 @@ out:  	return r;  } -int radeon_cs_finish_pages(struct radeon_cs_parser *p) -{ -	struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; -	int i; -	int size = PAGE_SIZE; - -	for (i = ibc->last_copied_page + 1; i <= ibc->last_page_index; i++) { -		if (i == ibc->last_page_index) { -			size = (ibc->length_dw * 4) % PAGE_SIZE; -			if (size == 0) -				size = PAGE_SIZE; -		} -		 -		if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), -				       ibc->user_ptr + (i * PAGE_SIZE), -				       size)) -			return -EFAULT; -	} -	return 0; -} - -static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx) -{ -	int new_page; -	struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; -	int i; -	int size = PAGE_SIZE; -	bool copy1 = (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) ? -		false : true; - -	for (i = ibc->last_copied_page + 1; i < pg_idx; i++) { -		if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), -				       ibc->user_ptr + (i * PAGE_SIZE), -				       PAGE_SIZE)) { -			p->parser_error = -EFAULT; -			return 0; -		} -	} - -	if (pg_idx == ibc->last_page_index) { -		size = (ibc->length_dw * 4) % PAGE_SIZE; -		if (size == 0) -			size = PAGE_SIZE; -	} - -	new_page = ibc->kpage_idx[0] < ibc->kpage_idx[1] ? 0 : 1; -	if (copy1) -		ibc->kpage[new_page] = p->ib.ptr + (pg_idx * (PAGE_SIZE / 4)); - -	if (DRM_COPY_FROM_USER(ibc->kpage[new_page], -			       ibc->user_ptr + (pg_idx * PAGE_SIZE), -			       size)) { -		p->parser_error = -EFAULT; -		return 0; -	} - -	/* copy to IB for non single case */ -	if (!copy1) -		memcpy((void *)(p->ib.ptr+(pg_idx*(PAGE_SIZE/4))), ibc->kpage[new_page], size); - -	ibc->last_copied_page = pg_idx; -	ibc->kpage_idx[new_page] = pg_idx; - -	return new_page; -} - -u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx) -{ -	struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; -	u32 pg_idx, pg_offset; -	u32 idx_value = 0; -	int new_page; - -	pg_idx = (idx * 4) / PAGE_SIZE; -	pg_offset = (idx * 4) % PAGE_SIZE; - -	if (ibc->kpage_idx[0] == pg_idx) -		return ibc->kpage[0][pg_offset/4]; -	if (ibc->kpage_idx[1] == pg_idx) -		return ibc->kpage[1][pg_offset/4]; - -	new_page = radeon_cs_update_pages(p, pg_idx); -	if (new_page < 0) { -		p->parser_error = new_page; -		return 0; -	} - -	idx_value = ibc->kpage[new_page][pg_offset/4]; -	return idx_value; -} -  /**   * radeon_cs_packet_parse() - parse cp packet and point ib index to next packet   * @parser:	parser structure holding parsing context. @@ -812,9 +814,9 @@ int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p,  	/* FIXME: we assume reloc size is 4 dwords */  	if (nomm) {  		*cs_reloc = p->relocs; -		(*cs_reloc)->lobj.gpu_offset = +		(*cs_reloc)->gpu_offset =  			(u64)relocs_chunk->kdata[idx + 3] << 32; -		(*cs_reloc)->lobj.gpu_offset |= relocs_chunk->kdata[idx + 0]; +		(*cs_reloc)->gpu_offset |= relocs_chunk->kdata[idx + 0];  	} else  		*cs_reloc = p->relocs_ptr[(idx / 4)];  	return 0; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 841d0e09be3..697add2cd4e 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -98,9 +98,20 @@ static const char radeon_family_name[][16] = {  	"BONAIRE",  	"KAVERI",  	"KABINI", +	"HAWAII", +	"MULLINS",  	"LAST",  }; +bool radeon_is_px(struct drm_device *dev) +{ +	struct radeon_device *rdev = dev->dev_private; + +	if (rdev->flags & RADEON_IS_PX) +		return true; +	return false; +} +  /**   * radeon_program_register_sequence - program an array of registers.   * @@ -137,6 +148,11 @@ void radeon_program_register_sequence(struct radeon_device *rdev,  	}  } +void radeon_pci_config_reset(struct radeon_device *rdev) +{ +	pci_write_config_dword(rdev->pdev, 0x7c, RADEON_ASIC_RESET_DATA); +} +  /**   * radeon_surface_init - Clear GPU surface registers.   * @@ -242,30 +258,25 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)   * Init doorbell driver information (CIK)   * Returns 0 on success, error on failure.   */ -int radeon_doorbell_init(struct radeon_device *rdev) +static int radeon_doorbell_init(struct radeon_device *rdev)  { -	int i; -  	/* doorbell bar mapping */  	rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);  	rdev->doorbell.size = pci_resource_len(rdev->pdev, 2); -	/* limit to 4 MB for now */ -	if (rdev->doorbell.size > (4 * 1024 * 1024)) -		rdev->doorbell.size = 4 * 1024 * 1024; +	rdev->doorbell.num_doorbells = min_t(u32, rdev->doorbell.size / sizeof(u32), RADEON_MAX_DOORBELLS); +	if (rdev->doorbell.num_doorbells == 0) +		return -EINVAL; -	rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size); +	rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.num_doorbells * sizeof(u32));  	if (rdev->doorbell.ptr == NULL) {  		return -ENOMEM;  	}  	DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);  	DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size); -	rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE; +	memset(&rdev->doorbell.used, 0, sizeof(rdev->doorbell.used)); -	for (i = 0; i < rdev->doorbell.num_pages; i++) { -		rdev->doorbell.free[i] = true; -	}  	return 0;  } @@ -276,47 +287,45 @@ int radeon_doorbell_init(struct radeon_device *rdev)   *   * Tear down doorbell driver information (CIK)   */ -void radeon_doorbell_fini(struct radeon_device *rdev) +static void radeon_doorbell_fini(struct radeon_device *rdev)  {  	iounmap(rdev->doorbell.ptr);  	rdev->doorbell.ptr = NULL;  }  /** - * radeon_doorbell_get - Allocate a doorbell page + * radeon_doorbell_get - Allocate a doorbell entry   *   * @rdev: radeon_device pointer - * @doorbell: doorbell page number + * @doorbell: doorbell index   * - * Allocate a doorbell page for use by the driver (all asics). + * Allocate a doorbell for use by the driver (all asics).   * Returns 0 on success or -EINVAL on failure.   */  int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)  { -	int i; - -	for (i = 0; i < rdev->doorbell.num_pages; i++) { -		if (rdev->doorbell.free[i]) { -			rdev->doorbell.free[i] = false; -			*doorbell = i; -			return 0; -		} +	unsigned long offset = find_first_zero_bit(rdev->doorbell.used, rdev->doorbell.num_doorbells); +	if (offset < rdev->doorbell.num_doorbells) { +		__set_bit(offset, rdev->doorbell.used); +		*doorbell = offset; +		return 0; +	} else { +		return -EINVAL;  	} -	return -EINVAL;  }  /** - * radeon_doorbell_free - Free a doorbell page + * radeon_doorbell_free - Free a doorbell entry   *   * @rdev: radeon_device pointer - * @doorbell: doorbell page number + * @doorbell: doorbell index   * - * Free a doorbell page allocated for use by the driver (all asics) + * Free a doorbell allocated for use by the driver (all asics)   */  void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)  { -	if (doorbell < rdev->doorbell.num_pages) -		rdev->doorbell.free[doorbell] = true; +	if (doorbell < rdev->doorbell.num_doorbells) +		__clear_bit(doorbell, rdev->doorbell.used);  }  /* @@ -1043,6 +1052,43 @@ static void radeon_check_arguments(struct radeon_device *rdev)  		radeon_agpmode = 0;  		break;  	} + +	if (!radeon_check_pot_argument(radeon_vm_size)) { +		dev_warn(rdev->dev, "VM size (%d) must be a power of 2\n", +			 radeon_vm_size); +		radeon_vm_size = 4; +	} + +	if (radeon_vm_size < 1) { +		dev_warn(rdev->dev, "VM size (%d) to small, min is 1GB\n", +			 radeon_vm_size); +		radeon_vm_size = 4; +	} + +       /* +        * Max GPUVM size for Cayman, SI and CI are 40 bits. +        */ +	if (radeon_vm_size > 1024) { +		dev_warn(rdev->dev, "VM size (%d) too large, max is 1TB\n", +			 radeon_vm_size); +		radeon_vm_size = 4; +	} + +	/* defines number of bits in page table versus page directory, +	 * a page is 4KB so we have 12 bits offset, minimum 9 bits in the +	 * page table and the remaining bits are in the page directory */ +	if (radeon_vm_block_size < 9) { +		dev_warn(rdev->dev, "VM page table size (%d) too small\n", +			 radeon_vm_block_size); +		radeon_vm_block_size = 9; +	} + +	if (radeon_vm_block_size > 24 || +	    (radeon_vm_size * 1024) < (1ull << radeon_vm_block_size)) { +		dev_warn(rdev->dev, "VM page table size (%d) too large\n", +			 radeon_vm_block_size); +		radeon_vm_block_size = 9; +	}  }  /** @@ -1076,7 +1122,10 @@ static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev)  static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)  {  	struct drm_device *dev = pci_get_drvdata(pdev); -	pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; + +	if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF) +		return; +  	if (state == VGA_SWITCHEROO_ON) {  		unsigned d3_delay = dev->pdev->d3_delay; @@ -1087,7 +1136,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero  		if (d3_delay < 20 && radeon_switcheroo_quirk_long_wakeup(pdev))  			dev->pdev->d3_delay = 20; -		radeon_resume_kms(dev); +		radeon_resume_kms(dev, true, true);  		dev->pdev->d3_delay = d3_delay; @@ -1097,7 +1146,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero  		printk(KERN_INFO "radeon: switched off\n");  		drm_kms_helper_poll_disable(dev);  		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; -		radeon_suspend_kms(dev, pmm); +		radeon_suspend_kms(dev, true, true);  		dev->switch_power_state = DRM_SWITCH_POWER_OFF;  	}  } @@ -1114,12 +1163,13 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero  static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)  {  	struct drm_device *dev = pci_get_drvdata(pdev); -	bool can_switch; -	spin_lock(&dev->count_lock); -	can_switch = (dev->open_count == 0); -	spin_unlock(&dev->count_lock); -	return can_switch; +	/* +	 * FIXME: open_count is protected by drm_global_mutex but that would lead to +	 * locking inversion with the driver load path. And the access here is +	 * completely racy anyway. So don't bother with locking for now. +	 */ +	return dev->open_count == 0;  }  static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { @@ -1147,6 +1197,7 @@ int radeon_device_init(struct radeon_device *rdev,  {  	int r, i;  	int dma_bits; +	bool runtime = false;  	rdev->shutdown = false;  	rdev->dev = &pdev->dev; @@ -1182,20 +1233,17 @@ int radeon_device_init(struct radeon_device *rdev,  	r = radeon_gem_init(rdev);  	if (r)  		return r; -	/* initialize vm here */ -	mutex_init(&rdev->vm_manager.lock); + +	radeon_check_arguments(rdev);  	/* Adjust VM size here. -	 * Currently set to 4GB ((1 << 20) 4k pages). -	 * Max GPUVM size for cayman and SI is 40 bits. +	 * Max GPUVM size for cayman+ is 40 bits.  	 */ -	rdev->vm_manager.max_pfn = 1 << 20; -	INIT_LIST_HEAD(&rdev->vm_manager.lru_vm); +	rdev->vm_manager.max_pfn = radeon_vm_size << 18;  	/* Set asic functions */  	r = radeon_asic_init(rdev);  	if (r)  		return r; -	radeon_check_arguments(rdev);  	/* all of the newer IGP chips have an internal gart  	 * However some rs4xx report as AGP, so remove that here. @@ -1293,7 +1341,12 @@ int radeon_device_init(struct radeon_device *rdev,  	/* this will fail for cards that aren't VGA class devices, just  	 * ignore it */  	vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); -	vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, false); + +	if (rdev->flags & RADEON_IS_PX) +		runtime = true; +	vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime); +	if (runtime) +		vga_switcheroo_init_domain_pm_ops(rdev->dev, &rdev->vga_pm_domain);  	r = radeon_init(rdev);  	if (r) @@ -1319,6 +1372,7 @@ int radeon_device_init(struct radeon_device *rdev,  		if (r)  			return r;  	} +  	if ((radeon_testing & 1)) {  		if (rdev->accel_working)  			radeon_test_moves(rdev); @@ -1383,7 +1437,7 @@ void radeon_device_fini(struct radeon_device *rdev)   * Returns 0 for success or an error on failure.   * Called at driver suspend.   */ -int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) +int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)  {  	struct radeon_device *rdev;  	struct drm_crtc *crtc; @@ -1394,9 +1448,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	if (dev == NULL || dev->dev_private == NULL) {  		return -ENODEV;  	} -	if (state.event == PM_EVENT_PRETHAW) { -		return 0; -	} +  	rdev = dev->dev_private;  	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) @@ -1411,7 +1463,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	/* unpin the front buffers */  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); +		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb);  		struct radeon_bo *robj;  		if (rfb == NULL || rfb->obj == NULL) { @@ -1430,10 +1482,9 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	/* evict vram memory */  	radeon_bo_evict_vram(rdev); -	mutex_lock(&rdev->ring_lock);  	/* wait for gpu to finish processing current batch */  	for (i = 0; i < RADEON_NUM_RINGS; i++) { -		r = radeon_fence_wait_empty_locked(rdev, i); +		r = radeon_fence_wait_empty(rdev, i);  		if (r) {  			/* delay GPU reset to resume */  			force_completion = true; @@ -1442,11 +1493,9 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	if (force_completion) {  		radeon_fence_driver_force_completion(rdev);  	} -	mutex_unlock(&rdev->ring_lock);  	radeon_save_bios_scratch_regs(rdev); -	radeon_pm_suspend(rdev);  	radeon_suspend(rdev);  	radeon_hpd_fini(rdev);  	/* evict remaining vram memory */ @@ -1455,14 +1504,17 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	radeon_agp_suspend(rdev);  	pci_save_state(dev->pdev); -	if (state.event == PM_EVENT_SUSPEND) { +	if (suspend) {  		/* Shut down the device */  		pci_disable_device(dev->pdev);  		pci_set_power_state(dev->pdev, PCI_D3hot);  	} -	console_lock(); -	radeon_fbdev_set_suspend(rdev, 1); -	console_unlock(); + +	if (fbcon) { +		console_lock(); +		radeon_fbdev_set_suspend(rdev, 1); +		console_unlock(); +	}  	return 0;  } @@ -1475,7 +1527,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)   * Returns 0 for success or an error on failure.   * Called at driver resume.   */ -int radeon_resume_kms(struct drm_device *dev) +int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)  {  	struct drm_connector *connector;  	struct radeon_device *rdev = dev->dev_private; @@ -1484,12 +1536,17 @@ int radeon_resume_kms(struct drm_device *dev)  	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)  		return 0; -	console_lock(); -	pci_set_power_state(dev->pdev, PCI_D0); -	pci_restore_state(dev->pdev); -	if (pci_enable_device(dev->pdev)) { -		console_unlock(); -		return -1; +	if (fbcon) { +		console_lock(); +	} +	if (resume) { +		pci_set_power_state(dev->pdev, PCI_D0); +		pci_restore_state(dev->pdev); +		if (pci_enable_device(dev->pdev)) { +			if (fbcon) +				console_unlock(); +			return -1; +		}  	}  	/* resume AGP if in use */  	radeon_agp_resume(rdev); @@ -1499,11 +1556,19 @@ int radeon_resume_kms(struct drm_device *dev)  	if (r)  		DRM_ERROR("ib ring test failed (%d).\n", r); -	radeon_pm_resume(rdev); -	radeon_restore_bios_scratch_regs(rdev); +	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { +		/* do dpm late init */ +		r = radeon_pm_late_init(rdev); +		if (r) { +			rdev->pm.dpm_enabled = false; +			DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); +		} +	} else { +		/* resume old pm late */ +		radeon_pm_resume(rdev); +	} -	radeon_fbdev_set_suspend(rdev, 0); -	console_unlock(); +	radeon_restore_bios_scratch_regs(rdev);  	/* init dig PHYs, disp eng pll */  	if (rdev->is_atom_bios) { @@ -1520,13 +1585,25 @@ int radeon_resume_kms(struct drm_device *dev)  	/* reset hpd state */  	radeon_hpd_init(rdev);  	/* blat the mode back in */ -	drm_helper_resume_force_mode(dev); -	/* turn on display hw */ -	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); +	if (fbcon) { +		drm_helper_resume_force_mode(dev); +		/* turn on display hw */ +		list_for_each_entry(connector, &dev->mode_config.connector_list, head) { +			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); +		}  	}  	drm_kms_helper_poll_enable(dev); + +	/* set the power state here in case we are a PX system or headless */ +	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) +		radeon_pm_compute_clocks(rdev); + +	if (fbcon) { +		radeon_fbdev_set_suspend(rdev, 0); +		console_unlock(); +	} +  	return 0;  } @@ -1549,6 +1626,14 @@ int radeon_gpu_reset(struct radeon_device *rdev)  	int resched;  	down_write(&rdev->exclusive_lock); + +	if (!rdev->needs_reset) { +		up_write(&rdev->exclusive_lock); +		return 0; +	} + +	rdev->needs_reset = false; +  	radeon_save_bios_scratch_regs(rdev);  	/* block TTM */  	resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 0d1aa050d41..bf25061c8ac 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -30,9 +30,12 @@  #include "atom.h"  #include <asm/div64.h> +#include <linux/pm_runtime.h>  #include <drm/drm_crtc_helper.h>  #include <drm/drm_edid.h> +#include <linux/gcd.h> +  static void avivo_crtc_load_lut(struct drm_crtc *crtc)  {  	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -63,7 +66,8 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)  			     (radeon_crtc->lut_b[i] << 0));  	} -	WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); +	/* Only change bit 0 of LUT_SEL, other bits are set elsewhere */ +	WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id, ~1);  }  static void dce4_crtc_load_lut(struct drm_crtc *crtc) @@ -246,16 +250,21 @@ static void radeon_crtc_destroy(struct drm_crtc *crtc)  	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);  	drm_crtc_cleanup(crtc); +	destroy_workqueue(radeon_crtc->flip_queue);  	kfree(radeon_crtc);  } -/* - * Handle unpin events outside the interrupt handler proper. +/** + * radeon_unpin_work_func - unpin old buffer object + * + * @__work - kernel work item + * + * Unpin the old frame buffer object outside of the interrupt handler   */  static void radeon_unpin_work_func(struct work_struct *__work)  { -	struct radeon_unpin_work *work = -		container_of(__work, struct radeon_unpin_work, work); +	struct radeon_flip_work *work = +		container_of(__work, struct radeon_flip_work, unpin_work);  	int r;  	/* unpin of the old buffer */ @@ -273,40 +282,35 @@ static void radeon_unpin_work_func(struct work_struct *__work)  	kfree(work);  } -void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) +void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id)  {  	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; -	struct radeon_unpin_work *work;  	unsigned long flags;  	u32 update_pending;  	int vpos, hpos; +	/* can happen during initialization */ +	if (radeon_crtc == NULL) +		return; +  	spin_lock_irqsave(&rdev->ddev->event_lock, flags); -	work = radeon_crtc->unpin_work; -	if (work == NULL || -	    (work->fence && !radeon_fence_signaled(work->fence))) { +	if (radeon_crtc->flip_status != RADEON_FLIP_SUBMITTED) { +		DRM_DEBUG_DRIVER("radeon_crtc->flip_status = %d != " +				 "RADEON_FLIP_SUBMITTED(%d)\n", +				 radeon_crtc->flip_status, +				 RADEON_FLIP_SUBMITTED);  		spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);  		return;  	} -	/* New pageflip, or just completion of a previous one? */ -	if (!radeon_crtc->deferred_flip_completion) { -		/* do the flip (mmio) */ -		update_pending = radeon_page_flip(rdev, crtc_id, work->new_crtc_base); -	} else { -		/* This is just a completion of a flip queued in crtc -		 * at last invocation. Make sure we go directly to -		 * completion routine. -		 */ -		update_pending = 0; -		radeon_crtc->deferred_flip_completion = 0; -	} + +	update_pending = radeon_page_flip_pending(rdev, crtc_id);  	/* Has the pageflip already completed in crtc, or is it certain  	 * to complete in this vblank?  	 */  	if (update_pending && -	    (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, -							       &vpos, &hpos)) && +	    (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0, +							       &vpos, &hpos, NULL, NULL)) &&  	    ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||  	     (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {  		/* crtc didn't flip in this target vblank interval, @@ -317,19 +321,43 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)  		 */  		update_pending = 0;  	} -	if (update_pending) { -		/* crtc didn't flip in this target vblank interval, -		 * but flip is pending in crtc. It will complete it -		 * in next vblank interval, so complete the flip at -		 * next vblank irq. -		 */ -		radeon_crtc->deferred_flip_completion = 1; +	spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); +	if (!update_pending) +		radeon_crtc_handle_flip(rdev, crtc_id); +} + +/** + * radeon_crtc_handle_flip - page flip completed + * + * @rdev: radeon device pointer + * @crtc_id: crtc number this event is for + * + * Called when we are sure that a page flip for this crtc is completed. + */ +void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) +{ +	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; +	struct radeon_flip_work *work; +	unsigned long flags; + +	/* this can happen at init */ +	if (radeon_crtc == NULL) +		return; + +	spin_lock_irqsave(&rdev->ddev->event_lock, flags); +	work = radeon_crtc->flip_work; +	if (radeon_crtc->flip_status != RADEON_FLIP_SUBMITTED) { +		DRM_DEBUG_DRIVER("radeon_crtc->flip_status = %d != " +				 "RADEON_FLIP_SUBMITTED(%d)\n", +				 radeon_crtc->flip_status, +				 RADEON_FLIP_SUBMITTED);  		spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);  		return;  	} -	/* Pageflip (will be) certainly completed in this vblank. Clean up. */ -	radeon_crtc->unpin_work = NULL; +	/* Pageflip completed. Clean up. */ +	radeon_crtc->flip_status = RADEON_FLIP_NONE; +	radeon_crtc->flip_work = NULL;  	/* wakeup userspace */  	if (work->event) @@ -338,9 +366,59 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)  	spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);  	drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id); -	radeon_fence_unref(&work->fence); -	radeon_post_page_flip(work->rdev, work->crtc_id); -	schedule_work(&work->work); +	radeon_irq_kms_pflip_irq_put(rdev, work->crtc_id); +	queue_work(radeon_crtc->flip_queue, &work->unpin_work); +} + +/** + * radeon_flip_work_func - page flip framebuffer + * + * @work - kernel work item + * + * Wait for the buffer object to become idle and do the actual page flip + */ +static void radeon_flip_work_func(struct work_struct *__work) +{ +	struct radeon_flip_work *work = +		container_of(__work, struct radeon_flip_work, flip_work); +	struct radeon_device *rdev = work->rdev; +	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id]; + +	struct drm_crtc *crtc = &radeon_crtc->base; +	unsigned long flags; +	int r; + +        down_read(&rdev->exclusive_lock); +	if (work->fence) { +		r = radeon_fence_wait(work->fence, false); +		if (r == -EDEADLK) { +			up_read(&rdev->exclusive_lock); +			r = radeon_gpu_reset(rdev); +			down_read(&rdev->exclusive_lock); +		} +		if (r) +			DRM_ERROR("failed to wait on page flip fence (%d)!\n", r); + +		/* We continue with the page flip even if we failed to wait on +		 * the fence, otherwise the DRM core and userspace will be +		 * confused about which BO the CRTC is scanning out +		 */ + +		radeon_fence_unref(&work->fence); +	} + +	/* We borrow the event spin lock for protecting flip_status */ +	spin_lock_irqsave(&crtc->dev->event_lock, flags); + +	/* set the proper interrupt */ +	radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); + +	/* do the flip (mmio) */ +	radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base); + +	radeon_crtc->flip_status = RADEON_FLIP_SUBMITTED; +	spin_unlock_irqrestore(&crtc->dev->event_lock, flags); +	up_read(&rdev->exclusive_lock);  }  static int radeon_crtc_page_flip(struct drm_crtc *crtc, @@ -354,69 +432,61 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,  	struct radeon_framebuffer *old_radeon_fb;  	struct radeon_framebuffer *new_radeon_fb;  	struct drm_gem_object *obj; -	struct radeon_bo *rbo; -	struct radeon_unpin_work *work; +	struct radeon_flip_work *work; +	struct radeon_bo *new_rbo; +	uint32_t tiling_flags, pitch_pixels; +	uint64_t base;  	unsigned long flags; -	u32 tiling_flags, pitch_pixels; -	u64 base;  	int r;  	work = kzalloc(sizeof *work, GFP_KERNEL);  	if (work == NULL)  		return -ENOMEM; -	work->event = event; +	INIT_WORK(&work->flip_work, radeon_flip_work_func); +	INIT_WORK(&work->unpin_work, radeon_unpin_work_func); +  	work->rdev = rdev;  	work->crtc_id = radeon_crtc->crtc_id; -	old_radeon_fb = to_radeon_framebuffer(crtc->fb); -	new_radeon_fb = to_radeon_framebuffer(fb); +	work->event = event; +  	/* schedule unpin of the old buffer */ +	old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb);  	obj = old_radeon_fb->obj; +  	/* take a reference to the old object */  	drm_gem_object_reference(obj); -	rbo = gem_to_radeon_bo(obj); -	work->old_rbo = rbo; -	obj = new_radeon_fb->obj; -	rbo = gem_to_radeon_bo(obj); +	work->old_rbo = gem_to_radeon_bo(obj); -	spin_lock(&rbo->tbo.bdev->fence_lock); -	if (rbo->tbo.sync_obj) -		work->fence = radeon_fence_ref(rbo->tbo.sync_obj); -	spin_unlock(&rbo->tbo.bdev->fence_lock); +	new_radeon_fb = to_radeon_framebuffer(fb); +	obj = new_radeon_fb->obj; +	new_rbo = gem_to_radeon_bo(obj); -	INIT_WORK(&work->work, radeon_unpin_work_func); - -	/* We borrow the event spin lock for protecting unpin_work */ -	spin_lock_irqsave(&dev->event_lock, flags); -	if (radeon_crtc->unpin_work) { -		DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); -		r = -EBUSY; -		goto unlock_free; -	} -	radeon_crtc->unpin_work = work; -	radeon_crtc->deferred_flip_completion = 0; -	spin_unlock_irqrestore(&dev->event_lock, flags); +	spin_lock(&new_rbo->tbo.bdev->fence_lock); +	if (new_rbo->tbo.sync_obj) +		work->fence = radeon_fence_ref(new_rbo->tbo.sync_obj); +	spin_unlock(&new_rbo->tbo.bdev->fence_lock);  	/* pin the new buffer */ -	DRM_DEBUG_DRIVER("flip-ioctl() cur_fbo = %p, cur_bbo = %p\n", -			 work->old_rbo, rbo); +	DRM_DEBUG_DRIVER("flip-ioctl() cur_rbo = %p, new_rbo = %p\n", +			 work->old_rbo, new_rbo); -	r = radeon_bo_reserve(rbo, false); +	r = radeon_bo_reserve(new_rbo, false);  	if (unlikely(r != 0)) {  		DRM_ERROR("failed to reserve new rbo buffer before flip\n"); -		goto pflip_cleanup; +		goto cleanup;  	}  	/* Only 27 bit offset for legacy CRTC */ -	r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM, +	r = radeon_bo_pin_restricted(new_rbo, RADEON_GEM_DOMAIN_VRAM,  				     ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, &base);  	if (unlikely(r != 0)) { -		radeon_bo_unreserve(rbo); +		radeon_bo_unreserve(new_rbo);  		r = -EINVAL;  		DRM_ERROR("failed to pin new rbo buffer before flip\n"); -		goto pflip_cleanup; +		goto cleanup;  	} -	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); -	radeon_bo_unreserve(rbo); +	radeon_bo_get_tiling_flags(new_rbo, &tiling_flags, NULL); +	radeon_bo_unreserve(new_rbo);  	if (!ASIC_IS_AVIVO(rdev)) {  		/* crtc offset is from display base addr not FB location */ @@ -453,52 +523,104 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,  		}  		base &= ~7;  	} +	work->base = base; -	spin_lock_irqsave(&dev->event_lock, flags); -	work->new_crtc_base = base; -	spin_unlock_irqrestore(&dev->event_lock, flags); - -	/* update crtc fb */ -	crtc->fb = fb; - -	r = drm_vblank_get(dev, radeon_crtc->crtc_id); +	r = drm_vblank_get(crtc->dev, radeon_crtc->crtc_id);  	if (r) {  		DRM_ERROR("failed to get vblank before flip\n"); -		goto pflip_cleanup1; +		goto pflip_cleanup;  	} -	/* set the proper interrupt */ -	radeon_pre_page_flip(rdev, radeon_crtc->crtc_id); +	/* We borrow the event spin lock for protecting flip_work */ +	spin_lock_irqsave(&crtc->dev->event_lock, flags); +	if (radeon_crtc->flip_status != RADEON_FLIP_NONE) { +		DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); +		spin_unlock_irqrestore(&crtc->dev->event_lock, flags); +		r = -EBUSY; +		goto vblank_cleanup; +	} +	radeon_crtc->flip_status = RADEON_FLIP_PENDING; +	radeon_crtc->flip_work = work; + +	/* update crtc fb */ +	crtc->primary->fb = fb; + +	spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + +	queue_work(radeon_crtc->flip_queue, &work->flip_work);  	return 0; -pflip_cleanup1: -	if (unlikely(radeon_bo_reserve(rbo, false) != 0)) { +vblank_cleanup: +	drm_vblank_put(crtc->dev, radeon_crtc->crtc_id); + +pflip_cleanup: +	if (unlikely(radeon_bo_reserve(new_rbo, false) != 0)) {  		DRM_ERROR("failed to reserve new rbo in error path\n"); -		goto pflip_cleanup; +		goto cleanup;  	} -	if (unlikely(radeon_bo_unpin(rbo) != 0)) { +	if (unlikely(radeon_bo_unpin(new_rbo) != 0)) {  		DRM_ERROR("failed to unpin new rbo in error path\n");  	} -	radeon_bo_unreserve(rbo); +	radeon_bo_unreserve(new_rbo); -pflip_cleanup: -	spin_lock_irqsave(&dev->event_lock, flags); -	radeon_crtc->unpin_work = NULL; -unlock_free: -	spin_unlock_irqrestore(&dev->event_lock, flags); -	drm_gem_object_unreference_unlocked(old_radeon_fb->obj); +cleanup: +	drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);  	radeon_fence_unref(&work->fence);  	kfree(work);  	return r;  } +static int +radeon_crtc_set_config(struct drm_mode_set *set) +{ +	struct drm_device *dev; +	struct radeon_device *rdev; +	struct drm_crtc *crtc; +	bool active = false; +	int ret; + +	if (!set || !set->crtc) +		return -EINVAL; + +	dev = set->crtc->dev; + +	ret = pm_runtime_get_sync(dev->dev); +	if (ret < 0) +		return ret; + +	ret = drm_crtc_helper_set_config(set); + +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) +		if (crtc->enabled) +			active = true; + +	pm_runtime_mark_last_busy(dev->dev); + +	rdev = dev->dev_private; +	/* if we have active crtcs and we don't have a power ref, +	   take the current one */ +	if (active && !rdev->have_disp_power_ref) { +		rdev->have_disp_power_ref = true; +		return ret; +	} +	/* if we have no active crtcs, then drop the power ref +	   we got before */ +	if (!active && rdev->have_disp_power_ref) { +		pm_runtime_put_autosuspend(dev->dev); +		rdev->have_disp_power_ref = false; +	} + +	/* drop the power reference we got coming in here */ +	pm_runtime_put_autosuspend(dev->dev); +	return ret; +}  static const struct drm_crtc_funcs radeon_crtc_funcs = {  	.cursor_set = radeon_crtc_cursor_set,  	.cursor_move = radeon_crtc_cursor_move,  	.gamma_set = radeon_crtc_gamma_set, -	.set_config = drm_crtc_helper_set_config, +	.set_config = radeon_crtc_set_config,  	.destroy = radeon_crtc_destroy,  	.page_flip = radeon_crtc_page_flip,  }; @@ -517,6 +639,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index)  	drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);  	radeon_crtc->crtc_id = index; +	radeon_crtc->flip_queue = create_singlethread_workqueue("radeon-crtc");  	rdev->mode_info.crtcs[index] = radeon_crtc;  	if (rdev->family >= CHIP_BONAIRE) { @@ -526,6 +649,8 @@ static void radeon_crtc_init(struct drm_device *dev, int index)  		radeon_crtc->max_cursor_width = CURSOR_WIDTH;  		radeon_crtc->max_cursor_height = CURSOR_HEIGHT;  	} +	dev->mode_config.cursor_width = radeon_crtc->max_cursor_width; +	dev->mode_config.cursor_height = radeon_crtc->max_cursor_height;  #if 0  	radeon_crtc->mode_set.crtc = &radeon_crtc->base; @@ -608,7 +733,7 @@ static void radeon_print_display_setup(struct drm_device *dev)  	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {  		radeon_connector = to_radeon_connector(connector);  		DRM_INFO("Connector %d:\n", i); -		DRM_INFO("  %s\n", drm_get_connector_name(connector)); +		DRM_INFO("  %s\n", connector->name);  		if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)  			DRM_INFO("  %s\n", hpd_names[radeon_connector->hpd.hpd]);  		if (radeon_connector->ddc_bus) { @@ -704,25 +829,28 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)  	struct radeon_device *rdev = dev->dev_private;  	int ret = 0; +	/* don't leak the edid if we already fetched it in detect() */ +	if (radeon_connector->edid) +		goto got_edid; +  	/* on hw with routers, select right port */  	if (radeon_connector->router.ddc_valid)  		radeon_router_select_ddc_port(radeon_connector);  	if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) !=  	    ENCODER_OBJECT_ID_NONE) { -		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - -		if (dig->dp_i2c_bus) +		if (radeon_connector->ddc_bus->has_aux)  			radeon_connector->edid = drm_get_edid(&radeon_connector->base, -							      &dig->dp_i2c_bus->adapter); +							      &radeon_connector->ddc_bus->aux.ddc);  	} else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||  		   (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {  		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;  		if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || -		     dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) +		     dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && +		    radeon_connector->ddc_bus->has_aux)  			radeon_connector->edid = drm_get_edid(&radeon_connector->base, -							      &dig->dp_i2c_bus->adapter); +							      &radeon_connector->ddc_bus->aux.ddc);  		else if (radeon_connector->ddc_bus && !radeon_connector->edid)  			radeon_connector->edid = drm_get_edid(&radeon_connector->base,  							      &radeon_connector->ddc_bus->adapter); @@ -743,8 +871,10 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)  			radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);  	}  	if (radeon_connector->edid) { +got_edid:  		drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);  		ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); +		drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);  		return ret;  	}  	drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); @@ -752,66 +882,89 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)  }  /* avivo */ -static void avivo_get_fb_div(struct radeon_pll *pll, -			     u32 target_clock, -			     u32 post_div, -			     u32 ref_div, -			     u32 *fb_div, -			     u32 *frac_fb_div) -{ -	u32 tmp = post_div * ref_div; -	tmp *= target_clock; -	*fb_div = tmp / pll->reference_freq; -	*frac_fb_div = tmp % pll->reference_freq; +/** + * avivo_reduce_ratio - fractional number reduction + * + * @nom: nominator + * @den: denominator + * @nom_min: minimum value for nominator + * @den_min: minimum value for denominator + * + * Find the greatest common divisor and apply it on both nominator and + * denominator, but make nominator and denominator are at least as large + * as their minimum values. + */ +static void avivo_reduce_ratio(unsigned *nom, unsigned *den, +			       unsigned nom_min, unsigned den_min) +{ +	unsigned tmp; + +	/* reduce the numbers to a simpler ratio */ +	tmp = gcd(*nom, *den); +	*nom /= tmp; +	*den /= tmp; + +	/* make sure nominator is large enough */ +        if (*nom < nom_min) { +		tmp = DIV_ROUND_UP(nom_min, *nom); +		*nom *= tmp; +		*den *= tmp; +	} -        if (*fb_div > pll->max_feedback_div) -		*fb_div = pll->max_feedback_div; -        else if (*fb_div < pll->min_feedback_div) -                *fb_div = pll->min_feedback_div; +	/* make sure the denominator is large enough */ +	if (*den < den_min) { +		tmp = DIV_ROUND_UP(den_min, *den); +		*nom *= tmp; +		*den *= tmp; +	}  } -static u32 avivo_get_post_div(struct radeon_pll *pll, -			      u32 target_clock) +/** + * avivo_get_fb_ref_div - feedback and ref divider calculation + * + * @nom: nominator + * @den: denominator + * @post_div: post divider + * @fb_div_max: feedback divider maximum + * @ref_div_max: reference divider maximum + * @fb_div: resulting feedback divider + * @ref_div: resulting reference divider + * + * Calculate feedback and reference divider for a given post divider. Makes + * sure we stay within the limits. + */ +static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div, +				 unsigned fb_div_max, unsigned ref_div_max, +				 unsigned *fb_div, unsigned *ref_div)  { -	u32 vco, post_div, tmp; +	/* limit reference * post divider to a maximum */ +	ref_div_max = max(min(100 / post_div, ref_div_max), 1u); -	if (pll->flags & RADEON_PLL_USE_POST_DIV) -		return pll->post_div; +	/* get matching reference and feedback divider */ +	*ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max); +	*fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den); -	if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { -		if (pll->flags & RADEON_PLL_IS_LCD) -			vco = pll->lcd_pll_out_min; -		else -			vco = pll->pll_out_min; -	} else { -		if (pll->flags & RADEON_PLL_IS_LCD) -			vco = pll->lcd_pll_out_max; -		else -			vco = pll->pll_out_max; +	/* limit fb divider to its maximum */ +        if (*fb_div > fb_div_max) { +		*ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div); +		*fb_div = fb_div_max;  	} - -	post_div = vco / target_clock; -	tmp = vco % target_clock; - -	if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { -		if (tmp) -			post_div++; -	} else { -		if (!tmp) -			post_div--; -	} - -	if (post_div > pll->max_post_div) -		post_div = pll->max_post_div; -	else if (post_div < pll->min_post_div) -		post_div = pll->min_post_div; - -	return post_div;  } -#define MAX_TOLERANCE 10 - +/** + * radeon_compute_pll_avivo - compute PLL paramaters + * + * @pll: information about the PLL + * @dot_clock_p: resulting pixel clock + * fb_div_p: resulting feedback divider + * frac_fb_div_p: fractional part of the feedback divider + * ref_div_p: resulting reference divider + * post_div_p: resulting reference divider + * + * Try to calculate the PLL parameters to generate the given frequency: + * dot_clock = (ref_freq * feedback_div) / (ref_div * post_div) + */  void radeon_compute_pll_avivo(struct radeon_pll *pll,  			      u32 freq,  			      u32 *dot_clock_p, @@ -820,53 +973,135 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,  			      u32 *ref_div_p,  			      u32 *post_div_p)  { -	u32 target_clock = freq / 10; -	u32 post_div = avivo_get_post_div(pll, target_clock); -	u32 ref_div = pll->min_ref_div; -	u32 fb_div = 0, frac_fb_div = 0, tmp; +	unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? +		freq : freq / 10; -	if (pll->flags & RADEON_PLL_USE_REF_DIV) -		ref_div = pll->reference_div; +	unsigned fb_div_min, fb_div_max, fb_div; +	unsigned post_div_min, post_div_max, post_div; +	unsigned ref_div_min, ref_div_max, ref_div; +	unsigned post_div_best, diff_best; +	unsigned nom, den; + +	/* determine allowed feedback divider range */ +	fb_div_min = pll->min_feedback_div; +	fb_div_max = pll->max_feedback_div;  	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { -		avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div); -		frac_fb_div = (100 * frac_fb_div) / pll->reference_freq; -		if (frac_fb_div >= 5) { -			frac_fb_div -= 5; -			frac_fb_div = frac_fb_div / 10; -			frac_fb_div++; +		fb_div_min *= 10; +		fb_div_max *= 10; +	} + +	/* determine allowed ref divider range */ +	if (pll->flags & RADEON_PLL_USE_REF_DIV) +		ref_div_min = pll->reference_div; +	else +		ref_div_min = pll->min_ref_div; + +	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && +	    pll->flags & RADEON_PLL_USE_REF_DIV) +		ref_div_max = pll->reference_div; +	else +		ref_div_max = pll->max_ref_div; + +	/* determine allowed post divider range */ +	if (pll->flags & RADEON_PLL_USE_POST_DIV) { +		post_div_min = pll->post_div; +		post_div_max = pll->post_div; +	} else { +		unsigned vco_min, vco_max; + +		if (pll->flags & RADEON_PLL_IS_LCD) { +			vco_min = pll->lcd_pll_out_min; +			vco_max = pll->lcd_pll_out_max; +		} else { +			vco_min = pll->pll_out_min; +			vco_max = pll->pll_out_max;  		} -		if (frac_fb_div >= 10) { -			fb_div++; -			frac_fb_div = 0; + +		if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { +			vco_min *= 10; +			vco_max *= 10;  		} -	} else { -		while (ref_div <= pll->max_ref_div) { -			avivo_get_fb_div(pll, target_clock, post_div, ref_div, -					 &fb_div, &frac_fb_div); -			if (frac_fb_div >= (pll->reference_freq / 2)) -				fb_div++; -			frac_fb_div = 0; -			tmp = (pll->reference_freq * fb_div) / (post_div * ref_div); -			tmp = (tmp * 10000) / target_clock; - -			if (tmp > (10000 + MAX_TOLERANCE)) -				ref_div++; -			else if (tmp >= (10000 - MAX_TOLERANCE)) -				break; -			else -				ref_div++; + +		post_div_min = vco_min / target_clock; +		if ((target_clock * post_div_min) < vco_min) +			++post_div_min; +		if (post_div_min < pll->min_post_div) +			post_div_min = pll->min_post_div; + +		post_div_max = vco_max / target_clock; +		if ((target_clock * post_div_max) > vco_max) +			--post_div_max; +		if (post_div_max > pll->max_post_div) +			post_div_max = pll->max_post_div; +	} + +	/* represent the searched ratio as fractional number */ +	nom = target_clock; +	den = pll->reference_freq; + +	/* reduce the numbers to a simpler ratio */ +	avivo_reduce_ratio(&nom, &den, fb_div_min, post_div_min); + +	/* now search for a post divider */ +	if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) +		post_div_best = post_div_min; +	else +		post_div_best = post_div_max; +	diff_best = ~0; + +	for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { +		unsigned diff; +		avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, +				     ref_div_max, &fb_div, &ref_div); +		diff = abs(target_clock - (pll->reference_freq * fb_div) / +			(ref_div * post_div)); + +		if (diff < diff_best || (diff == diff_best && +		    !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { + +			post_div_best = post_div; +			diff_best = diff;  		}  	} +	post_div = post_div_best; + +	/* get the feedback and reference divider for the optimal value */ +	avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max, +			     &fb_div, &ref_div); + +	/* reduce the numbers to a simpler ratio once more */ +	/* this also makes sure that the reference divider is large enough */ +	avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min); + +	/* avoid high jitter with small fractional dividers */ +	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && (fb_div % 10)) { +		fb_div_min = max(fb_div_min, (9 - (fb_div % 10)) * 20 + 50); +		if (fb_div < fb_div_min) { +			unsigned tmp = DIV_ROUND_UP(fb_div_min, fb_div); +			fb_div *= tmp; +			ref_div *= tmp; +		} +	} + +	/* and finally save the result */ +	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { +		*fb_div_p = fb_div / 10; +		*frac_fb_div_p = fb_div % 10; +	} else { +		*fb_div_p = fb_div; +		*frac_fb_div_p = 0; +	} -	*dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) / -		(ref_div * post_div * 10); -	*fb_div_p = fb_div; -	*frac_fb_div_p = frac_fb_div; +	*dot_clock_p = ((pll->reference_freq * *fb_div_p * 10) + +			(pll->reference_freq * *frac_fb_div_p)) / +		       (ref_div * post_div * 10);  	*ref_div_p = ref_div;  	*post_div_p = post_div; -	DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n", -		      *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div); + +	DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", +		      freq, *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p, +		      ref_div, post_div);  }  /* pre-avivo */ @@ -1178,6 +1413,12 @@ static struct drm_prop_enum_list radeon_audio_enum_list[] =  	{ RADEON_AUDIO_AUTO, "auto" },  }; +/* XXX support different dither options? spatial, temporal, both, etc. */ +static struct drm_prop_enum_list radeon_dither_enum_list[] = +{	{ RADEON_FMT_DITHER_DISABLE, "off" }, +	{ RADEON_FMT_DITHER_ENABLE, "on" }, +}; +  static int radeon_modeset_create_props(struct radeon_device *rdev)  {  	int sz; @@ -1234,6 +1475,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)  					 "audio",  					 radeon_audio_enum_list, sz); +	sz = ARRAY_SIZE(radeon_dither_enum_list); +	rdev->mode_info.dither_property = +		drm_property_create_enum(rdev->ddev, 0, +					 "dither", +					 radeon_dither_enum_list, sz); +  	return 0;  } @@ -1407,12 +1654,22 @@ int radeon_modeset_init(struct radeon_device *rdev)  	/* setup afmt */  	radeon_afmt_init(rdev); -	/* Initialize power management */ -	radeon_pm_init(rdev); -  	radeon_fbdev_init(rdev);  	drm_kms_helper_poll_init(rdev->ddev); +	if (rdev->pm.dpm_enabled) { +		/* do dpm late init */ +		ret = radeon_pm_late_init(rdev); +		if (ret) { +			rdev->pm.dpm_enabled = false; +			DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); +		} +		/* set the dpm state for PX since there won't be +		 * a modeset to call this. +		 */ +		radeon_pm_compute_clocks(rdev); +	} +  	return 0;  } @@ -1420,7 +1677,6 @@ void radeon_modeset_fini(struct radeon_device *rdev)  {  	radeon_fbdev_fini(rdev);  	kfree(rdev->mode_info.bios_hardcoded_edid); -	radeon_pm_fini(rdev);  	if (rdev->mode_info.mode_config_initialized) {  		radeon_afmt_fini(rdev); @@ -1539,12 +1795,18 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,  }  /* - * Retrieve current video scanout position of crtc on a given gpu. + * Retrieve current video scanout position of crtc on a given gpu, and + * an optional accurate timestamp of when query happened.   *   * \param dev Device to query.   * \param crtc Crtc to query. + * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).   * \param *vpos Location where vertical scanout position should be stored.   * \param *hpos Location where horizontal scanout position should go. + * \param *stime Target location for timestamp taken immediately before + *               scanout position query. Can be NULL to skip timestamp. + * \param *etime Target location for timestamp taken immediately after + *               scanout position query. Can be NULL to skip timestamp.   *   * Returns vpos as a positive number while in active scanout area.   * Returns vpos as a negative number inside vblank, counting the number @@ -1560,7 +1822,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,   * unknown small number of scanlines wrt. real scanout position.   *   */ -int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos) +int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, +			       int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)  {  	u32 stat_crtc = 0, vbl = 0, position = 0;  	int vbl_start, vbl_end, vtotal, ret = 0; @@ -1568,6 +1831,12 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int  	struct radeon_device *rdev = dev->dev_private; +	/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ + +	/* Get optional system timestamp before query. */ +	if (stime) +		*stime = ktime_get(); +  	if (ASIC_IS_DCE4(rdev)) {  		if (crtc == 0) {  			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + @@ -1650,6 +1919,12 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int  		}  	} +	/* Get optional system timestamp after query. */ +	if (etime) +		*etime = ktime_get(); + +	/* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ +  	/* Decode into vertical and horizontal scanout position. */  	*vpos = position & 0x1fff;  	*hpos = (position >> 16) & 0x1fff; @@ -1690,5 +1965,27 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int  	if (in_vbl)  		ret |= DRM_SCANOUTPOS_INVBL; +	/* Is vpos outside nominal vblank area, but less than +	 * 1/100 of a frame height away from start of vblank? +	 * If so, assume this isn't a massively delayed vblank +	 * interrupt, but a vblank interrupt that fired a few +	 * microseconds before true start of vblank. Compensate +	 * by adding a full frame duration to the final timestamp. +	 * Happens, e.g., on ATI R500, R600. +	 * +	 * We only do this if DRM_CALLED_FROM_VBLIRQ. +	 */ +	if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { +		vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; +		vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; + +		if (vbl_start - *vpos < vtotal / 100) { +			*vpos -= vtotal; + +			/* Signal this correction as "applied". */ +			ret |= 0x8; +		} +	} +  	return ret;  } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index cdd12dcd988..e9e36108424 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -36,8 +36,9 @@  #include <drm/drm_pciids.h>  #include <linux/console.h>  #include <linux/module.h> - - +#include <linux/pm_runtime.h> +#include <linux/vga_switcheroo.h> +#include "drm_crtc_helper.h"  /*   * KMS wrapper.   * - 2.0.0 - initial interface @@ -75,9 +76,15 @@   *   2.32.0 - new info request for rings working   *   2.33.0 - Add SI tiling mode array query   *   2.34.0 - Add CIK tiling mode array query + *   2.35.0 - Add CIK macrotile mode array query + *   2.36.0 - Fix CIK DCE tiling setup + *   2.37.0 - allow GS ring setup on r6xx/r7xx + *   2.38.0 - RADEON_GEM_OP (GET_INITIAL_DOMAIN, SET_INITIAL_DOMAIN), + *            CIK: 1D and linear tiling modes contain valid PIPE_CONFIG + *   2.39.0 - Add INFO query for number of active CUs   */  #define KMS_DRIVER_MAJOR	2 -#define KMS_DRIVER_MINOR	34 +#define KMS_DRIVER_MINOR	39  #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); @@ -87,8 +94,8 @@ void radeon_driver_postclose_kms(struct drm_device *dev,  				 struct drm_file *file_priv);  void radeon_driver_preclose_kms(struct drm_device *dev,  				struct drm_file *file_priv); -int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); -int radeon_resume_kms(struct drm_device *dev); +int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon); +int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);  u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc);  int radeon_enable_vblank_kms(struct drm_device *dev, int crtc);  void radeon_disable_vblank_kms(struct drm_device *dev, int crtc); @@ -99,15 +106,17 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,  void radeon_driver_irq_preinstall_kms(struct drm_device *dev);  int radeon_driver_irq_postinstall_kms(struct drm_device *dev);  void radeon_driver_irq_uninstall_kms(struct drm_device *dev); -irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS); -int radeon_gem_object_init(struct drm_gem_object *obj); +irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg);  void radeon_gem_object_free(struct drm_gem_object *obj);  int radeon_gem_object_open(struct drm_gem_object *obj,  				struct drm_file *file_priv);  void radeon_gem_object_close(struct drm_gem_object *obj,  				struct drm_file *file_priv);  extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, -				      int *vpos, int *hpos); +				      unsigned int flags, +				      int *vpos, int *hpos, ktime_t *stime, +				      ktime_t *etime); +extern bool radeon_is_px(struct drm_device *dev);  extern const struct drm_ioctl_desc radeon_ioctls_kms[];  extern int radeon_max_kms_ioctl;  int radeon_mmap(struct file *filp, struct vm_area_struct *vma); @@ -153,7 +162,7 @@ int radeon_benchmarking = 0;  int radeon_testing = 0;  int radeon_connector_table = 0;  int radeon_tv = 1; -int radeon_audio = 1; +int radeon_audio = -1;  int radeon_disp_priority = 0;  int radeon_hw_i2c = 0;  int radeon_pcie_gen2 = -1; @@ -162,6 +171,11 @@ int radeon_lockup_timeout = 10000;  int radeon_fastfb = 0;  int radeon_dpm = -1;  int radeon_aspm = -1; +int radeon_runtime_pm = -1; +int radeon_hard_reset = 0; +int radeon_vm_size = 4; +int radeon_vm_block_size = 9; +int radeon_deep_color = 0;  MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");  module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -175,7 +189,7 @@ module_param_named(dynclks, radeon_dynclks, int, 0444);  MODULE_PARM_DESC(r4xx_atom, "Enable ATOMBIOS modesetting for R4xx");  module_param_named(r4xx_atom, radeon_r4xx_atom, int, 0444); -MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing"); +MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");  module_param_named(vramlimit, radeon_vram_limit, int, 0600);  MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); @@ -196,7 +210,7 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);  MODULE_PARM_DESC(tv, "TV enable (0 = disable)");  module_param_named(tv, radeon_tv, int, 0444); -MODULE_PARM_DESC(audio, "Audio enable (1 = enable)"); +MODULE_PARM_DESC(audio, "Audio enable (-1 = auto, 0 = disable, 1 = enable)");  module_param_named(audio, radeon_audio, int, 0444);  MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)"); @@ -223,6 +237,21 @@ module_param_named(dpm, radeon_dpm, int, 0444);  MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)");  module_param_named(aspm, radeon_aspm, int, 0444); +MODULE_PARM_DESC(runpm, "PX runtime pm (1 = force enable, 0 = disable, -1 = PX only default)"); +module_param_named(runpm, radeon_runtime_pm, int, 0444); + +MODULE_PARM_DESC(hard_reset, "PCI config reset (1 = force enable, 0 = disable (default))"); +module_param_named(hard_reset, radeon_hard_reset, int, 0444); + +MODULE_PARM_DESC(vm_size, "VM address space size in gigabytes (default 4GB)"); +module_param_named(vm_size, radeon_vm_size, int, 0444); + +MODULE_PARM_DESC(vm_block_size, "VM page table size in bits (default 9)"); +module_param_named(vm_block_size, radeon_vm_block_size, int, 0444); + +MODULE_PARM_DESC(deep_color, "Deep Color support (1 = enable, 0 = disable (default))"); +module_param_named(deep_color, radeon_deep_color, int, 0444); +  static struct pci_device_id pciidlist[] = {  	radeon_PCI_IDS  }; @@ -259,6 +288,7 @@ static int radeon_resume(struct drm_device *dev)  	return 0;  } +  static const struct file_operations radeon_driver_old_fops = {  	.owner = THIS_MODULE,  	.open = drm_open, @@ -353,25 +383,142 @@ radeon_pci_remove(struct pci_dev *pdev)  	drm_put_dev(dev);  } -static int -radeon_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int radeon_pmops_suspend(struct device *dev)  { -	struct drm_device *dev = pci_get_drvdata(pdev); -	return radeon_suspend_kms(dev, state); +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	return radeon_suspend_kms(drm_dev, true, true);  } -static int -radeon_pci_resume(struct pci_dev *pdev) +static int radeon_pmops_resume(struct device *dev)  { -	struct drm_device *dev = pci_get_drvdata(pdev); -	return radeon_resume_kms(dev); +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	return radeon_resume_kms(drm_dev, true, true); +} + +static int radeon_pmops_freeze(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	return radeon_suspend_kms(drm_dev, false, true); +} + +static int radeon_pmops_thaw(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	return radeon_resume_kms(drm_dev, false, true); +} + +static int radeon_pmops_runtime_suspend(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	int ret; + +	if (!radeon_is_px(drm_dev)) { +		pm_runtime_forbid(dev); +		return -EBUSY; +	} + +	drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; +	drm_kms_helper_poll_disable(drm_dev); +	vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); + +	ret = radeon_suspend_kms(drm_dev, false, false); +	pci_save_state(pdev); +	pci_disable_device(pdev); +	pci_set_power_state(pdev, PCI_D3cold); +	drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; + +	return 0; +} + +static int radeon_pmops_runtime_resume(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	int ret; + +	if (!radeon_is_px(drm_dev)) +		return -EINVAL; + +	drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + +	pci_set_power_state(pdev, PCI_D0); +	pci_restore_state(pdev); +	ret = pci_enable_device(pdev); +	if (ret) +		return ret; +	pci_set_master(pdev); + +	ret = radeon_resume_kms(drm_dev, false, false); +	drm_kms_helper_poll_enable(drm_dev); +	vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); +	drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; +	return 0;  } +static int radeon_pmops_runtime_idle(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	struct drm_crtc *crtc; + +	if (!radeon_is_px(drm_dev)) { +		pm_runtime_forbid(dev); +		return -EBUSY; +	} + +	list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { +		if (crtc->enabled) { +			DRM_DEBUG_DRIVER("failing to power off - crtc active\n"); +			return -EBUSY; +		} +	} + +	pm_runtime_mark_last_busy(dev); +	pm_runtime_autosuspend(dev); +	/* we don't want the main rpm_idle to call suspend - we want to autosuspend */ +	return 1; +} + +long radeon_drm_ioctl(struct file *filp, +		      unsigned int cmd, unsigned long arg) +{ +	struct drm_file *file_priv = filp->private_data; +	struct drm_device *dev; +	long ret; +	dev = file_priv->minor->dev; +	ret = pm_runtime_get_sync(dev->dev); +	if (ret < 0) +		return ret; + +	ret = drm_ioctl(filp, cmd, arg); +	 +	pm_runtime_mark_last_busy(dev->dev); +	pm_runtime_put_autosuspend(dev->dev); +	return ret; +} + +static const struct dev_pm_ops radeon_pm_ops = { +	.suspend = radeon_pmops_suspend, +	.resume = radeon_pmops_resume, +	.freeze = radeon_pmops_freeze, +	.thaw = radeon_pmops_thaw, +	.poweroff = radeon_pmops_freeze, +	.restore = radeon_pmops_resume, +	.runtime_suspend = radeon_pmops_runtime_suspend, +	.runtime_resume = radeon_pmops_runtime_resume, +	.runtime_idle = radeon_pmops_runtime_idle, +}; +  static const struct file_operations radeon_driver_kms_fops = {  	.owner = THIS_MODULE,  	.open = drm_open,  	.release = drm_release, -	.unlocked_ioctl = drm_ioctl, +	.unlocked_ioctl = radeon_drm_ioctl,  	.mmap = radeon_mmap,  	.poll = drm_poll,  	.read = drm_read, @@ -385,15 +532,12 @@ static struct drm_driver kms_driver = {  	    DRIVER_USE_AGP |  	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |  	    DRIVER_PRIME | DRIVER_RENDER, -	.dev_priv_size = 0,  	.load = radeon_driver_load_kms,  	.open = radeon_driver_open_kms,  	.preclose = radeon_driver_preclose_kms,  	.postclose = radeon_driver_postclose_kms,  	.lastclose = radeon_driver_lastclose_kms,  	.unload = radeon_driver_unload_kms, -	.suspend = radeon_suspend_kms, -	.resume = radeon_resume_kms,  	.get_vblank_counter = radeon_get_vblank_counter_kms,  	.enable_vblank = radeon_enable_vblank_kms,  	.disable_vblank = radeon_disable_vblank_kms, @@ -408,7 +552,6 @@ static struct drm_driver kms_driver = {  	.irq_uninstall = radeon_driver_irq_uninstall_kms,  	.irq_handler = radeon_driver_irq_handler_kms,  	.ioctls = radeon_ioctls_kms, -	.gem_init_object = radeon_gem_object_init,  	.gem_free_object = radeon_gem_object_free,  	.gem_open_object = radeon_gem_object_open,  	.gem_close_object = radeon_gem_object_close, @@ -451,8 +594,7 @@ static struct pci_driver radeon_kms_pci_driver = {  	.id_table = pciidlist,  	.probe = radeon_pci_probe,  	.remove = radeon_pci_remove, -	.suspend = radeon_pci_suspend, -	.resume = radeon_pci_resume, +	.driver.pm = &radeon_pm_ops,  };  static int __init radeon_init(void) diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index b369d42f7de..dafd812e457 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -108,11 +108,15 @@   * 1.31- Add support for num Z pipes from GET_PARAM   * 1.32- fixes for rv740 setup   * 1.33- Add r6xx/r7xx const buffer support + * 1.34- fix evergreen/cayman GS register   */  #define DRIVER_MAJOR		1 -#define DRIVER_MINOR		33 +#define DRIVER_MINOR		34  #define DRIVER_PATCHLEVEL	0 +long radeon_drm_ioctl(struct file *filp, +		      unsigned int cmd, unsigned long arg); +  /* The rest of the file is DEPRECATED! */  #ifdef CONFIG_DRM_RADEON_UMS @@ -401,7 +405,7 @@ extern void radeon_do_release(struct drm_device * dev);  extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);  extern int radeon_enable_vblank(struct drm_device *dev, int crtc);  extern void radeon_disable_vblank(struct drm_device *dev, int crtc); -extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); +extern irqreturn_t radeon_driver_irq_handler(int irq, void *arg);  extern void radeon_driver_irq_preinstall(struct drm_device * dev);  extern int radeon_driver_irq_postinstall(struct drm_device *dev);  extern void radeon_driver_irq_uninstall(struct drm_device * dev); diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h index 3c8289083f9..4b7b87f71a6 100644 --- a/drivers/gpu/drm/radeon/radeon_family.h +++ b/drivers/gpu/drm/radeon/radeon_family.h @@ -96,6 +96,8 @@ enum radeon_family {  	CHIP_BONAIRE,  	CHIP_KAVERI,  	CHIP_KABINI, +	CHIP_HAWAII, +	CHIP_MULLINS,  	CHIP_LAST,  }; @@ -114,6 +116,7 @@ enum radeon_chip_flags {  	RADEON_NEW_MEMMAP = 0x00400000UL,  	RADEON_IS_PCI = 0x00800000UL,  	RADEON_IS_IGPGART = 0x01000000UL, +	RADEON_IS_PX = 0x02000000UL,  };  #endif diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index ddb8f8e04eb..913787085df 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -121,7 +121,7 @@ int radeon_fence_emit(struct radeon_device *rdev,  	(*fence)->seq = ++rdev->fence_drv[ring].sync_seq[ring];  	(*fence)->ring = ring;  	radeon_fence_ring_emit(rdev, ring, *fence); -	trace_radeon_fence_emit(rdev->ddev, (*fence)->seq); +	trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq);  	return 0;  } @@ -190,10 +190,8 @@ void radeon_fence_process(struct radeon_device *rdev, int ring)  		}  	} while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq); -	if (wake) { -		rdev->fence_drv[ring].last_activity = jiffies; +	if (wake)  		wake_up_all(&rdev->fence_queue); -	}  }  /** @@ -212,13 +210,13 @@ static void radeon_fence_destroy(struct kref *kref)  }  /** - * radeon_fence_seq_signaled - check if a fence sequeuce number has signaled + * radeon_fence_seq_signaled - check if a fence sequence number has signaled   *   * @rdev: radeon device pointer   * @seq: sequence number   * @ring: ring index the fence is associated with   * - * Check if the last singled fence sequnce number is >= the requested + * Check if the last signaled fence sequnce number is >= the requested   * sequence number (all asics).   * Returns true if the fence has signaled (current fence value   * is >= requested value) or false if it has not (current fence @@ -263,113 +261,122 @@ bool radeon_fence_signaled(struct radeon_fence *fence)  }  /** - * radeon_fence_wait_seq - wait for a specific sequence number + * radeon_fence_any_seq_signaled - check if any sequence number is signaled   *   * @rdev: radeon device pointer - * @target_seq: sequence number we want to wait for - * @ring: ring index the fence is associated with + * @seq: sequence numbers + * + * Check if the last signaled fence sequnce number is >= the requested + * sequence number (all asics). + * Returns true if any has signaled (current value is >= requested value) + * or false if it has not. Helper function for radeon_fence_wait_seq. + */ +static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq) +{ +	unsigned i; + +	for (i = 0; i < RADEON_NUM_RINGS; ++i) { +		if (seq[i] && radeon_fence_seq_signaled(rdev, seq[i], i)) +			return true; +	} +	return false; +} + +/** + * radeon_fence_wait_seq - wait for a specific sequence numbers + * + * @rdev: radeon device pointer + * @target_seq: sequence number(s) we want to wait for   * @intr: use interruptable sleep - * @lock_ring: whether the ring should be locked or not   * - * Wait for the requested sequence number to be written (all asics). + * Wait for the requested sequence number(s) to be written by any ring + * (all asics).  Sequnce number array is indexed by ring id.   * @intr selects whether to use interruptable (true) or non-interruptable   * (false) sleep when waiting for the sequence number.  Helper function - * for radeon_fence_wait(), et al. + * for radeon_fence_wait_*().   * Returns 0 if the sequence number has passed, error for all other cases. - * -EDEADLK is returned when a GPU lockup has been detected and the ring is - * marked as not ready so no further jobs get scheduled until a successful - * reset. + * -EDEADLK is returned when a GPU lockup has been detected.   */ -static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq, -				 unsigned ring, bool intr, bool lock_ring) +static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq, +				 bool intr)  { -	unsigned long timeout, last_activity; -	uint64_t seq; -	unsigned i; +	uint64_t last_seq[RADEON_NUM_RINGS];  	bool signaled; -	int r; +	int i, r; + +	while (!radeon_fence_any_seq_signaled(rdev, target_seq)) { -	while (target_seq > atomic64_read(&rdev->fence_drv[ring].last_seq)) { -		if (!rdev->ring[ring].ready) { -			return -EBUSY; +		/* Save current sequence values, used to check for GPU lockups */ +		for (i = 0; i < RADEON_NUM_RINGS; ++i) { +			if (!target_seq[i]) +				continue; + +			last_seq[i] = atomic64_read(&rdev->fence_drv[i].last_seq); +			trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]); +			radeon_irq_kms_sw_irq_get(rdev, i);  		} -		timeout = jiffies - RADEON_FENCE_JIFFIES_TIMEOUT; -		if (time_after(rdev->fence_drv[ring].last_activity, timeout)) { -			/* the normal case, timeout is somewhere before last_activity */ -			timeout = rdev->fence_drv[ring].last_activity - timeout; +		if (intr) { +			r = wait_event_interruptible_timeout(rdev->fence_queue, ( +				(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)) +				 || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT);  		} else { -			/* either jiffies wrapped around, or no fence was signaled in the last 500ms -			 * anyway we will just wait for the minimum amount and then check for a lockup -			 */ -			timeout = 1; +			r = wait_event_timeout(rdev->fence_queue, ( +				(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)) +				 || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT);  		} -		seq = atomic64_read(&rdev->fence_drv[ring].last_seq); -		/* Save current last activity valuee, used to check for GPU lockups */ -		last_activity = rdev->fence_drv[ring].last_activity; -		trace_radeon_fence_wait_begin(rdev->ddev, seq); -		radeon_irq_kms_sw_irq_get(rdev, ring); -		if (intr) { -			r = wait_event_interruptible_timeout(rdev->fence_queue, -				(signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)), -				timeout); -                } else { -			r = wait_event_timeout(rdev->fence_queue, -				(signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)), -				timeout); +		for (i = 0; i < RADEON_NUM_RINGS; ++i) { +			if (!target_seq[i]) +				continue; + +			radeon_irq_kms_sw_irq_put(rdev, i); +			trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]);  		} -		radeon_irq_kms_sw_irq_put(rdev, ring); -		if (unlikely(r < 0)) { + +		if (unlikely(r < 0))  			return r; -		} -		trace_radeon_fence_wait_end(rdev->ddev, seq);  		if (unlikely(!signaled)) { +			if (rdev->needs_reset) +				return -EDEADLK; +  			/* we were interrupted for some reason and fence  			 * isn't signaled yet, resume waiting */ -			if (r) { +			if (r)  				continue; -			} -			/* check if sequence value has changed since last_activity */ -			if (seq != atomic64_read(&rdev->fence_drv[ring].last_seq)) { -				continue; -			} +			for (i = 0; i < RADEON_NUM_RINGS; ++i) { +				if (!target_seq[i]) +					continue; -			if (lock_ring) { -				mutex_lock(&rdev->ring_lock); +				if (last_seq[i] != atomic64_read(&rdev->fence_drv[i].last_seq)) +					break;  			} -			/* test if somebody else has already decided that this is a lockup */ -			if (last_activity != rdev->fence_drv[ring].last_activity) { -				if (lock_ring) { -					mutex_unlock(&rdev->ring_lock); -				} +			if (i != RADEON_NUM_RINGS)  				continue; + +			for (i = 0; i < RADEON_NUM_RINGS; ++i) { +				if (!target_seq[i]) +					continue; + +				if (radeon_ring_is_lockup(rdev, i, &rdev->ring[i])) +					break;  			} -			if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) { +			if (i < RADEON_NUM_RINGS) {  				/* good news we believe it's a lockup */ -				dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016llx last fence id 0x%016llx)\n", -					 target_seq, seq); - -				/* change last activity so nobody else think there is a lockup */ -				for (i = 0; i < RADEON_NUM_RINGS; ++i) { -					rdev->fence_drv[i].last_activity = jiffies; -				} - -				/* mark the ring as not ready any more */ -				rdev->ring[ring].ready = false; -				if (lock_ring) { -					mutex_unlock(&rdev->ring_lock); -				} +				dev_warn(rdev->dev, "GPU lockup (waiting for " +					 "0x%016llx last fence id 0x%016llx on" +					 " ring %d)\n", +					 target_seq[i], last_seq[i], i); + +				/* remember that we need an reset */ +				rdev->needs_reset = true; +				wake_up_all(&rdev->fence_queue);  				return -EDEADLK;  			} - -			if (lock_ring) { -				mutex_unlock(&rdev->ring_lock); -			}  		}  	}  	return 0; @@ -388,6 +395,7 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq,   */  int radeon_fence_wait(struct radeon_fence *fence, bool intr)  { +	uint64_t seq[RADEON_NUM_RINGS] = {};  	int r;  	if (fence == NULL) { @@ -395,147 +403,15 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr)  		return -EINVAL;  	} -	r = radeon_fence_wait_seq(fence->rdev, fence->seq, -				  fence->ring, intr, true); -	if (r) { -		return r; -	} -	fence->seq = RADEON_FENCE_SIGNALED_SEQ; -	return 0; -} - -static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq) -{ -	unsigned i; - -	for (i = 0; i < RADEON_NUM_RINGS; ++i) { -		if (seq[i] && radeon_fence_seq_signaled(rdev, seq[i], i)) { -			return true; -		} -	} -	return false; -} - -/** - * radeon_fence_wait_any_seq - wait for a sequence number on any ring - * - * @rdev: radeon device pointer - * @target_seq: sequence number(s) we want to wait for - * @intr: use interruptable sleep - * - * Wait for the requested sequence number(s) to be written by any ring - * (all asics).  Sequnce number array is indexed by ring id. - * @intr selects whether to use interruptable (true) or non-interruptable - * (false) sleep when waiting for the sequence number.  Helper function - * for radeon_fence_wait_any(), et al. - * Returns 0 if the sequence number has passed, error for all other cases. - */ -static int radeon_fence_wait_any_seq(struct radeon_device *rdev, -				     u64 *target_seq, bool intr) -{ -	unsigned long timeout, last_activity, tmp; -	unsigned i, ring = RADEON_NUM_RINGS; -	bool signaled; -	int r; - -	for (i = 0, last_activity = 0; i < RADEON_NUM_RINGS; ++i) { -		if (!target_seq[i]) { -			continue; -		} - -		/* use the most recent one as indicator */ -		if (time_after(rdev->fence_drv[i].last_activity, last_activity)) { -			last_activity = rdev->fence_drv[i].last_activity; -		} - -		/* For lockup detection just pick the lowest ring we are -		 * actively waiting for -		 */ -		if (i < ring) { -			ring = i; -		} -	} - -	/* nothing to wait for ? */ -	if (ring == RADEON_NUM_RINGS) { -		return -ENOENT; -	} - -	while (!radeon_fence_any_seq_signaled(rdev, target_seq)) { -		timeout = jiffies - RADEON_FENCE_JIFFIES_TIMEOUT; -		if (time_after(last_activity, timeout)) { -			/* the normal case, timeout is somewhere before last_activity */ -			timeout = last_activity - timeout; -		} else { -			/* either jiffies wrapped around, or no fence was signaled in the last 500ms -			 * anyway we will just wait for the minimum amount and then check for a lockup -			 */ -			timeout = 1; -		} - -		trace_radeon_fence_wait_begin(rdev->ddev, target_seq[ring]); -		for (i = 0; i < RADEON_NUM_RINGS; ++i) { -			if (target_seq[i]) { -				radeon_irq_kms_sw_irq_get(rdev, i); -			} -		} -		if (intr) { -			r = wait_event_interruptible_timeout(rdev->fence_queue, -				(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)), -				timeout); -		} else { -			r = wait_event_timeout(rdev->fence_queue, -				(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)), -				timeout); -		} -		for (i = 0; i < RADEON_NUM_RINGS; ++i) { -			if (target_seq[i]) { -				radeon_irq_kms_sw_irq_put(rdev, i); -			} -		} -		if (unlikely(r < 0)) { -			return r; -		} -		trace_radeon_fence_wait_end(rdev->ddev, target_seq[ring]); +	seq[fence->ring] = fence->seq; +	if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ) +		return 0; -		if (unlikely(!signaled)) { -			/* we were interrupted for some reason and fence -			 * isn't signaled yet, resume waiting */ -			if (r) { -				continue; -			} - -			mutex_lock(&rdev->ring_lock); -			for (i = 0, tmp = 0; i < RADEON_NUM_RINGS; ++i) { -				if (time_after(rdev->fence_drv[i].last_activity, tmp)) { -					tmp = rdev->fence_drv[i].last_activity; -				} -			} -			/* test if somebody else has already decided that this is a lockup */ -			if (last_activity != tmp) { -				last_activity = tmp; -				mutex_unlock(&rdev->ring_lock); -				continue; -			} - -			if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) { -				/* good news we believe it's a lockup */ -				dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016llx)\n", -					 target_seq[ring]); - -				/* change last activity so nobody else think there is a lockup */ -				for (i = 0; i < RADEON_NUM_RINGS; ++i) { -					rdev->fence_drv[i].last_activity = jiffies; -				} +	r = radeon_fence_wait_seq(fence->rdev, seq, intr); +	if (r) +		return r; -				/* mark the ring as not ready any more */ -				rdev->ring[ring].ready = false; -				mutex_unlock(&rdev->ring_lock); -				return -EDEADLK; -			} -			mutex_unlock(&rdev->ring_lock); -		} -	} +	fence->seq = RADEON_FENCE_SIGNALED_SEQ;  	return 0;  } @@ -557,7 +433,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev,  			  bool intr)  {  	uint64_t seq[RADEON_NUM_RINGS]; -	unsigned i; +	unsigned i, num_rings = 0;  	int r;  	for (i = 0; i < RADEON_NUM_RINGS; ++i) { @@ -567,15 +443,19 @@ int radeon_fence_wait_any(struct radeon_device *rdev,  			continue;  		} -		if (fences[i]->seq == RADEON_FENCE_SIGNALED_SEQ) { -			/* something was allready signaled */ -			return 0; -		} -  		seq[i] = fences[i]->seq; +		++num_rings; + +		/* test if something was allready signaled */ +		if (seq[i] == RADEON_FENCE_SIGNALED_SEQ) +			return 0;  	} -	r = radeon_fence_wait_any_seq(rdev, seq, intr); +	/* nothing to wait for ? */ +	if (num_rings == 0) +		return -ENOENT; + +	r = radeon_fence_wait_seq(rdev, seq, intr);  	if (r) {  		return r;  	} @@ -583,7 +463,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev,  }  /** - * radeon_fence_wait_next_locked - wait for the next fence to signal + * radeon_fence_wait_next - wait for the next fence to signal   *   * @rdev: radeon device pointer   * @ring: ring index the fence is associated with @@ -592,21 +472,21 @@ int radeon_fence_wait_any(struct radeon_device *rdev,   * Returns 0 if the next fence has passed, error for all other cases.   * Caller must hold ring lock.   */ -int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring) +int radeon_fence_wait_next(struct radeon_device *rdev, int ring)  { -	uint64_t seq; +	uint64_t seq[RADEON_NUM_RINGS] = {}; -	seq = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; -	if (seq >= rdev->fence_drv[ring].sync_seq[ring]) { +	seq[ring] = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; +	if (seq[ring] >= rdev->fence_drv[ring].sync_seq[ring]) {  		/* nothing to wait for, last_seq is  		   already the last emited fence */  		return -ENOENT;  	} -	return radeon_fence_wait_seq(rdev, seq, ring, false, false); +	return radeon_fence_wait_seq(rdev, seq, false);  }  /** - * radeon_fence_wait_empty_locked - wait for all fences to signal + * radeon_fence_wait_empty - wait for all fences to signal   *   * @rdev: radeon device pointer   * @ring: ring index the fence is associated with @@ -615,16 +495,20 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)   * Returns 0 if the fences have passed, error for all other cases.   * Caller must hold ring lock.   */ -int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) +int radeon_fence_wait_empty(struct radeon_device *rdev, int ring)  { -	uint64_t seq = rdev->fence_drv[ring].sync_seq[ring]; +	uint64_t seq[RADEON_NUM_RINGS] = {};  	int r; -	r = radeon_fence_wait_seq(rdev, seq, ring, false, false); +	seq[ring] = rdev->fence_drv[ring].sync_seq[ring]; +	if (!seq[ring]) +		return 0; + +	r = radeon_fence_wait_seq(rdev, seq, false);  	if (r) { -		if (r == -EDEADLK) { +		if (r == -EDEADLK)  			return -EDEADLK; -		} +  		dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n",  			ring, r);  	} @@ -826,7 +710,6 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring)  	for (i = 0; i < RADEON_NUM_RINGS; ++i)  		rdev->fence_drv[ring].sync_seq[i] = 0;  	atomic64_set(&rdev->fence_drv[ring].last_seq, 0); -	rdev->fence_drv[ring].last_activity = jiffies;  	rdev->fence_drv[ring].initialized = false;  } @@ -872,7 +755,7 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)  	for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {  		if (!rdev->fence_drv[ring].initialized)  			continue; -		r = radeon_fence_wait_empty_locked(rdev, ring); +		r = radeon_fence_wait_empty(rdev, ring);  		if (r) {  			/* no need to trigger GPU reset as we are unloading */  			radeon_fence_driver_force_completion(rdev); @@ -919,6 +802,8 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data)  		if (!rdev->fence_drv[i].initialized)  			continue; +		radeon_fence_process(rdev, i); +  		seq_printf(m, "--- ring %d ---\n", i);  		seq_printf(m, "Last signaled fence 0x%016llx\n",  			   (unsigned long long)atomic64_read(&rdev->fence_drv[i].last_seq)); @@ -934,15 +819,35 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data)  	return 0;  } +/** + * radeon_debugfs_gpu_reset - manually trigger a gpu reset + * + * Manually trigger a gpu reset at the next fence wait. + */ +static int radeon_debugfs_gpu_reset(struct seq_file *m, void *data) +{ +	struct drm_info_node *node = (struct drm_info_node *) m->private; +	struct drm_device *dev = node->minor->dev; +	struct radeon_device *rdev = dev->dev_private; + +	down_read(&rdev->exclusive_lock); +	seq_printf(m, "%d\n", rdev->needs_reset); +	rdev->needs_reset = true; +	up_read(&rdev->exclusive_lock); + +	return 0; +} +  static struct drm_info_list radeon_debugfs_fence_list[] = {  	{"radeon_fence_info", &radeon_debugfs_fence_info, 0, NULL}, +	{"radeon_gpu_reset", &radeon_debugfs_gpu_reset, 0, NULL}  };  #endif  int radeon_debugfs_fence_init(struct radeon_device *rdev)  {  #if defined(CONFIG_DEBUG_FS) -	return radeon_debugfs_add_files(rdev, radeon_debugfs_fence_list, 1); +	return radeon_debugfs_add_files(rdev, radeon_debugfs_fence_list, 2);  #else  	return 0;  #endif diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index b990b1a2bd5..2e723651069 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -28,7 +28,6 @@  #include <drm/drmP.h>  #include <drm/radeon_drm.h>  #include "radeon.h" -#include "radeon_reg.h"  /*   * GART @@ -393,894 +392,3 @@ void radeon_gart_fini(struct radeon_device *rdev)  	radeon_dummy_page_fini(rdev);  } - -/* - * GPUVM - * GPUVM is similar to the legacy gart on older asics, however - * rather than there being a single global gart table - * for the entire GPU, there are multiple VM page tables active - * at any given time.  The VM page tables can contain a mix - * vram pages and system memory pages and system memory pages - * can be mapped as snooped (cached system pages) or unsnooped - * (uncached system pages). - * Each VM has an ID associated with it and there is a page table - * associated with each VMID.  When execting a command buffer, - * the kernel tells the the ring what VMID to use for that command - * buffer.  VMIDs are allocated dynamically as commands are submitted. - * The userspace drivers maintain their own address space and the kernel - * sets up their pages tables accordingly when they submit their - * command buffers and a VMID is assigned. - * Cayman/Trinity support up to 8 active VMs at any given time; - * SI supports 16. - */ - -/* - * vm helpers - * - * TODO bind a default page at vm initialization for default address - */ - -/** - * radeon_vm_num_pde - return the number of page directory entries - * - * @rdev: radeon_device pointer - * - * Calculate the number of page directory entries (cayman+). - */ -static unsigned radeon_vm_num_pdes(struct radeon_device *rdev) -{ -	return rdev->vm_manager.max_pfn >> RADEON_VM_BLOCK_SIZE; -} - -/** - * radeon_vm_directory_size - returns the size of the page directory in bytes - * - * @rdev: radeon_device pointer - * - * Calculate the size of the page directory in bytes (cayman+). - */ -static unsigned radeon_vm_directory_size(struct radeon_device *rdev) -{ -	return RADEON_GPU_PAGE_ALIGN(radeon_vm_num_pdes(rdev) * 8); -} - -/** - * radeon_vm_manager_init - init the vm manager - * - * @rdev: radeon_device pointer - * - * Init the vm manager (cayman+). - * Returns 0 for success, error for failure. - */ -int radeon_vm_manager_init(struct radeon_device *rdev) -{ -	struct radeon_vm *vm; -	struct radeon_bo_va *bo_va; -	int r; -	unsigned size; - -	if (!rdev->vm_manager.enabled) { -		/* allocate enough for 2 full VM pts */ -		size = radeon_vm_directory_size(rdev); -		size += rdev->vm_manager.max_pfn * 8; -		size *= 2; -		r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager, -					      RADEON_GPU_PAGE_ALIGN(size), -					      RADEON_VM_PTB_ALIGN_SIZE, -					      RADEON_GEM_DOMAIN_VRAM); -		if (r) { -			dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n", -				(rdev->vm_manager.max_pfn * 8) >> 10); -			return r; -		} - -		r = radeon_asic_vm_init(rdev); -		if (r) -			return r; - -		rdev->vm_manager.enabled = true; - -		r = radeon_sa_bo_manager_start(rdev, &rdev->vm_manager.sa_manager); -		if (r) -			return r; -	} - -	/* restore page table */ -	list_for_each_entry(vm, &rdev->vm_manager.lru_vm, list) { -		if (vm->page_directory == NULL) -			continue; - -		list_for_each_entry(bo_va, &vm->va, vm_list) { -			bo_va->valid = false; -		} -	} -	return 0; -} - -/** - * radeon_vm_free_pt - free the page table for a specific vm - * - * @rdev: radeon_device pointer - * @vm: vm to unbind - * - * Free the page table of a specific vm (cayman+). - * - * Global and local mutex must be lock! - */ -static void radeon_vm_free_pt(struct radeon_device *rdev, -				    struct radeon_vm *vm) -{ -	struct radeon_bo_va *bo_va; -	int i; - -	if (!vm->page_directory) -		return; - -	list_del_init(&vm->list); -	radeon_sa_bo_free(rdev, &vm->page_directory, vm->fence); - -	list_for_each_entry(bo_va, &vm->va, vm_list) { -		bo_va->valid = false; -	} - -	if (vm->page_tables == NULL) -		return; - -	for (i = 0; i < radeon_vm_num_pdes(rdev); i++) -		radeon_sa_bo_free(rdev, &vm->page_tables[i], vm->fence); - -	kfree(vm->page_tables); -} - -/** - * radeon_vm_manager_fini - tear down the vm manager - * - * @rdev: radeon_device pointer - * - * Tear down the VM manager (cayman+). - */ -void radeon_vm_manager_fini(struct radeon_device *rdev) -{ -	struct radeon_vm *vm, *tmp; -	int i; - -	if (!rdev->vm_manager.enabled) -		return; - -	mutex_lock(&rdev->vm_manager.lock); -	/* free all allocated page tables */ -	list_for_each_entry_safe(vm, tmp, &rdev->vm_manager.lru_vm, list) { -		mutex_lock(&vm->mutex); -		radeon_vm_free_pt(rdev, vm); -		mutex_unlock(&vm->mutex); -	} -	for (i = 0; i < RADEON_NUM_VM; ++i) { -		radeon_fence_unref(&rdev->vm_manager.active[i]); -	} -	radeon_asic_vm_fini(rdev); -	mutex_unlock(&rdev->vm_manager.lock); - -	radeon_sa_bo_manager_suspend(rdev, &rdev->vm_manager.sa_manager); -	radeon_sa_bo_manager_fini(rdev, &rdev->vm_manager.sa_manager); -	rdev->vm_manager.enabled = false; -} - -/** - * radeon_vm_evict - evict page table to make room for new one - * - * @rdev: radeon_device pointer - * @vm: VM we want to allocate something for - * - * Evict a VM from the lru, making sure that it isn't @vm. (cayman+). - * Returns 0 for success, -ENOMEM for failure. - * - * Global and local mutex must be locked! - */ -static int radeon_vm_evict(struct radeon_device *rdev, struct radeon_vm *vm) -{ -	struct radeon_vm *vm_evict; - -	if (list_empty(&rdev->vm_manager.lru_vm)) -		return -ENOMEM; - -	vm_evict = list_first_entry(&rdev->vm_manager.lru_vm, -				    struct radeon_vm, list); -	if (vm_evict == vm) -		return -ENOMEM; - -	mutex_lock(&vm_evict->mutex); -	radeon_vm_free_pt(rdev, vm_evict); -	mutex_unlock(&vm_evict->mutex); -	return 0; -} - -/** - * radeon_vm_alloc_pt - allocates a page table for a VM - * - * @rdev: radeon_device pointer - * @vm: vm to bind - * - * Allocate a page table for the requested vm (cayman+). - * Returns 0 for success, error for failure. - * - * Global and local mutex must be locked! - */ -int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm) -{ -	unsigned pd_size, pts_size; -	u64 *pd_addr; -	int r; - -	if (vm == NULL) { -		return -EINVAL; -	} - -	if (vm->page_directory != NULL) { -		return 0; -	} - -retry: -	pd_size = radeon_vm_directory_size(rdev); -	r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, -			     &vm->page_directory, pd_size, -			     RADEON_VM_PTB_ALIGN_SIZE, false); -	if (r == -ENOMEM) { -		r = radeon_vm_evict(rdev, vm); -		if (r) -			return r; -		goto retry; - -	} else if (r) { -		return r; -	} - -	vm->pd_gpu_addr = radeon_sa_bo_gpu_addr(vm->page_directory); - -	/* Initially clear the page directory */ -	pd_addr = radeon_sa_bo_cpu_addr(vm->page_directory); -	memset(pd_addr, 0, pd_size); - -	pts_size = radeon_vm_num_pdes(rdev) * sizeof(struct radeon_sa_bo *); -	vm->page_tables = kzalloc(pts_size, GFP_KERNEL); - -	if (vm->page_tables == NULL) { -		DRM_ERROR("Cannot allocate memory for page table array\n"); -		radeon_sa_bo_free(rdev, &vm->page_directory, vm->fence); -		return -ENOMEM; -	} - -	return 0; -} - -/** - * radeon_vm_add_to_lru - add VMs page table to LRU list - * - * @rdev: radeon_device pointer - * @vm: vm to add to LRU - * - * Add the allocated page table to the LRU list (cayman+). - * - * Global mutex must be locked! - */ -void radeon_vm_add_to_lru(struct radeon_device *rdev, struct radeon_vm *vm) -{ -	list_del_init(&vm->list); -	list_add_tail(&vm->list, &rdev->vm_manager.lru_vm); -} - -/** - * radeon_vm_grab_id - allocate the next free VMID - * - * @rdev: radeon_device pointer - * @vm: vm to allocate id for - * @ring: ring we want to submit job to - * - * Allocate an id for the vm (cayman+). - * Returns the fence we need to sync to (if any). - * - * Global and local mutex must be locked! - */ -struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, -				       struct radeon_vm *vm, int ring) -{ -	struct radeon_fence *best[RADEON_NUM_RINGS] = {}; -	unsigned choices[2] = {}; -	unsigned i; - -	/* check if the id is still valid */ -	if (vm->fence && vm->fence == rdev->vm_manager.active[vm->id]) -		return NULL; - -	/* we definately need to flush */ -	radeon_fence_unref(&vm->last_flush); - -	/* skip over VMID 0, since it is the system VM */ -	for (i = 1; i < rdev->vm_manager.nvm; ++i) { -		struct radeon_fence *fence = rdev->vm_manager.active[i]; - -		if (fence == NULL) { -			/* found a free one */ -			vm->id = i; -			return NULL; -		} - -		if (radeon_fence_is_earlier(fence, best[fence->ring])) { -			best[fence->ring] = fence; -			choices[fence->ring == ring ? 0 : 1] = i; -		} -	} - -	for (i = 0; i < 2; ++i) { -		if (choices[i]) { -			vm->id = choices[i]; -			return rdev->vm_manager.active[choices[i]]; -		} -	} - -	/* should never happen */ -	BUG(); -	return NULL; -} - -/** - * radeon_vm_fence - remember fence for vm - * - * @rdev: radeon_device pointer - * @vm: vm we want to fence - * @fence: fence to remember - * - * Fence the vm (cayman+). - * Set the fence used to protect page table and id. - * - * Global and local mutex must be locked! - */ -void radeon_vm_fence(struct radeon_device *rdev, -		     struct radeon_vm *vm, -		     struct radeon_fence *fence) -{ -	radeon_fence_unref(&rdev->vm_manager.active[vm->id]); -	rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence); - -	radeon_fence_unref(&vm->fence); -	vm->fence = radeon_fence_ref(fence); -} - -/** - * radeon_vm_bo_find - find the bo_va for a specific vm & bo - * - * @vm: requested vm - * @bo: requested buffer object - * - * Find @bo inside the requested vm (cayman+). - * Search inside the @bos vm list for the requested vm - * Returns the found bo_va or NULL if none is found - * - * Object has to be reserved! - */ -struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, -				       struct radeon_bo *bo) -{ -	struct radeon_bo_va *bo_va; - -	list_for_each_entry(bo_va, &bo->va, bo_list) { -		if (bo_va->vm == vm) { -			return bo_va; -		} -	} -	return NULL; -} - -/** - * radeon_vm_bo_add - add a bo to a specific vm - * - * @rdev: radeon_device pointer - * @vm: requested vm - * @bo: radeon buffer object - * - * Add @bo into the requested vm (cayman+). - * Add @bo to the list of bos associated with the vm - * Returns newly added bo_va or NULL for failure - * - * Object has to be reserved! - */ -struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, -				      struct radeon_vm *vm, -				      struct radeon_bo *bo) -{ -	struct radeon_bo_va *bo_va; - -	bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); -	if (bo_va == NULL) { -		return NULL; -	} -	bo_va->vm = vm; -	bo_va->bo = bo; -	bo_va->soffset = 0; -	bo_va->eoffset = 0; -	bo_va->flags = 0; -	bo_va->valid = false; -	bo_va->ref_count = 1; -	INIT_LIST_HEAD(&bo_va->bo_list); -	INIT_LIST_HEAD(&bo_va->vm_list); - -	mutex_lock(&vm->mutex); -	list_add(&bo_va->vm_list, &vm->va); -	list_add_tail(&bo_va->bo_list, &bo->va); -	mutex_unlock(&vm->mutex); - -	return bo_va; -} - -/** - * radeon_vm_bo_set_addr - set bos virtual address inside a vm - * - * @rdev: radeon_device pointer - * @bo_va: bo_va to store the address - * @soffset: requested offset of the buffer in the VM address space - * @flags: attributes of pages (read/write/valid/etc.) - * - * Set offset of @bo_va (cayman+). - * Validate and set the offset requested within the vm address space. - * Returns 0 for success, error for failure. - * - * Object has to be reserved! - */ -int radeon_vm_bo_set_addr(struct radeon_device *rdev, -			  struct radeon_bo_va *bo_va, -			  uint64_t soffset, -			  uint32_t flags) -{ -	uint64_t size = radeon_bo_size(bo_va->bo); -	uint64_t eoffset, last_offset = 0; -	struct radeon_vm *vm = bo_va->vm; -	struct radeon_bo_va *tmp; -	struct list_head *head; -	unsigned last_pfn; - -	if (soffset) { -		/* make sure object fit at this offset */ -		eoffset = soffset + size; -		if (soffset >= eoffset) { -			return -EINVAL; -		} - -		last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; -		if (last_pfn > rdev->vm_manager.max_pfn) { -			dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", -				last_pfn, rdev->vm_manager.max_pfn); -			return -EINVAL; -		} - -	} else { -		eoffset = last_pfn = 0; -	} - -	mutex_lock(&vm->mutex); -	head = &vm->va; -	last_offset = 0; -	list_for_each_entry(tmp, &vm->va, vm_list) { -		if (bo_va == tmp) { -			/* skip over currently modified bo */ -			continue; -		} - -		if (soffset >= last_offset && eoffset <= tmp->soffset) { -			/* bo can be added before this one */ -			break; -		} -		if (eoffset > tmp->soffset && soffset < tmp->eoffset) { -			/* bo and tmp overlap, invalid offset */ -			dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", -				bo_va->bo, (unsigned)bo_va->soffset, tmp->bo, -				(unsigned)tmp->soffset, (unsigned)tmp->eoffset); -			mutex_unlock(&vm->mutex); -			return -EINVAL; -		} -		last_offset = tmp->eoffset; -		head = &tmp->vm_list; -	} - -	bo_va->soffset = soffset; -	bo_va->eoffset = eoffset; -	bo_va->flags = flags; -	bo_va->valid = false; -	list_move(&bo_va->vm_list, head); - -	mutex_unlock(&vm->mutex); -	return 0; -} - -/** - * radeon_vm_map_gart - get the physical address of a gart page - * - * @rdev: radeon_device pointer - * @addr: the unmapped addr - * - * Look up the physical address of the page that the pte resolves - * to (cayman+). - * Returns the physical address of the page. - */ -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); - -	return result; -} - -/** - * radeon_vm_update_pdes - make sure that page directory is valid - * - * @rdev: radeon_device pointer - * @vm: requested vm - * @start: start of GPU address range - * @end: end of GPU address range - * - * Allocates new page tables if necessary - * and updates the page directory (cayman+). - * Returns 0 for success, error for failure. - * - * Global and local mutex must be locked! - */ -static int radeon_vm_update_pdes(struct radeon_device *rdev, -				 struct radeon_vm *vm, -				 struct radeon_ib *ib, -				 uint64_t start, uint64_t end) -{ -	static const uint32_t incr = RADEON_VM_PTE_COUNT * 8; - -	uint64_t last_pde = ~0, last_pt = ~0; -	unsigned count = 0; -	uint64_t pt_idx; -	int r; - -	start = (start / RADEON_GPU_PAGE_SIZE) >> RADEON_VM_BLOCK_SIZE; -	end = (end / RADEON_GPU_PAGE_SIZE) >> RADEON_VM_BLOCK_SIZE; - -	/* walk over the address space and update the page directory */ -	for (pt_idx = start; pt_idx <= end; ++pt_idx) { -		uint64_t pde, pt; - -		if (vm->page_tables[pt_idx]) -			continue; - -retry: -		r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, -				     &vm->page_tables[pt_idx], -				     RADEON_VM_PTE_COUNT * 8, -				     RADEON_GPU_PAGE_SIZE, false); - -		if (r == -ENOMEM) { -			r = radeon_vm_evict(rdev, vm); -			if (r) -				return r; -			goto retry; -		} else if (r) { -			return r; -		} - -		pde = vm->pd_gpu_addr + pt_idx * 8; - -		pt = radeon_sa_bo_gpu_addr(vm->page_tables[pt_idx]); - -		if (((last_pde + 8 * count) != pde) || -		    ((last_pt + incr * count) != pt)) { - -			if (count) { -				radeon_asic_vm_set_page(rdev, ib, last_pde, -							last_pt, count, incr, -							RADEON_VM_PAGE_VALID); -			} - -			count = 1; -			last_pde = pde; -			last_pt = pt; -		} else { -			++count; -		} -	} - -	if (count) { -		radeon_asic_vm_set_page(rdev, ib, last_pde, last_pt, count, -					incr, RADEON_VM_PAGE_VALID); - -	} - -	return 0; -} - -/** - * radeon_vm_update_ptes - make sure that page tables are valid - * - * @rdev: radeon_device pointer - * @vm: requested vm - * @start: start of GPU address range - * @end: end of GPU address range - * @dst: destination address to map to - * @flags: mapping flags - * - * Update the page tables in the range @start - @end (cayman+). - * - * Global and local mutex must be locked! - */ -static void radeon_vm_update_ptes(struct radeon_device *rdev, -				  struct radeon_vm *vm, -				  struct radeon_ib *ib, -				  uint64_t start, uint64_t end, -				  uint64_t dst, uint32_t flags) -{ -	static const uint64_t mask = RADEON_VM_PTE_COUNT - 1; - -	uint64_t last_pte = ~0, last_dst = ~0; -	unsigned count = 0; -	uint64_t addr; - -	start = start / RADEON_GPU_PAGE_SIZE; -	end = end / RADEON_GPU_PAGE_SIZE; - -	/* walk over the address space and update the page tables */ -	for (addr = start; addr < end; ) { -		uint64_t pt_idx = addr >> RADEON_VM_BLOCK_SIZE; -		unsigned nptes; -		uint64_t pte; - -		if ((addr & ~mask) == (end & ~mask)) -			nptes = end - addr; -		else -			nptes = RADEON_VM_PTE_COUNT - (addr & mask); - -		pte = radeon_sa_bo_gpu_addr(vm->page_tables[pt_idx]); -		pte += (addr & mask) * 8; - -		if ((last_pte + 8 * count) != pte) { - -			if (count) { -				radeon_asic_vm_set_page(rdev, ib, last_pte, -							last_dst, count, -							RADEON_GPU_PAGE_SIZE, -							flags); -			} - -			count = nptes; -			last_pte = pte; -			last_dst = dst; -		} else { -			count += nptes; -		} - -		addr += nptes; -		dst += nptes * RADEON_GPU_PAGE_SIZE; -	} - -	if (count) { -		radeon_asic_vm_set_page(rdev, ib, last_pte, -					last_dst, count, -					RADEON_GPU_PAGE_SIZE, flags); -	} -} - -/** - * radeon_vm_bo_update_pte - map a bo into the vm page table - * - * @rdev: radeon_device pointer - * @vm: requested vm - * @bo: radeon buffer object - * @mem: ttm mem - * - * Fill in the page table entries for @bo (cayman+). - * Returns 0 for success, -EINVAL for failure. - * - * Object have to be reserved & global and local mutex must be locked! - */ -int radeon_vm_bo_update_pte(struct radeon_device *rdev, -			    struct radeon_vm *vm, -			    struct radeon_bo *bo, -			    struct ttm_mem_reg *mem) -{ -	unsigned ridx = rdev->asic->vm.pt_ring_index; -	struct radeon_ib ib; -	struct radeon_bo_va *bo_va; -	unsigned nptes, npdes, ndw; -	uint64_t addr; -	int r; - -	/* nothing to do if vm isn't bound */ -	if (vm->page_directory == NULL) -		return 0; - -	bo_va = radeon_vm_bo_find(vm, bo); -	if (bo_va == NULL) { -		dev_err(rdev->dev, "bo %p not in vm %p\n", bo, vm); -		return -EINVAL; -	} - -	if (!bo_va->soffset) { -		dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n", -			bo, vm); -		return -EINVAL; -	} - -	if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) -		return 0; - -	bo_va->flags &= ~RADEON_VM_PAGE_VALID; -	bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; -	if (mem) { -		addr = mem->start << PAGE_SHIFT; -		if (mem->mem_type != TTM_PL_SYSTEM) { -			bo_va->flags |= RADEON_VM_PAGE_VALID; -			bo_va->valid = true; -		} -		if (mem->mem_type == TTM_PL_TT) { -			bo_va->flags |= RADEON_VM_PAGE_SYSTEM; -		} else { -			addr += rdev->vm_manager.vram_base_offset; -		} -	} else { -		addr = 0; -		bo_va->valid = false; -	} - -	nptes = radeon_bo_ngpu_pages(bo); - -	/* assume two extra pdes in case the mapping overlaps the borders */ -	npdes = (nptes >> RADEON_VM_BLOCK_SIZE) + 2; - -	/* padding, etc. */ -	ndw = 64; - -	if (RADEON_VM_BLOCK_SIZE > 11) -		/* reserve space for one header for every 2k dwords */ -		ndw += (nptes >> 11) * 4; -	else -		/* reserve space for one header for -		    every (1 << BLOCK_SIZE) entries */ -		ndw += (nptes >> RADEON_VM_BLOCK_SIZE) * 4; - -	/* reserve space for pte addresses */ -	ndw += nptes * 2; - -	/* reserve space for one header for every 2k dwords */ -	ndw += (npdes >> 11) * 4; - -	/* reserve space for pde addresses */ -	ndw += npdes * 2; - -	/* update too big for an IB */ -	if (ndw > 0xfffff) -		return -ENOMEM; - -	r = radeon_ib_get(rdev, ridx, &ib, NULL, ndw * 4); -	ib.length_dw = 0; - -	r = radeon_vm_update_pdes(rdev, vm, &ib, bo_va->soffset, bo_va->eoffset); -	if (r) { -		radeon_ib_free(rdev, &ib); -		return r; -	} - -	radeon_vm_update_ptes(rdev, vm, &ib, bo_va->soffset, bo_va->eoffset, -			      addr, bo_va->flags); - -	radeon_ib_sync_to(&ib, vm->fence); -	r = radeon_ib_schedule(rdev, &ib, NULL); -	if (r) { -		radeon_ib_free(rdev, &ib); -		return r; -	} -	radeon_fence_unref(&vm->fence); -	vm->fence = radeon_fence_ref(ib.fence); -	radeon_ib_free(rdev, &ib); -	radeon_fence_unref(&vm->last_flush); - -	return 0; -} - -/** - * radeon_vm_bo_rmv - remove a bo to a specific vm - * - * @rdev: radeon_device pointer - * @bo_va: requested bo_va - * - * Remove @bo_va->bo from the requested vm (cayman+). - * Remove @bo_va->bo from the list of bos associated with the bo_va->vm and - * remove the ptes for @bo_va in the page table. - * Returns 0 for success. - * - * Object have to be reserved! - */ -int radeon_vm_bo_rmv(struct radeon_device *rdev, -		     struct radeon_bo_va *bo_va) -{ -	int r = 0; - -	mutex_lock(&rdev->vm_manager.lock); -	mutex_lock(&bo_va->vm->mutex); -	if (bo_va->soffset) { -		r = radeon_vm_bo_update_pte(rdev, bo_va->vm, bo_va->bo, NULL); -	} -	mutex_unlock(&rdev->vm_manager.lock); -	list_del(&bo_va->vm_list); -	mutex_unlock(&bo_va->vm->mutex); -	list_del(&bo_va->bo_list); - -	kfree(bo_va); -	return r; -} - -/** - * radeon_vm_bo_invalidate - mark the bo as invalid - * - * @rdev: radeon_device pointer - * @vm: requested vm - * @bo: radeon buffer object - * - * Mark @bo as invalid (cayman+). - */ -void radeon_vm_bo_invalidate(struct radeon_device *rdev, -			     struct radeon_bo *bo) -{ -	struct radeon_bo_va *bo_va; - -	list_for_each_entry(bo_va, &bo->va, bo_list) { -		bo_va->valid = false; -	} -} - -/** - * radeon_vm_init - initialize a vm instance - * - * @rdev: radeon_device pointer - * @vm: requested vm - * - * Init @vm fields (cayman+). - */ -void radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) -{ -	vm->id = 0; -	vm->fence = NULL; -	mutex_init(&vm->mutex); -	INIT_LIST_HEAD(&vm->list); -	INIT_LIST_HEAD(&vm->va); -} - -/** - * radeon_vm_fini - tear down a vm instance - * - * @rdev: radeon_device pointer - * @vm: requested vm - * - * Tear down @vm (cayman+). - * Unbind the VM and remove all bos from the vm bo list - */ -void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) -{ -	struct radeon_bo_va *bo_va, *tmp; -	int r; - -	mutex_lock(&rdev->vm_manager.lock); -	mutex_lock(&vm->mutex); -	radeon_vm_free_pt(rdev, vm); -	mutex_unlock(&rdev->vm_manager.lock); - -	if (!list_empty(&vm->va)) { -		dev_err(rdev->dev, "still active bo inside vm\n"); -	} -	list_for_each_entry_safe(bo_va, tmp, &vm->va, vm_list) { -		list_del_init(&bo_va->vm_list); -		r = radeon_bo_reserve(bo_va->bo, false); -		if (!r) { -			list_del_init(&bo_va->bo_list); -			radeon_bo_unreserve(bo_va->bo); -			kfree(bo_va); -		} -	} -	radeon_fence_unref(&vm->fence); -	radeon_fence_unref(&vm->last_flush); -	mutex_unlock(&vm->mutex); -} diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index dce99c8a583..d09650c1d72 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -29,13 +29,6 @@  #include <drm/radeon_drm.h>  #include "radeon.h" -int radeon_gem_object_init(struct drm_gem_object *obj) -{ -	BUG(); - -	return 0; -} -  void radeon_gem_object_free(struct drm_gem_object *gobj)  {  	struct radeon_bo *robj = gem_to_radeon_bo(gobj); @@ -93,7 +86,7 @@ retry:  	return 0;  } -int radeon_gem_set_domain(struct drm_gem_object *gobj, +static int radeon_gem_set_domain(struct drm_gem_object *gobj,  			  uint32_t rdomain, uint32_t wdomain)  {  	struct radeon_bo *robj; @@ -351,18 +344,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,  	}  	robj = gem_to_radeon_bo(gobj);  	r = radeon_bo_wait(robj, &cur_placement, true); -	switch (cur_placement) { -	case TTM_PL_VRAM: -		args->domain = RADEON_GEM_DOMAIN_VRAM; -		break; -	case TTM_PL_TT: -		args->domain = RADEON_GEM_DOMAIN_GTT; -		break; -	case TTM_PL_SYSTEM: -		args->domain = RADEON_GEM_DOMAIN_CPU; -	default: -		break; -	} +	args->domain = radeon_mem_type_to_domain(cur_placement);  	drm_gem_object_unreference_unlocked(gobj);  	r = radeon_gem_handle_lockup(rdev, r);  	return r; @@ -540,6 +522,42 @@ out:  	return r;  } +int radeon_gem_op_ioctl(struct drm_device *dev, void *data, +			struct drm_file *filp) +{ +	struct drm_radeon_gem_op *args = data; +	struct drm_gem_object *gobj; +	struct radeon_bo *robj; +	int r; + +	gobj = drm_gem_object_lookup(dev, filp, args->handle); +	if (gobj == NULL) { +		return -ENOENT; +	} +	robj = gem_to_radeon_bo(gobj); +	r = radeon_bo_reserve(robj, false); +	if (unlikely(r)) +		goto out; + +	switch (args->op) { +	case RADEON_GEM_OP_GET_INITIAL_DOMAIN: +		args->value = robj->initial_domain; +		break; +	case RADEON_GEM_OP_SET_INITIAL_DOMAIN: +		robj->initial_domain = args->value & (RADEON_GEM_DOMAIN_VRAM | +						      RADEON_GEM_DOMAIN_GTT | +						      RADEON_GEM_DOMAIN_CPU); +		break; +	default: +		r = -EINVAL; +	} + +	radeon_bo_unreserve(robj); +out: +	drm_gem_object_unreference_unlocked(gobj); +	return r; +} +  int radeon_mode_dumb_create(struct drm_file *file_priv,  			    struct drm_device *dev,  			    struct drm_mode_create_dumb *args) diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index fc60b74ee30..add62200840 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -64,8 +64,7 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux)  		radeon_router_select_ddc_port(radeon_connector);  	if (use_aux) { -		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; -		ret = i2c_transfer(&dig->dp_i2c_bus->adapter, msgs, 2); +		ret = i2c_transfer(&radeon_connector->ddc_bus->aux.ddc, msgs, 2);  	} else {  		ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);  	} @@ -95,6 +94,8 @@ static int pre_xfer(struct i2c_adapter *i2c_adap)  	struct radeon_i2c_bus_rec *rec = &i2c->rec;  	uint32_t temp; +	mutex_lock(&i2c->mutex); +  	/* RV410 appears to have a bug where the hw i2c in reset  	 * holds the i2c port in a bad state - switch hw i2c away before  	 * doing DDC - do this for all r200s/r300s/r400s for safety sake @@ -171,6 +172,8 @@ static void post_xfer(struct i2c_adapter *i2c_adap)  	temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask;  	WREG32(rec->mask_data_reg, temp);  	temp = RREG32(rec->mask_data_reg); + +	mutex_unlock(&i2c->mutex);  }  static int get_clock(void *i2c_priv) @@ -814,6 +817,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,  	struct radeon_i2c_bus_rec *rec = &i2c->rec;  	int ret = 0; +	mutex_lock(&i2c->mutex); +  	switch (rdev->family) {  	case CHIP_R100:  	case CHIP_RV100: @@ -880,6 +885,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,  		break;  	} +	mutex_unlock(&i2c->mutex); +  	return ret;  } @@ -920,6 +927,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,  	i2c->adapter.dev.parent = &dev->pdev->dev;  	i2c->dev = dev;  	i2c_set_adapdata(&i2c->adapter, i2c); +	mutex_init(&i2c->mutex);  	if (rec->mm_i2c ||  	    (rec->hw_capable &&  	     radeon_hw_i2c && @@ -950,16 +958,16 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,  		/* set the radeon bit adapter */  		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),  			 "Radeon i2c bit bus %s", name); -		i2c->adapter.algo_data = &i2c->algo.bit; -		i2c->algo.bit.pre_xfer = pre_xfer; -		i2c->algo.bit.post_xfer = post_xfer; -		i2c->algo.bit.setsda = set_data; -		i2c->algo.bit.setscl = set_clock; -		i2c->algo.bit.getsda = get_data; -		i2c->algo.bit.getscl = get_clock; -		i2c->algo.bit.udelay = 10; -		i2c->algo.bit.timeout = usecs_to_jiffies(2200);	/* from VESA */ -		i2c->algo.bit.data = i2c; +		i2c->adapter.algo_data = &i2c->bit; +		i2c->bit.pre_xfer = pre_xfer; +		i2c->bit.post_xfer = post_xfer; +		i2c->bit.setsda = set_data; +		i2c->bit.setscl = set_clock; +		i2c->bit.getsda = get_data; +		i2c->bit.getscl = get_clock; +		i2c->bit.udelay = 10; +		i2c->bit.timeout = usecs_to_jiffies(2200);	/* from VESA */ +		i2c->bit.data = i2c;  		ret = i2c_bit_add_bus(&i2c->adapter);  		if (ret) {  			DRM_ERROR("Failed to register bit i2c %s\n", name); @@ -974,52 +982,22 @@ out_free:  } -struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, -					     struct radeon_i2c_bus_rec *rec, -					     const char *name) -{ -	struct radeon_i2c_chan *i2c; -	int ret; - -	i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); -	if (i2c == NULL) -		return NULL; - -	i2c->rec = *rec; -	i2c->adapter.owner = THIS_MODULE; -	i2c->adapter.class = I2C_CLASS_DDC; -	i2c->adapter.dev.parent = &dev->pdev->dev; -	i2c->dev = dev; -	snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), -		 "Radeon aux bus %s", name); -	i2c_set_adapdata(&i2c->adapter, i2c); -	i2c->adapter.algo_data = &i2c->algo.dp; -	i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; -	i2c->algo.dp.address = 0; -	ret = i2c_dp_aux_add_bus(&i2c->adapter); -	if (ret) { -		DRM_INFO("Failed to register i2c %s\n", name); -		goto out_free; -	} - -	return i2c; -out_free: -	kfree(i2c); -	return NULL; - -} -  void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)  {  	if (!i2c)  		return;  	i2c_del_adapter(&i2c->adapter); +	if (i2c->has_aux) +		drm_dp_aux_unregister(&i2c->aux);  	kfree(i2c);  }  /* Add the default buses */  void radeon_i2c_init(struct radeon_device *rdev)  { +	if (radeon_hw_i2c) +		DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n"); +  	if (rdev->is_atom_bios)  		radeon_atombios_i2c_init(rdev);  	else diff --git a/drivers/gpu/drm/radeon/radeon_ioc32.c b/drivers/gpu/drm/radeon/radeon_ioc32.c index c180df8e84d..0b98ea13457 100644 --- a/drivers/gpu/drm/radeon/radeon_ioc32.c +++ b/drivers/gpu/drm/radeon/radeon_ioc32.c @@ -399,7 +399,7 @@ long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  	if (nr < DRM_COMMAND_BASE)  		return drm_compat_ioctl(filp, cmd, arg); -	if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls)) +	if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(radeon_compat_ioctls))  		fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE];  	if (fn != NULL) @@ -418,7 +418,7 @@ long radeon_kms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long  	if (nr < DRM_COMMAND_BASE)  		return drm_compat_ioctl(filp, cmd, arg); -	ret = drm_ioctl(filp, cmd, arg); +	ret = radeon_drm_ioctl(filp, cmd, arg);  	return ret;  } diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 8d68e972789..244b19bab2e 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -181,7 +181,7 @@ static u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_dis   * tied to dma at all, this is just a hangover from dri prehistory.   */ -irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) +irqreturn_t radeon_driver_irq_handler(int irq, void *arg)  {  	struct drm_device *dev = (struct drm_device *) arg;  	drm_radeon_private_t *dev_priv = @@ -203,7 +203,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)  	/* SW interrupt */  	if (stat & RADEON_SW_INT_TEST) -		DRM_WAKEUP(&dev_priv->swi_queue); +		wake_up(&dev_priv->swi_queue);  	/* VBLANK interrupt */  	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { @@ -249,7 +249,7 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)  	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; -	DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, +	DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * HZ,  		    RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr);  	return ret; @@ -302,7 +302,7 @@ int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_pr  	result = radeon_emit_irq(dev); -	if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { +	if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {  		DRM_ERROR("copy_to_user\n");  		return -EFAULT;  	} @@ -354,7 +354,7 @@ int radeon_driver_irq_postinstall(struct drm_device *dev)  	    (drm_radeon_private_t *) dev->dev_private;  	atomic_set(&dev_priv->swi_emitted, 0); -	DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); +	init_waitqueue_head(&dev_priv->swi_queue);  	dev->max_vblank_count = 0x001fffff; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index cc9e8482cf3..16807afab36 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -32,23 +32,29 @@  #include "radeon.h"  #include "atom.h" +#include <linux/pm_runtime.h> +  #define RADEON_WAIT_IDLE_TIMEOUT 200  /**   * radeon_driver_irq_handler_kms - irq handler for KMS   * - * @DRM_IRQ_ARGS: args + * @int irq, void *arg: args   *   * This is the irq handler for the radeon KMS driver (all asics).   * radeon_irq_process is a macro that points to the per-asic   * irq handler callback.   */ -irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS) +irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg)  {  	struct drm_device *dev = (struct drm_device *) arg;  	struct radeon_device *rdev = dev->dev_private; +	irqreturn_t ret; -	return radeon_irq_process(rdev); +	ret = radeon_irq_process(rdev); +	if (ret == IRQ_HANDLED) +		pm_runtime_mark_last_busy(dev->dev); +	return ret;  }  /* @@ -281,7 +287,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)  	INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func);  	rdev->irq.installed = true; -	r = drm_irq_install(rdev->ddev); +	r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);  	if (r) {  		rdev->irq.installed = false;  		flush_work(&rdev->hotplug_work); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 61580ddc4eb..d25ae6acfd5 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -32,6 +32,13 @@  #include <linux/vga_switcheroo.h>  #include <linux/slab.h> +#include <linux/pm_runtime.h> + +#if defined(CONFIG_VGA_SWITCHEROO) +bool radeon_has_atpx(void); +#else +static inline bool radeon_has_atpx(void) { return false; } +#endif  /**   * radeon_driver_unload_kms - Main unload function for KMS. @@ -50,9 +57,14 @@ int radeon_driver_unload_kms(struct drm_device *dev)  	if (rdev == NULL)  		return 0; +  	if (rdev->rmmio == NULL)  		goto done_free; + +	pm_runtime_get_sync(dev->dev); +  	radeon_acpi_fini(rdev); +	  	radeon_modeset_fini(rdev);  	radeon_device_fini(rdev); @@ -95,6 +107,11 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)  		flags |= RADEON_IS_PCI;  	} +	if ((radeon_runtime_pm != 0) && +	    radeon_has_atpx() && +	    ((flags & RADEON_IS_IGP) == 0)) +		flags |= RADEON_IS_PX; +  	/* radeon_device_init should report only fatal error  	 * like memory allocation failure or iomapping failure,  	 * or memory manager initialization failure, it must @@ -125,9 +142,20 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)  				"Error during ACPI methods call\n");  	} +	if (radeon_is_px(dev)) { +		pm_runtime_use_autosuspend(dev->dev); +		pm_runtime_set_autosuspend_delay(dev->dev, 5000); +		pm_runtime_set_active(dev->dev); +		pm_runtime_allow(dev->dev); +		pm_runtime_mark_last_busy(dev->dev); +		pm_runtime_put_autosuspend(dev->dev); +	} +  out:  	if (r)  		radeon_driver_unload_kms(dev); + +  	return r;  } @@ -175,7 +203,7 @@ static void radeon_set_filp_rights(struct drm_device *dev,   * etc. (all asics).   * Returns 0 on success, -EINVAL on failure.   */ -int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) +static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  {  	struct radeon_device *rdev = dev->dev_private;  	struct drm_radeon_info *info = data; @@ -191,7 +219,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  	switch (info->request) {  	case RADEON_INFO_DEVICE_ID: -		*value = dev->pci_device; +		*value = dev->pdev->device;  		break;  	case RADEON_INFO_NUM_GB_PIPES:  		*value = rdev->num_gb_pipes; @@ -207,7 +235,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  			*value = rdev->accel_working;  		break;  	case RADEON_INFO_CRTC_FROM_ID: -		if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) { +		if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {  			DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);  			return -EFAULT;  		} @@ -253,7 +281,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  		 *  		 * When returning, the value is 1 if filp owns hyper-z access,  		 * 0 otherwise. */ -		if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) { +		if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {  			DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);  			return -EFAULT;  		} @@ -265,7 +293,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  		break;  	case RADEON_INFO_WANT_CMASK:  		/* The same logic as Hyper-Z. */ -		if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) { +		if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {  			DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);  			return -EFAULT;  		} @@ -324,7 +352,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  		break;  	case RADEON_INFO_BACKEND_MAP:  		if (rdev->family >= CHIP_BONAIRE) -			return -EINVAL; +			*value = rdev->config.cik.backend_map;  		else if (rdev->family >= CHIP_TAHITI)  			*value = rdev->config.si.backend_map;  		else if (rdev->family >= CHIP_CAYMAN) @@ -401,7 +429,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  		*value = rdev->fastfb_working;  		break;  	case RADEON_INFO_RING_WORKING: -		if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) { +		if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {  			DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);  			return -EFAULT;  		} @@ -417,6 +445,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  		case RADEON_CS_RING_UVD:  			*value = rdev->ring[R600_RING_TYPE_UVD_INDEX].ready;  			break; +		case RADEON_CS_RING_VCE: +			*value = rdev->ring[TN_RING_TYPE_VCE1_INDEX].ready; +			break;  		default:  			return -EINVAL;  		} @@ -433,14 +464,76 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  			return -EINVAL;  		}  		break; +	case RADEON_INFO_CIK_MACROTILE_MODE_ARRAY: +		if (rdev->family >= CHIP_BONAIRE) { +			value = rdev->config.cik.macrotile_mode_array; +			value_size = sizeof(uint32_t)*16; +		} else { +			DRM_DEBUG_KMS("macrotile mode array is cik+ only!\n"); +			return -EINVAL; +		} +		break;  	case RADEON_INFO_SI_CP_DMA_COMPUTE:  		*value = 1;  		break; +	case RADEON_INFO_SI_BACKEND_ENABLED_MASK: +		if (rdev->family >= CHIP_BONAIRE) { +			*value = rdev->config.cik.backend_enable_mask; +		} else if (rdev->family >= CHIP_TAHITI) { +			*value = rdev->config.si.backend_enable_mask; +		} else { +			DRM_DEBUG_KMS("BACKEND_ENABLED_MASK is si+ only!\n"); +		} +		break; +	case RADEON_INFO_MAX_SCLK: +		if ((rdev->pm.pm_method == PM_METHOD_DPM) && +		    rdev->pm.dpm_enabled) +			*value = rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk * 10; +		else +			*value = rdev->pm.default_sclk * 10; +		break; +	case RADEON_INFO_VCE_FW_VERSION: +		*value = rdev->vce.fw_version; +		break; +	case RADEON_INFO_VCE_FB_VERSION: +		*value = rdev->vce.fb_version; +		break; +	case RADEON_INFO_NUM_BYTES_MOVED: +		value = (uint32_t*)&value64; +		value_size = sizeof(uint64_t); +		value64 = atomic64_read(&rdev->num_bytes_moved); +		break; +	case RADEON_INFO_VRAM_USAGE: +		value = (uint32_t*)&value64; +		value_size = sizeof(uint64_t); +		value64 = atomic64_read(&rdev->vram_usage); +		break; +	case RADEON_INFO_GTT_USAGE: +		value = (uint32_t*)&value64; +		value_size = sizeof(uint64_t); +		value64 = atomic64_read(&rdev->gtt_usage); +		break; +	case RADEON_INFO_ACTIVE_CU_COUNT: +		if (rdev->family >= CHIP_BONAIRE) +			*value = rdev->config.cik.active_cus; +		else if (rdev->family >= CHIP_TAHITI) +			*value = rdev->config.si.active_cus; +		else if (rdev->family >= CHIP_CAYMAN) +			*value = rdev->config.cayman.active_simds; +		else if (rdev->family >= CHIP_CEDAR) +			*value = rdev->config.evergreen.active_simds; +		else if (rdev->family >= CHIP_RV770) +			*value = rdev->config.rv770.active_simds; +		else if (rdev->family >= CHIP_R600) +			*value = rdev->config.r600.active_simds; +		else +			*value = 1; +		break;  	default:  		DRM_DEBUG_KMS("Invalid request %d\n", info->request);  		return -EINVAL;  	} -	if (DRM_COPY_TO_USER(value_ptr, (char*)value, value_size)) { +	if (copy_to_user(value_ptr, (char*)value, value_size)) {  		DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);  		return -EFAULT;  	} @@ -475,13 +568,18 @@ void radeon_driver_lastclose_kms(struct drm_device *dev)  int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)  {  	struct radeon_device *rdev = dev->dev_private; +	int r;  	file_priv->driver_priv = NULL; +	r = pm_runtime_get_sync(dev->dev); +	if (r < 0) +		return r; +  	/* new gpu have virtual address space support */  	if (rdev->family >= CHIP_CAYMAN) {  		struct radeon_fpriv *fpriv; -		struct radeon_bo_va *bo_va; +		struct radeon_vm *vm;  		int r;  		fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); @@ -489,23 +587,42 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)  			return -ENOMEM;  		} -		radeon_vm_init(rdev, &fpriv->vm); - -		/* map the ib pool buffer read only into -		 * virtual address space */ -		bo_va = radeon_vm_bo_add(rdev, &fpriv->vm, -					 rdev->ring_tmp_bo.bo); -		r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET, -					  RADEON_VM_PAGE_READABLE | -					  RADEON_VM_PAGE_SNOOPED); +		vm = &fpriv->vm; +		r = radeon_vm_init(rdev, vm);  		if (r) { -			radeon_vm_fini(rdev, &fpriv->vm);  			kfree(fpriv);  			return r;  		} +		if (rdev->accel_working) { +			r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); +			if (r) { +				radeon_vm_fini(rdev, vm); +				kfree(fpriv); +				return r; +			} + +			/* map the ib pool buffer read only into +			 * virtual address space */ +			vm->ib_bo_va = radeon_vm_bo_add(rdev, vm, +							rdev->ring_tmp_bo.bo); +			r = radeon_vm_bo_set_addr(rdev, vm->ib_bo_va, +						  RADEON_VA_IB_OFFSET, +						  RADEON_VM_PAGE_READABLE | +						  RADEON_VM_PAGE_SNOOPED); + +			radeon_bo_unreserve(rdev->ring_tmp_bo.bo); +			if (r) { +				radeon_vm_fini(rdev, vm); +				kfree(fpriv); +				return r; +			} +		}  		file_priv->driver_priv = fpriv;  	} + +	pm_runtime_mark_last_busy(dev->dev); +	pm_runtime_put_autosuspend(dev->dev);  	return 0;  } @@ -525,19 +642,19 @@ void radeon_driver_postclose_kms(struct drm_device *dev,  	/* new gpu have virtual address space support */  	if (rdev->family >= CHIP_CAYMAN && file_priv->driver_priv) {  		struct radeon_fpriv *fpriv = file_priv->driver_priv; -		struct radeon_bo_va *bo_va; +		struct radeon_vm *vm = &fpriv->vm;  		int r; -		r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); -		if (!r) { -			bo_va = radeon_vm_bo_find(&fpriv->vm, -						  rdev->ring_tmp_bo.bo); -			if (bo_va) -				radeon_vm_bo_rmv(rdev, bo_va); -			radeon_bo_unreserve(rdev->ring_tmp_bo.bo); +		if (rdev->accel_working) { +			r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); +			if (!r) { +				if (vm->ib_bo_va) +					radeon_vm_bo_rmv(rdev, vm->ib_bo_va); +				radeon_bo_unreserve(rdev->ring_tmp_bo.bo); +			}  		} -		radeon_vm_fini(rdev, &fpriv->vm); +		radeon_vm_fini(rdev, vm);  		kfree(fpriv);  		file_priv->driver_priv = NULL;  	} @@ -561,6 +678,7 @@ void radeon_driver_preclose_kms(struct drm_device *dev,  	if (rdev->cmask_filp == file_priv)  		rdev->cmask_filp = NULL;  	radeon_uvd_free_handles(rdev, file_priv); +	radeon_vce_free_handles(rdev, file_priv);  }  /* @@ -670,11 +788,12 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,  	/* Helper routine in DRM core does all the work: */  	return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,  						     vblank_time, flags, -						     drmcrtc); +						     drmcrtc, &drmcrtc->hwmode);  }  #define KMS_INVALID_IOCTL(name)						\ -int name(struct drm_device *dev, void *data, struct drm_file *file_priv)\ +static int name(struct drm_device *dev, void *data, struct drm_file	\ +		*file_priv)						\  {									\  	DRM_ERROR("invalid ioctl with kms %s\n", __func__);		\  	return -EINVAL;							\ @@ -754,5 +873,6 @@ const struct drm_ioctl_desc radeon_ioctls_kms[] = {  	DRM_IOCTL_DEF_DRV(RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),  	DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),  	DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), +	DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),  }; -int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms); +int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 7cb178a34a0..cafb1ccf2ec 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -385,7 +385,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,  	DRM_DEBUG_KMS("\n");  	/* no fb bound */ -	if (!atomic && !crtc->fb) { +	if (!atomic && !crtc->primary->fb) {  		DRM_DEBUG_KMS("No FB bound\n");  		return 0;  	} @@ -395,8 +395,8 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,  		target_fb = fb;  	}  	else { -		radeon_fb = to_radeon_framebuffer(crtc->fb); -		target_fb = crtc->fb; +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb); +		target_fb = crtc->primary->fb;  	}  	switch (target_fb->bits_per_pixel) { @@ -422,6 +422,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,  	/* Pin framebuffer & get tilling informations */  	obj = radeon_fb->obj;  	rbo = gem_to_radeon_bo(obj); +retry:  	r = radeon_bo_reserve(rbo, false);  	if (unlikely(r != 0))  		return r; @@ -430,6 +431,33 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,  				     &base);  	if (unlikely(r != 0)) {  		radeon_bo_unreserve(rbo); + +		/* On old GPU like RN50 with little vram pining can fails because +		 * current fb is taking all space needed. So instead of unpining +		 * the old buffer after pining the new one, first unpin old one +		 * and then retry pining new one. +		 * +		 * As only master can set mode only master can pin and it is +		 * unlikely the master client will race with itself especialy +		 * on those old gpu with single crtc. +		 * +		 * We don't shutdown the display controller because new buffer +		 * will end up in same spot. +		 */ +		if (!atomic && fb && fb != crtc->primary->fb) { +			struct radeon_bo *old_rbo; +			unsigned long nsize, osize; + +			old_rbo = gem_to_radeon_bo(to_radeon_framebuffer(fb)->obj); +			osize = radeon_bo_size(old_rbo); +			nsize = radeon_bo_size(rbo); +			if (nsize <= osize && !radeon_bo_reserve(old_rbo, false)) { +				radeon_bo_unpin(old_rbo); +				radeon_bo_unreserve(old_rbo); +				fb = NULL; +				goto retry; +			} +		}  		return -EINVAL;  	}  	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); @@ -527,7 +555,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,  	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);  	WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); -	if (!atomic && fb && fb != crtc->fb) { +	if (!atomic && fb && fb != crtc->primary->fb) {  		radeon_fb = to_radeon_framebuffer(fb);  		rbo = gem_to_radeon_bo(radeon_fb->obj);  		r = radeon_bo_reserve(rbo, false); @@ -571,7 +599,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod  		}  	} -	switch (crtc->fb->bits_per_pixel) { +	switch (crtc->primary->fb->bits_per_pixel) {  	case 8:  		format = 2;  		break; @@ -1056,6 +1084,26 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)  	}  } +static void radeon_crtc_disable(struct drm_crtc *crtc) +{ +	radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +	if (crtc->primary->fb) { +		int r; +		struct radeon_framebuffer *radeon_fb; +		struct radeon_bo *rbo; + +		radeon_fb = to_radeon_framebuffer(crtc->primary->fb); +		rbo = gem_to_radeon_bo(radeon_fb->obj); +		r = radeon_bo_reserve(rbo, false); +		if (unlikely(r)) +			DRM_ERROR("failed to reserve rbo before unpin\n"); +		else { +			radeon_bo_unpin(rbo); +			radeon_bo_unreserve(rbo); +		} +	} +} +  static const struct drm_crtc_helper_funcs legacy_helper_funcs = {  	.dpms = radeon_crtc_dpms,  	.mode_fixup = radeon_crtc_mode_fixup, @@ -1065,6 +1113,7 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = {  	.prepare = radeon_crtc_prepare,  	.commit = radeon_crtc_commit,  	.load_lut = radeon_crtc_load_lut, +	.disable = radeon_crtc_disable  }; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 62cd512f5c8..c89971d904c 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -392,7 +392,7 @@ void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,  	props.type = BACKLIGHT_RAW;  	snprintf(bl_name, sizeof(bl_name),  		 "radeon_bl%d", dev->primary->index); -	bd = backlight_device_register(bl_name, &drm_connector->kdev, +	bd = backlight_device_register(bl_name, drm_connector->kdev,  				       pdata, &radeon_backlight_ops, &props);  	if (IS_ERR(bd)) {  		DRM_ERROR("Backlight registration failed\n"); diff --git a/drivers/gpu/drm/radeon/radeon_mem.c b/drivers/gpu/drm/radeon/radeon_mem.c index d54d2d7c903..146d253f113 100644 --- a/drivers/gpu/drm/radeon/radeon_mem.c +++ b/drivers/gpu/drm/radeon/radeon_mem.c @@ -243,7 +243,7 @@ int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_p  	if (!block)  		return -ENOMEM; -	if (DRM_COPY_TO_USER(alloc->region_offset, &block->start, +	if (copy_to_user(alloc->region_offset, &block->start,  			     sizeof(int))) {  		DRM_ERROR("copy_to_user\n");  		return -EFAULT; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index ef63d3f00b2..0592ddb0904 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -46,6 +46,10 @@ struct radeon_device;  #define to_radeon_encoder(x) container_of(x, struct radeon_encoder, base)  #define to_radeon_framebuffer(x) container_of(x, struct radeon_framebuffer, base) +#define RADEON_MAX_HPD_PINS 7 +#define RADEON_MAX_CRTCS 6 +#define RADEON_MAX_AFMT_BLOCKS 7 +  enum radeon_rmx_type {  	RMX_OFF,  	RMX_FULL, @@ -187,11 +191,11 @@ struct radeon_pll {  struct radeon_i2c_chan {  	struct i2c_adapter adapter;  	struct drm_device *dev; -	union { -		struct i2c_algo_bit_data bit; -		struct i2c_algo_dp_aux_data dp; -	} algo; +	struct i2c_algo_bit_data bit;  	struct radeon_i2c_bus_rec rec; +	struct drm_dp_aux aux; +	bool has_aux; +	struct mutex mutex;  };  /* mostly for macs, but really any system without connector tables */ @@ -233,8 +237,8 @@ struct radeon_mode_info {  	struct card_info *atom_card_info;  	enum radeon_connector_table connector_table;  	bool mode_config_initialized; -	struct radeon_crtc *crtcs[6]; -	struct radeon_afmt *afmt[7]; +	struct radeon_crtc *crtcs[RADEON_MAX_CRTCS]; +	struct radeon_afmt *afmt[RADEON_MAX_AFMT_BLOCKS];  	/* DVI-I properties */  	struct drm_property *coherent_mode_property;  	/* DAC enable load detect */ @@ -249,6 +253,8 @@ struct radeon_mode_info {  	struct drm_property *underscan_vborder_property;  	/* audio */  	struct drm_property *audio_property; +	/* FMT dithering */ +	struct drm_property *dither_property;  	/* hardcoded DFP edid from BIOS */  	struct edid *bios_hardcoded_edid;  	int bios_hardcoded_edid_size; @@ -289,6 +295,7 @@ struct radeon_tv_regs {  struct radeon_atom_ss {  	uint16_t percentage; +	uint16_t percentage_divider;  	uint8_t type;  	uint16_t step;  	uint8_t delay; @@ -299,6 +306,12 @@ struct radeon_atom_ss {  	uint16_t amount;  }; +enum radeon_flip_status { +	RADEON_FLIP_NONE, +	RADEON_FLIP_PENDING, +	RADEON_FLIP_SUBMITTED +}; +  struct radeon_crtc {  	struct drm_crtc base;  	int crtc_id; @@ -322,8 +335,9 @@ struct radeon_crtc {  	struct drm_display_mode native_mode;  	int pll_id;  	/* page flipping */ -	struct radeon_unpin_work *unpin_work; -	int deferred_flip_completion; +	struct workqueue_struct *flip_queue; +	struct radeon_flip_work *flip_work; +	enum radeon_flip_status flip_status;  	/* pll sharing */  	struct radeon_atom_ss ss;  	bool ss_enabled; @@ -436,7 +450,6 @@ struct radeon_encoder {  struct radeon_connector_atom_dig {  	uint32_t igp_lane_info;  	/* displayport */ -	struct radeon_i2c_chan *dp_i2c_bus;  	u8 dpcd[DP_RECEIVER_CAP_SIZE];  	u8 dp_sink_type;  	int dp_clock; @@ -479,6 +492,11 @@ enum radeon_connector_audio {  	RADEON_AUDIO_AUTO = 2  }; +enum radeon_connector_dither { +	RADEON_FMT_DITHER_DISABLE = 0, +	RADEON_FMT_DITHER_ENABLE = 1, +}; +  struct radeon_connector {  	struct drm_connector base;  	uint32_t connector_id; @@ -498,6 +516,8 @@ struct radeon_connector {  	struct radeon_router router;  	struct radeon_i2c_chan *router_bus;  	enum radeon_connector_audio audio; +	enum radeon_connector_dither dither; +	int pixelclock_for_modeset;  };  struct radeon_framebuffer { @@ -616,6 +636,30 @@ struct atom_voltage_table  	struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES];  }; + +extern void +radeon_add_atom_connector(struct drm_device *dev, +			  uint32_t connector_id, +			  uint32_t supported_device, +			  int connector_type, +			  struct radeon_i2c_bus_rec *i2c_bus, +			  uint32_t igp_lane_info, +			  uint16_t connector_object_id, +			  struct radeon_hpd *hpd, +			  struct radeon_router *router); +extern void +radeon_add_legacy_connector(struct drm_device *dev, +			    uint32_t connector_id, +			    uint32_t supported_device, +			    int connector_type, +			    struct radeon_i2c_bus_rec *i2c_bus, +			    uint16_t connector_object_id, +			    struct radeon_hpd *hpd); +extern uint32_t +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, +			uint8_t dac); +extern void radeon_link_encoder_connector(struct drm_device *dev); +  extern enum radeon_tv_std  radeon_combios_get_tv_info(struct radeon_device *rdev);  extern enum radeon_tv_std @@ -623,6 +667,15 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev);  extern void radeon_atombios_get_default_voltages(struct radeon_device *rdev,  						 u16 *vddc, u16 *vddci, u16 *mvdd); +extern void +radeon_combios_connected_scratch_regs(struct drm_connector *connector, +				      struct drm_encoder *encoder, +				      bool connected); +extern void +radeon_atombios_connected_scratch_regs(struct drm_connector *connector, +				       struct drm_encoder *encoder, +				       bool connected); +  extern struct drm_connector *  radeon_get_connector_for_encoder(struct drm_encoder *encoder);  extern struct drm_connector * @@ -648,6 +701,9 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);  extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);  extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,  				    struct drm_connector *connector); +extern void radeon_dp_set_rx_power_state(struct drm_connector *connector, +					 u8 power_state); +extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);  extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);  extern void radeon_atom_encoder_init(struct radeon_device *rdev);  extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev); @@ -656,8 +712,7 @@ extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,  					   uint8_t lane_set);  extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);  extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder); -extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, -				u8 write_byte, u8 *read_byte); +void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);  extern void radeon_i2c_init(struct radeon_device *rdev);  extern void radeon_i2c_fini(struct radeon_device *rdev); @@ -668,9 +723,6 @@ extern void radeon_i2c_add(struct radeon_device *rdev,  			   const char *name);  extern struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,  						 struct radeon_i2c_bus_rec *i2c_bus); -extern struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, -						    struct radeon_i2c_bus_rec *rec, -						    const char *name);  extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,  						 struct radeon_i2c_bus_rec *rec,  						 const char *name); @@ -758,7 +810,9 @@ extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,  				   int x, int y);  extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, -				      int *vpos, int *hpos); +				      unsigned int flags, +				      int *vpos, int *hpos, ktime_t *stime, +				      ktime_t *etime);  extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);  extern struct edid * @@ -850,6 +904,12 @@ void radeon_legacy_tv_mode_set(struct drm_encoder *encoder,  			       struct drm_display_mode *mode,  			       struct drm_display_mode *adjusted_mode); +/* fmt blocks */ +void avivo_program_fmt(struct drm_encoder *encoder); +void dce3_program_fmt(struct drm_encoder *encoder); +void dce4_program_fmt(struct drm_encoder *encoder); +void dce8_program_fmt(struct drm_encoder *encoder); +  /* fbdev layer */  int radeon_fbdev_init(struct radeon_device *rdev);  void radeon_fbdev_fini(struct radeon_device *rdev); @@ -859,6 +919,7 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)  void radeon_fb_output_poll_changed(struct radeon_device *rdev); +void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id);  void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);  int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index c0fa4aa9cee..6c717b257d6 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -46,7 +46,7 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo);   * function are calling it.   */ -void radeon_bo_clear_va(struct radeon_bo *bo) +static void radeon_bo_clear_va(struct radeon_bo *bo)  {  	struct radeon_bo_va *bo_va, *tmp; @@ -56,11 +56,36 @@ void radeon_bo_clear_va(struct radeon_bo *bo)  	}  } +static void radeon_update_memory_usage(struct radeon_bo *bo, +				       unsigned mem_type, int sign) +{ +	struct radeon_device *rdev = bo->rdev; +	u64 size = (u64)bo->tbo.num_pages << PAGE_SHIFT; + +	switch (mem_type) { +	case TTM_PL_TT: +		if (sign > 0) +			atomic64_add(size, &rdev->gtt_usage); +		else +			atomic64_sub(size, &rdev->gtt_usage); +		break; +	case TTM_PL_VRAM: +		if (sign > 0) +			atomic64_add(size, &rdev->vram_usage); +		else +			atomic64_sub(size, &rdev->vram_usage); +		break; +	} +} +  static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)  {  	struct radeon_bo *bo;  	bo = container_of(tbo, struct radeon_bo, tbo); + +	radeon_update_memory_usage(bo, bo->tbo.mem.mem_type, -1); +  	mutex_lock(&bo->rdev->gem.mutex);  	list_del_init(&bo->list);  	mutex_unlock(&bo->rdev->gem.mutex); @@ -79,7 +104,7 @@ bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo)  void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)  { -	u32 c = 0; +	u32 c = 0, i;  	rbo->placement.fpfn = 0;  	rbo->placement.lpfn = 0; @@ -106,6 +131,17 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)  		rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;  	rbo->placement.num_placement = c;  	rbo->placement.num_busy_placement = c; + +	/* +	 * Use two-ended allocation depending on the buffer size to +	 * improve fragmentation quality. +	 * 512kb was measured as the most optimal number. +	 */ +	if (rbo->tbo.mem.size > 512 * 1024) { +		for (i = 0; i < c; i++) { +			rbo->placements[i] |= TTM_PL_FLAG_TOPDOWN; +		} +	}  }  int radeon_bo_create(struct radeon_device *rdev, @@ -120,7 +156,6 @@ int radeon_bo_create(struct radeon_device *rdev,  	size = ALIGN(size, PAGE_SIZE); -	rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;  	if (kernel) {  		type = ttm_bo_type_kernel;  	} else if (sg) { @@ -145,6 +180,9 @@ int radeon_bo_create(struct radeon_device *rdev,  	bo->surface_reg = -1;  	INIT_LIST_HEAD(&bo->list);  	INIT_LIST_HEAD(&bo->va); +	bo->initial_domain = domain & (RADEON_GEM_DOMAIN_VRAM | +	                               RADEON_GEM_DOMAIN_GTT | +	                               RADEON_GEM_DOMAIN_CPU);  	radeon_ttm_placement_from_domain(bo, domain);  	/* Kernel allocation are uninterruptible */  	down_read(&rdev->pm.mclk_lock); @@ -338,42 +376,109 @@ void radeon_bo_fini(struct radeon_device *rdev)  	arch_phys_wc_del(rdev->mc.vram_mtrr);  } -void radeon_bo_list_add_object(struct radeon_bo_list *lobj, -				struct list_head *head) +/* Returns how many bytes TTM can move per IB. + */ +static u64 radeon_bo_get_threshold_for_moves(struct radeon_device *rdev)  { -	if (lobj->written) { -		list_add(&lobj->tv.head, head); -	} else { -		list_add_tail(&lobj->tv.head, head); -	} +	u64 real_vram_size = rdev->mc.real_vram_size; +	u64 vram_usage = atomic64_read(&rdev->vram_usage); + +	/* This function is based on the current VRAM usage. +	 * +	 * - If all of VRAM is free, allow relocating the number of bytes that +	 *   is equal to 1/4 of the size of VRAM for this IB. + +	 * - If more than one half of VRAM is occupied, only allow relocating +	 *   1 MB of data for this IB. +	 * +	 * - From 0 to one half of used VRAM, the threshold decreases +	 *   linearly. +	 *         __________________ +	 * 1/4 of -|\               | +	 * VRAM    | \              | +	 *         |  \             | +	 *         |   \            | +	 *         |    \           | +	 *         |     \          | +	 *         |      \         | +	 *         |       \________|1 MB +	 *         |----------------| +	 *    VRAM 0 %             100 % +	 *         used            used +	 * +	 * Note: It's a threshold, not a limit. The threshold must be crossed +	 * for buffer relocations to stop, so any buffer of an arbitrary size +	 * can be moved as long as the threshold isn't crossed before +	 * the relocation takes place. We don't want to disable buffer +	 * relocations completely. +	 * +	 * The idea is that buffers should be placed in VRAM at creation time +	 * and TTM should only do a minimum number of relocations during +	 * command submission. In practice, you need to submit at least +	 * a dozen IBs to move all buffers to VRAM if they are in GTT. +	 * +	 * Also, things can get pretty crazy under memory pressure and actual +	 * VRAM usage can change a lot, so playing safe even at 50% does +	 * consistently increase performance. +	 */ + +	u64 half_vram = real_vram_size >> 1; +	u64 half_free_vram = vram_usage >= half_vram ? 0 : half_vram - vram_usage; +	u64 bytes_moved_threshold = half_free_vram >> 1; +	return max(bytes_moved_threshold, 1024*1024ull);  } -int radeon_bo_list_validate(struct ww_acquire_ctx *ticket, +int radeon_bo_list_validate(struct radeon_device *rdev, +			    struct ww_acquire_ctx *ticket,  			    struct list_head *head, int ring)  { -	struct radeon_bo_list *lobj; +	struct radeon_cs_reloc *lobj;  	struct radeon_bo *bo; -	u32 domain;  	int r; +	u64 bytes_moved = 0, initial_bytes_moved; +	u64 bytes_moved_threshold = radeon_bo_get_threshold_for_moves(rdev);  	r = ttm_eu_reserve_buffers(ticket, head);  	if (unlikely(r != 0)) {  		return r;  	} +  	list_for_each_entry(lobj, head, tv.head) { -		bo = lobj->bo; +		bo = lobj->robj;  		if (!bo->pin_count) { -			domain = lobj->domain; -			 +			u32 domain = lobj->prefered_domains; +			u32 current_domain = +				radeon_mem_type_to_domain(bo->tbo.mem.mem_type); + +			/* Check if this buffer will be moved and don't move it +			 * if we have moved too many buffers for this IB already. +			 * +			 * Note that this allows moving at least one buffer of +			 * any size, because it doesn't take the current "bo" +			 * into account. We don't want to disallow buffer moves +			 * completely. +			 */ +			if ((lobj->allowed_domains & current_domain) != 0 && +			    (domain & current_domain) == 0 && /* will be moved */ +			    bytes_moved > bytes_moved_threshold) { +				/* don't move it */ +				domain = current_domain; +			} +  		retry:  			radeon_ttm_placement_from_domain(bo, domain);  			if (ring == R600_RING_TYPE_UVD_INDEX)  				radeon_uvd_force_into_uvd_segment(bo); -			r = ttm_bo_validate(&bo->tbo, &bo->placement, -						true, false); + +			initial_bytes_moved = atomic64_read(&rdev->num_bytes_moved); +			r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); +			bytes_moved += atomic64_read(&rdev->num_bytes_moved) - +				       initial_bytes_moved; +  			if (unlikely(r)) { -				if (r != -ERESTARTSYS && domain != lobj->alt_domain) { -					domain = lobj->alt_domain; +				if (r != -ERESTARTSYS && +				    domain != lobj->allowed_domains) { +					domain = lobj->allowed_domains;  					goto retry;  				}  				ttm_eu_backoff_reservation(ticket, head); @@ -564,14 +669,23 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,  }  void radeon_bo_move_notify(struct ttm_buffer_object *bo, -			   struct ttm_mem_reg *mem) +			   struct ttm_mem_reg *new_mem)  {  	struct radeon_bo *rbo; +  	if (!radeon_ttm_bo_is_radeon_bo(bo))  		return; +  	rbo = container_of(bo, struct radeon_bo, tbo);  	radeon_bo_check_tiling(rbo, 0, 1);  	radeon_vm_bo_invalidate(rbo->rdev, rbo); + +	/* update statistics */ +	if (!new_mem) +		return; + +	radeon_update_memory_usage(rbo, bo->mem.mem_type, -1); +	radeon_update_memory_usage(rbo, new_mem->mem_type, 1);  }  int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) @@ -586,22 +700,30 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)  	rbo = container_of(bo, struct radeon_bo, tbo);  	radeon_bo_check_tiling(rbo, 0, 0);  	rdev = rbo->rdev; -	if (bo->mem.mem_type == TTM_PL_VRAM) { -		size = bo->mem.num_pages << PAGE_SHIFT; -		offset = bo->mem.start << PAGE_SHIFT; -		if ((offset + size) > rdev->mc.visible_vram_size) { -			/* hurrah the memory is not visible ! */ -			radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM); -			rbo->placement.lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; -			r = ttm_bo_validate(bo, &rbo->placement, false, false); -			if (unlikely(r != 0)) -				return r; -			offset = bo->mem.start << PAGE_SHIFT; -			/* this should not happen */ -			if ((offset + size) > rdev->mc.visible_vram_size) -				return -EINVAL; -		} +	if (bo->mem.mem_type != TTM_PL_VRAM) +		return 0; + +	size = bo->mem.num_pages << PAGE_SHIFT; +	offset = bo->mem.start << PAGE_SHIFT; +	if ((offset + size) <= rdev->mc.visible_vram_size) +		return 0; + +	/* hurrah the memory is not visible ! */ +	radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM); +	rbo->placement.lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; +	r = ttm_bo_validate(bo, &rbo->placement, false, false); +	if (unlikely(r == -ENOMEM)) { +		radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); +		return ttm_bo_validate(bo, &rbo->placement, false, false); +	} else if (unlikely(r != 0)) { +		return r;  	} + +	offset = bo->mem.start << PAGE_SHIFT; +	/* this should never happen */ +	if ((offset + size) > rdev->mc.visible_vram_size) +		return -EINVAL; +  	return 0;  } @@ -609,7 +731,7 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait)  {  	int r; -	r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0); +	r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, NULL);  	if (unlikely(r != 0))  		return r;  	spin_lock(&bo->tbo.bdev->fence_lock); diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 209b1115026..5a873f31a17 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -65,7 +65,7 @@ static inline int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr)  {  	int r; -	r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, 0); +	r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, NULL);  	if (unlikely(r != 0)) {  		if (r != -ERESTARTSYS)  			dev_err(bo->rdev->dev, "%p reserve failed\n", bo); @@ -138,9 +138,8 @@ extern int radeon_bo_evict_vram(struct radeon_device *rdev);  extern void radeon_bo_force_delete(struct radeon_device *rdev);  extern int radeon_bo_init(struct radeon_device *rdev);  extern void radeon_bo_fini(struct radeon_device *rdev); -extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj, -				struct list_head *head); -extern int radeon_bo_list_validate(struct ww_acquire_ctx *ticket, +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); @@ -151,7 +150,7 @@ extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo,  extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,  				bool force_drop);  extern void radeon_bo_move_notify(struct ttm_buffer_object *bo, -					struct ttm_mem_reg *mem); +				  struct ttm_mem_reg *new_mem);  extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);  extern int radeon_bo_get_surface_reg(struct radeon_bo *bo); @@ -181,7 +180,7 @@ extern int radeon_sa_bo_manager_suspend(struct radeon_device *rdev,  extern int radeon_sa_bo_new(struct radeon_device *rdev,  			    struct radeon_sa_manager *sa_manager,  			    struct radeon_sa_bo **sa_bo, -			    unsigned size, unsigned align, bool block); +			    unsigned size, unsigned align);  extern void radeon_sa_bo_free(struct radeon_device *rdev,  			      struct radeon_sa_bo **sa_bo,  			      struct radeon_fence *fence); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index ac07ad1d4f8..e447e390d09 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -73,8 +73,10 @@ void radeon_pm_acpi_event_handler(struct radeon_device *rdev)  			rdev->pm.dpm.ac_power = true;  		else  			rdev->pm.dpm.ac_power = false; -		if (rdev->asic->dpm.enable_bapm) -			radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power); +		if (rdev->family == CHIP_ARUBA) { +			if (rdev->asic->dpm.enable_bapm) +				radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power); +		}  		mutex_unlock(&rdev->pm.mutex);          } else if (rdev->pm.pm_method == PM_METHOD_PROFILE) {  		if (rdev->pm.profile == PM_PROFILE_AUTO) { @@ -260,7 +262,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)  		if (!ring->ready) {  			continue;  		} -		r = radeon_fence_wait_empty_locked(rdev, i); +		r = radeon_fence_wait_empty(rdev, i);  		if (r) {  			/* needs a GPU reset dont reset here */  			mutex_unlock(&rdev->ring_lock); @@ -361,6 +363,11 @@ static ssize_t radeon_set_pm_profile(struct device *dev,  	struct drm_device *ddev = dev_get_drvdata(dev);  	struct radeon_device *rdev = ddev->dev_private; +	/* Can't set profile when the card is off */ +	if  ((rdev->flags & RADEON_IS_PX) && +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) +		return -EINVAL; +  	mutex_lock(&rdev->pm.mutex);  	if (rdev->pm.pm_method == PM_METHOD_PROFILE) {  		if (strncmp("default", buf, strlen("default")) == 0) @@ -409,6 +416,13 @@ static ssize_t radeon_set_pm_method(struct device *dev,  	struct drm_device *ddev = dev_get_drvdata(dev);  	struct radeon_device *rdev = ddev->dev_private; +	/* Can't set method when the card is off */ +	if  ((rdev->flags & RADEON_IS_PX) && +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { +		count = -EINVAL; +		goto fail; +	} +  	/* we don't support the legacy modes with dpm */  	if (rdev->pm.pm_method == PM_METHOD_DPM) {  		count = -EINVAL; @@ -446,6 +460,10 @@ static ssize_t radeon_get_dpm_state(struct device *dev,  	struct radeon_device *rdev = ddev->dev_private;  	enum radeon_pm_state_type pm = rdev->pm.dpm.user_state; +	if  ((rdev->flags & RADEON_IS_PX) && +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) +		return snprintf(buf, PAGE_SIZE, "off\n"); +  	return snprintf(buf, PAGE_SIZE, "%s\n",  			(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :  			(pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance"); @@ -459,6 +477,11 @@ static ssize_t radeon_set_dpm_state(struct device *dev,  	struct drm_device *ddev = dev_get_drvdata(dev);  	struct radeon_device *rdev = ddev->dev_private; +	/* Can't set dpm state when the card is off */ +	if  ((rdev->flags & RADEON_IS_PX) && +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) +		return -EINVAL; +  	mutex_lock(&rdev->pm.mutex);  	if (strncmp("battery", buf, strlen("battery")) == 0)  		rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY; @@ -485,6 +508,10 @@ static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,  	struct radeon_device *rdev = ddev->dev_private;  	enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; +	if  ((rdev->flags & RADEON_IS_PX) && +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) +		return snprintf(buf, PAGE_SIZE, "off\n"); +  	return snprintf(buf, PAGE_SIZE, "%s\n",  			(level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :  			(level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high"); @@ -500,6 +527,11 @@ static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,  	enum radeon_dpm_forced_level level;  	int ret = 0; +	/* Can't force performance level when the card is off */ +	if  ((rdev->flags & RADEON_IS_PX) && +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) +		return -EINVAL; +  	mutex_lock(&rdev->pm.mutex);  	if (strncmp("low", buf, strlen("low")) == 0) {  		level = RADEON_DPM_FORCED_LEVEL_LOW; @@ -508,17 +540,21 @@ static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,  	} else if (strncmp("auto", buf, strlen("auto")) == 0) {  		level = RADEON_DPM_FORCED_LEVEL_AUTO;  	} else { -		mutex_unlock(&rdev->pm.mutex);  		count = -EINVAL;  		goto fail;  	}  	if (rdev->asic->dpm.force_performance_level) { +		if (rdev->pm.dpm.thermal_active) { +			count = -EINVAL; +			goto fail; +		}  		ret = radeon_dpm_force_performance_level(rdev, level);  		if (ret)  			count = -EINVAL;  	} -	mutex_unlock(&rdev->pm.mutex);  fail: +	mutex_unlock(&rdev->pm.mutex); +  	return count;  } @@ -533,10 +569,15 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,  				      struct device_attribute *attr,  				      char *buf)  { -	struct drm_device *ddev = dev_get_drvdata(dev); -	struct radeon_device *rdev = ddev->dev_private; +	struct radeon_device *rdev = dev_get_drvdata(dev); +	struct drm_device *ddev = rdev->ddev;  	int temp; +	/* Can't get temperature when the card is off */ +	if  ((rdev->flags & RADEON_IS_PX) && +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) +		return -EINVAL; +  	if (rdev->asic->pm.get_temperature)  		temp = radeon_get_temperature(rdev);  	else @@ -549,8 +590,7 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,  					     struct device_attribute *attr,  					     char *buf)  { -	struct drm_device *ddev = dev_get_drvdata(dev); -	struct radeon_device *rdev = ddev->dev_private; +	struct radeon_device *rdev = dev_get_drvdata(dev);  	int hyst = to_sensor_dev_attr(attr)->index;  	int temp; @@ -562,23 +602,14 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,  	return snprintf(buf, PAGE_SIZE, "%d\n", temp);  } -static ssize_t radeon_hwmon_show_name(struct device *dev, -				      struct device_attribute *attr, -				      char *buf) -{ -	return sprintf(buf, "radeon\n"); -} -  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(name, S_IRUGO, radeon_hwmon_show_name, 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_name.dev_attr.attr,  	NULL  }; @@ -586,8 +617,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,  					struct attribute *attr, int index)  {  	struct device *dev = container_of(kobj, struct device, kobj); -	struct drm_device *ddev = dev_get_drvdata(dev); -	struct radeon_device *rdev = ddev->dev_private; +	struct radeon_device *rdev = dev_get_drvdata(dev);  	/* Skip limit attributes if DPM is not enabled */  	if (rdev->pm.pm_method != PM_METHOD_DPM && @@ -603,12 +633,15 @@ static const struct attribute_group hwmon_attrgroup = {  	.is_visible = hwmon_attributes_visible,  }; +static const struct attribute_group *hwmon_groups[] = { +	&hwmon_attrgroup, +	NULL +}; +  static int radeon_hwmon_init(struct radeon_device *rdev)  {  	int err = 0; -	rdev->pm.int_hwmon_dev = NULL; -  	switch (rdev->pm.int_thermal_type) {  	case THERMAL_TYPE_RV6XX:  	case THERMAL_TYPE_RV770: @@ -620,20 +653,13 @@ static int radeon_hwmon_init(struct radeon_device *rdev)  	case THERMAL_TYPE_KV:  		if (rdev->asic->pm.get_temperature == NULL)  			return err; -		rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev); +		rdev->pm.int_hwmon_dev = hwmon_device_register_with_groups(rdev->dev, +									   "radeon", rdev, +									   hwmon_groups);  		if (IS_ERR(rdev->pm.int_hwmon_dev)) {  			err = PTR_ERR(rdev->pm.int_hwmon_dev);  			dev_err(rdev->dev,  				"Unable to register hwmon device: %d\n", err); -			break; -		} -		dev_set_drvdata(rdev->pm.int_hwmon_dev, rdev->ddev); -		err = sysfs_create_group(&rdev->pm.int_hwmon_dev->kobj, -					 &hwmon_attrgroup); -		if (err) { -			dev_err(rdev->dev, -				"Unable to create hwmon sysfs file: %d\n", err); -			hwmon_device_unregister(rdev->dev);  		}  		break;  	default: @@ -645,10 +671,8 @@ static int radeon_hwmon_init(struct radeon_device *rdev)  static void radeon_hwmon_fini(struct radeon_device *rdev)  { -	if (rdev->pm.int_hwmon_dev) { -		sysfs_remove_group(&rdev->pm.int_hwmon_dev->kobj, &hwmon_attrgroup); +	if (rdev->pm.int_hwmon_dev)  		hwmon_device_unregister(rdev->pm.int_hwmon_dev); -	}  }  static void radeon_dpm_thermal_work_handler(struct work_struct *work) @@ -845,6 +869,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)  	/* no need to reprogram if nothing changed unless we are on BTC+ */  	if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) { +		/* vce just modifies an existing state so force a change */ +		if (ps->vce_active != rdev->pm.dpm.vce_active) +			goto force;  		if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) {  			/* for pre-BTC and APUs if the num crtcs changed but state is the same,  			 * all we need to do is update the display configuration. @@ -881,15 +908,21 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)  		}  	} -	printk("switching from power state:\n"); -	radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps); -	printk("switching to power state:\n"); -	radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps); +force: +	if (radeon_dpm == 1) { +		printk("switching from power state:\n"); +		radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps); +		printk("switching to power state:\n"); +		radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps); +	}  	mutex_lock(&rdev->ddev->struct_mutex);  	down_write(&rdev->pm.mclk_lock);  	mutex_lock(&rdev->ring_lock); +	/* update whether vce is active */ +	ps->vce_active = rdev->pm.dpm.vce_active; +  	ret = radeon_dpm_pre_set_power_state(rdev);  	if (ret)  		goto done; @@ -906,7 +939,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)  	for (i = 0; i < RADEON_NUM_RINGS; i++) {  		struct radeon_ring *ring = &rdev->ring[i];  		if (ring->ready) -			radeon_fence_wait_empty_locked(rdev, i); +			radeon_fence_wait_empty(rdev, i);  	}  	/* program the new power state */ @@ -918,12 +951,16 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)  	radeon_dpm_post_set_power_state(rdev);  	if (rdev->asic->dpm.force_performance_level) { -		if (rdev->pm.dpm.thermal_active) +		if (rdev->pm.dpm.thermal_active) { +			enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;  			/* force low perf level for thermal */  			radeon_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_LOW); -		else -			/* otherwise, enable auto */ -			radeon_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO); +			/* save the user's level */ +			rdev->pm.dpm.forced_level = level; +		} else { +			/* otherwise, user selected level */ +			radeon_dpm_force_performance_level(rdev, rdev->pm.dpm.forced_level); +		}  	}  done: @@ -938,6 +975,10 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)  	if (rdev->asic->dpm.powergate_uvd) {  		mutex_lock(&rdev->pm.mutex); +		/* don't powergate anything if we +		   have active but pause streams */ +		enable |= rdev->pm.dpm.sd > 0; +		enable |= rdev->pm.dpm.hd > 0;  		/* enable/disable UVD */  		radeon_dpm_powergate_uvd(rdev, !enable);  		mutex_unlock(&rdev->pm.mutex); @@ -945,6 +986,8 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)  		if (enable) {  			mutex_lock(&rdev->pm.mutex);  			rdev->pm.dpm.uvd_active = true; +			/* disable this for now */ +#if 0  			if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0))  				dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD;  			else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0)) @@ -954,6 +997,7 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)  			else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2))  				dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2;  			else +#endif  				dpm_state = POWER_STATE_TYPE_INTERNAL_UVD;  			rdev->pm.dpm.state = dpm_state;  			mutex_unlock(&rdev->pm.mutex); @@ -967,6 +1011,23 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)  	}  } +void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable) +{ +	if (enable) { +		mutex_lock(&rdev->pm.mutex); +		rdev->pm.dpm.vce_active = true; +		/* XXX select vce level based on ring/task */ +		rdev->pm.dpm.vce_level = RADEON_VCE_LEVEL_AC_ALL; +		mutex_unlock(&rdev->pm.mutex); +	} else { +		mutex_lock(&rdev->pm.mutex); +		rdev->pm.dpm.vce_active = false; +		mutex_unlock(&rdev->pm.mutex); +	} + +	radeon_pm_compute_clocks(rdev); +} +  static void radeon_pm_suspend_old(struct radeon_device *rdev)  {  	mutex_lock(&rdev->pm.mutex); @@ -1021,8 +1082,10 @@ static void radeon_pm_resume_old(struct radeon_device *rdev)  	rdev->pm.current_clock_mode_index = 0;  	rdev->pm.current_sclk = rdev->pm.default_sclk;  	rdev->pm.current_mclk = rdev->pm.default_mclk; -	rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; -	rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; +	if (rdev->pm.power_state) { +		rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; +		rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; +	}  	if (rdev->pm.pm_method == PM_METHOD_DYNPM  	    && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) {  		rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; @@ -1043,25 +1106,26 @@ static void radeon_pm_resume_dpm(struct radeon_device *rdev)  	radeon_dpm_setup_asic(rdev);  	ret = radeon_dpm_enable(rdev);  	mutex_unlock(&rdev->pm.mutex); -	if (ret) { -		DRM_ERROR("radeon: dpm resume failed\n"); -		if ((rdev->family >= CHIP_BARTS) && -		    (rdev->family <= CHIP_CAYMAN) && -		    rdev->mc_fw) { -			if (rdev->pm.default_vddc) -				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, -							SET_VOLTAGE_TYPE_ASIC_VDDC); -			if (rdev->pm.default_vddci) -				radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, -							SET_VOLTAGE_TYPE_ASIC_VDDCI); -			if (rdev->pm.default_sclk) -				radeon_set_engine_clock(rdev, rdev->pm.default_sclk); -			if (rdev->pm.default_mclk) -				radeon_set_memory_clock(rdev, rdev->pm.default_mclk); -		} -	} else { -		rdev->pm.dpm_enabled = true; -		radeon_pm_compute_clocks(rdev); +	if (ret) +		goto dpm_resume_fail; +	rdev->pm.dpm_enabled = true; +	return; + +dpm_resume_fail: +	DRM_ERROR("radeon: dpm resume failed\n"); +	if ((rdev->family >= CHIP_BARTS) && +	    (rdev->family <= CHIP_CAYMAN) && +	    rdev->mc_fw) { +		if (rdev->pm.default_vddc) +			radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, +						SET_VOLTAGE_TYPE_ASIC_VDDC); +		if (rdev->pm.default_vddci) +			radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, +						SET_VOLTAGE_TYPE_ASIC_VDDCI); +		if (rdev->pm.default_sclk) +			radeon_set_engine_clock(rdev, rdev->pm.default_sclk); +		if (rdev->pm.default_mclk) +			radeon_set_memory_clock(rdev, rdev->pm.default_mclk);  	}  } @@ -1176,55 +1240,55 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev)  	mutex_lock(&rdev->pm.mutex);  	radeon_dpm_init(rdev);  	rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; -	radeon_dpm_print_power_states(rdev); +	if (radeon_dpm == 1) +		radeon_dpm_print_power_states(rdev);  	radeon_dpm_setup_asic(rdev);  	ret = radeon_dpm_enable(rdev);  	mutex_unlock(&rdev->pm.mutex); -	if (ret) { -		rdev->pm.dpm_enabled = false; -		if ((rdev->family >= CHIP_BARTS) && -		    (rdev->family <= CHIP_CAYMAN) && -		    rdev->mc_fw) { -			if (rdev->pm.default_vddc) -				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, -							SET_VOLTAGE_TYPE_ASIC_VDDC); -			if (rdev->pm.default_vddci) -				radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, -							SET_VOLTAGE_TYPE_ASIC_VDDCI); -			if (rdev->pm.default_sclk) -				radeon_set_engine_clock(rdev, rdev->pm.default_sclk); -			if (rdev->pm.default_mclk) -				radeon_set_memory_clock(rdev, rdev->pm.default_mclk); -		} -		DRM_ERROR("radeon: dpm initialization failed\n"); -		return ret; -	} +	if (ret) +		goto dpm_failed;  	rdev->pm.dpm_enabled = true; -	radeon_pm_compute_clocks(rdev); - -	if (rdev->pm.num_power_states > 1) { -		ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); -		if (ret) -			DRM_ERROR("failed to create device file for dpm state\n"); -		ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); -		if (ret) -			DRM_ERROR("failed to create device file for dpm state\n"); -		/* XXX: these are noops for dpm but are here for backwards compat */ -		ret = device_create_file(rdev->dev, &dev_attr_power_profile); -		if (ret) -			DRM_ERROR("failed to create device file for power profile\n"); -		ret = device_create_file(rdev->dev, &dev_attr_power_method); -		if (ret) -			DRM_ERROR("failed to create device file for power method\n"); -		if (radeon_debugfs_pm_init(rdev)) { -			DRM_ERROR("Failed to register debugfs file for dpm!\n"); -		} +	ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); +	if (ret) +		DRM_ERROR("failed to create device file for dpm state\n"); +	ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); +	if (ret) +		DRM_ERROR("failed to create device file for dpm state\n"); +	/* XXX: these are noops for dpm but are here for backwards compat */ +	ret = device_create_file(rdev->dev, &dev_attr_power_profile); +	if (ret) +		DRM_ERROR("failed to create device file for power profile\n"); +	ret = device_create_file(rdev->dev, &dev_attr_power_method); +	if (ret) +		DRM_ERROR("failed to create device file for power method\n"); -		DRM_INFO("radeon: dpm initialized\n"); +	if (radeon_debugfs_pm_init(rdev)) { +		DRM_ERROR("Failed to register debugfs file for dpm!\n");  	} +	DRM_INFO("radeon: dpm initialized\n"); +  	return 0; + +dpm_failed: +	rdev->pm.dpm_enabled = false; +	if ((rdev->family >= CHIP_BARTS) && +	    (rdev->family <= CHIP_CAYMAN) && +	    rdev->mc_fw) { +		if (rdev->pm.default_vddc) +			radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, +						SET_VOLTAGE_TYPE_ASIC_VDDC); +		if (rdev->pm.default_vddci) +			radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, +						SET_VOLTAGE_TYPE_ASIC_VDDCI); +		if (rdev->pm.default_sclk) +			radeon_set_engine_clock(rdev, rdev->pm.default_sclk); +		if (rdev->pm.default_mclk) +			radeon_set_memory_clock(rdev, rdev->pm.default_mclk); +	} +	DRM_ERROR("radeon: dpm initialization failed\n"); +	return ret;  }  int radeon_pm_init(struct radeon_device *rdev) @@ -1239,6 +1303,22 @@ int radeon_pm_init(struct radeon_device *rdev)  	case CHIP_RS780:  	case CHIP_RS880:  	case CHIP_RV770: +	case CHIP_BARTS: +	case CHIP_TURKS: +	case CHIP_CAICOS: +	case CHIP_CAYMAN: +		/* DPM requires the RLC, RV770+ dGPU requires SMC */ +		if (!rdev->rlc_fw) +			rdev->pm.pm_method = PM_METHOD_PROFILE; +		else if ((rdev->family >= CHIP_RV770) && +			 (!(rdev->flags & RADEON_IS_IGP)) && +			 (!rdev->smc_fw)) +			rdev->pm.pm_method = PM_METHOD_PROFILE; +		else if (radeon_dpm == 1) +			rdev->pm.pm_method = PM_METHOD_DPM; +		else +			rdev->pm.pm_method = PM_METHOD_PROFILE; +		break;  	case CHIP_RV730:  	case CHIP_RV710:  	case CHIP_RV740: @@ -1250,10 +1330,6 @@ int radeon_pm_init(struct radeon_device *rdev)  	case CHIP_PALM:  	case CHIP_SUMO:  	case CHIP_SUMO2: -	case CHIP_BARTS: -	case CHIP_TURKS: -	case CHIP_CAICOS: -	case CHIP_CAYMAN:  	case CHIP_ARUBA:  	case CHIP_TAHITI:  	case CHIP_PITCAIRN: @@ -1263,6 +1339,8 @@ int radeon_pm_init(struct radeon_device *rdev)  	case CHIP_BONAIRE:  	case CHIP_KABINI:  	case CHIP_KAVERI: +	case CHIP_HAWAII: +	case CHIP_MULLINS:  		/* DPM requires the RLC, RV770+ dGPU requires SMC */  		if (!rdev->rlc_fw)  			rdev->pm.pm_method = PM_METHOD_PROFILE; @@ -1270,10 +1348,10 @@ 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 (radeon_dpm == 1) -			rdev->pm.pm_method = PM_METHOD_DPM; -		else +		else if (radeon_dpm == 0)  			rdev->pm.pm_method = PM_METHOD_PROFILE; +		else +			rdev->pm.pm_method = PM_METHOD_DPM;  		break;  	default:  		/* default to profile method */ @@ -1287,6 +1365,18 @@ int radeon_pm_init(struct radeon_device *rdev)  		return radeon_pm_init_old(rdev);  } +int radeon_pm_late_init(struct radeon_device *rdev) +{ +	int ret = 0; + +	if (rdev->pm.pm_method == PM_METHOD_DPM) { +		mutex_lock(&rdev->pm.mutex); +		ret = radeon_dpm_late_enable(rdev); +		mutex_unlock(&rdev->pm.mutex); +	} +	return ret; +} +  static void radeon_pm_fini_old(struct radeon_device *rdev)  {  	if (rdev->pm.num_power_states > 1) { @@ -1309,10 +1399,10 @@ static void radeon_pm_fini_old(struct radeon_device *rdev)  		device_remove_file(rdev->dev, &dev_attr_power_method);  	} +	radeon_hwmon_fini(rdev); +  	if (rdev->pm.power_state)  		kfree(rdev->pm.power_state); - -	radeon_hwmon_fini(rdev);  }  static void radeon_pm_fini_dpm(struct radeon_device *rdev) @@ -1330,10 +1420,10 @@ static void radeon_pm_fini_dpm(struct radeon_device *rdev)  	}  	radeon_dpm_fini(rdev); +	radeon_hwmon_fini(rdev); +  	if (rdev->pm.power_state)  		kfree(rdev->pm.power_state); - -	radeon_hwmon_fini(rdev);  }  void radeon_pm_fini(struct radeon_device *rdev) @@ -1357,12 +1447,14 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)  	rdev->pm.active_crtcs = 0;  	rdev->pm.active_crtc_count = 0; -	list_for_each_entry(crtc, -		&ddev->mode_config.crtc_list, head) { -		radeon_crtc = to_radeon_crtc(crtc); -		if (radeon_crtc->enabled) { -			rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); -			rdev->pm.active_crtc_count++; +	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, +				    &ddev->mode_config.crtc_list, head) { +			radeon_crtc = to_radeon_crtc(crtc); +			if (radeon_crtc->enabled) { +				rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); +				rdev->pm.active_crtc_count++; +			}  		}  	} @@ -1421,17 +1513,22 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)  	struct drm_crtc *crtc;  	struct radeon_crtc *radeon_crtc; +	if (!rdev->pm.dpm_enabled) +		return; +  	mutex_lock(&rdev->pm.mutex);  	/* update active crtc counts */  	rdev->pm.dpm.new_active_crtcs = 0;  	rdev->pm.dpm.new_active_crtc_count = 0; -	list_for_each_entry(crtc, -		&ddev->mode_config.crtc_list, head) { -		radeon_crtc = to_radeon_crtc(crtc); -		if (crtc->enabled) { -			rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id); -			rdev->pm.dpm.new_active_crtc_count++; +	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, +				    &ddev->mode_config.crtc_list, head) { +			radeon_crtc = to_radeon_crtc(crtc); +			if (crtc->enabled) { +				rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id); +				rdev->pm.dpm.new_active_crtc_count++; +			}  		}  	} @@ -1465,7 +1562,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)  	 */  	for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {  		if (rdev->pm.active_crtcs & (1 << crtc)) { -			vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos); +			vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL);  			if ((vbl_status & DRM_SCANOUTPOS_VALID) &&  			    !(vbl_status & DRM_SCANOUTPOS_INVBL))  				in_vbl = false; @@ -1557,8 +1654,12 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)  	struct drm_info_node *node = (struct drm_info_node *) m->private;  	struct drm_device *dev = node->minor->dev;  	struct radeon_device *rdev = dev->dev_private; +	struct drm_device *ddev = rdev->ddev; -	if (rdev->pm.dpm_enabled) { +	if  ((rdev->flags & RADEON_IS_PX) && +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { +		seq_printf(m, "PX asic powered off\n"); +	} else if (rdev->pm.dpm_enabled) {  		mutex_lock(&rdev->pm.mutex);  		if (rdev->asic->dpm.debugfs_print_current_performance_level)  			radeon_dpm_debugfs_print_current_performance_level(rdev, m); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 18254e1c3e7..f8050f5429e 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -61,9 +61,9 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,  		  struct radeon_ib *ib, struct radeon_vm *vm,  		  unsigned size)  { -	int i, r; +	int r; -	r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256, true); +	r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256);  	if (r) {  		dev_err(rdev->dev, "failed to get a new IB (%d)\n", r);  		return r; @@ -87,8 +87,6 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,  		ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo);  	}  	ib->is_const_ib = false; -	for (i = 0; i < RADEON_NUM_RINGS; ++i) -		ib->sync_to[i] = NULL;  	return 0;  } @@ -109,25 +107,6 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib)  }  /** - * radeon_ib_sync_to - sync to fence before executing the IB - * - * @ib: IB object to add fence to - * @fence: fence to sync to - * - * Sync to the fence before executing the IB - */ -void radeon_ib_sync_to(struct radeon_ib *ib, struct radeon_fence *fence) -{ -	struct radeon_fence *other; - -	if (!fence) -		return; - -	other = ib->sync_to[fence->ring]; -	ib->sync_to[fence->ring] = radeon_fence_later(fence, other); -} - -/**   * radeon_ib_schedule - schedule an IB (Indirect Buffer) on the ring   *   * @rdev: radeon_device pointer @@ -151,8 +130,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,  		       struct radeon_ib *const_ib)  {  	struct radeon_ring *ring = &rdev->ring[ib->ring]; -	bool need_sync = false; -	int i, r = 0; +	int r = 0;  	if (!ib->length_dw || !ring->ready) {  		/* TODO: Nothings in the ib we should report. */ @@ -161,29 +139,30 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,  	}  	/* 64 dwords should be enough for fence too */ -	r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_RINGS * 8); +	r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8);  	if (r) {  		dev_err(rdev->dev, "scheduling IB failed (%d).\n", r);  		return r;  	} -	for (i = 0; i < RADEON_NUM_RINGS; ++i) { -		struct radeon_fence *fence = ib->sync_to[i]; -		if (radeon_fence_need_sync(fence, ib->ring)) { -			need_sync = true; -			radeon_semaphore_sync_rings(rdev, ib->semaphore, -						    fence->ring, ib->ring); -			radeon_fence_note_sync(fence, ib->ring); -		} -	} -	/* immediately free semaphore when we don't need to sync */ -	if (!need_sync) { -		radeon_semaphore_free(rdev, &ib->semaphore, NULL); + +	/* grab a vm id if necessary */ +	if (ib->vm) { +		struct radeon_fence *vm_id_fence; +		vm_id_fence = radeon_vm_grab_id(rdev, ib->vm, ib->ring); +        	radeon_semaphore_sync_to(ib->semaphore, vm_id_fence);  	} -	/* if we can't remember our last VM flush then flush now! */ -	/* XXX figure out why we have to flush for every IB */ -	if (ib->vm /*&& !ib->vm->last_flush*/) { -		radeon_ring_vm_flush(rdev, ib->ring, ib->vm); + +	/* sync with other rings */ +	r = radeon_semaphore_sync_rings(rdev, ib->semaphore, ib->ring); +	if (r) { +		dev_err(rdev->dev, "failed to sync rings (%d)\n", r); +		radeon_ring_unlock_undo(rdev, ring); +		return r;  	} + +	if (ib->vm) +		radeon_vm_flush(rdev, ib->vm, ib->ring); +  	if (const_ib) {  		radeon_ring_ib_execute(rdev, const_ib->ring, const_ib);  		radeon_semaphore_free(rdev, &const_ib->semaphore, NULL); @@ -198,10 +177,10 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,  	if (const_ib) {  		const_ib->fence = radeon_fence_ref(ib->fence);  	} -	/* we just flushed the VM, remember that */ -	if (ib->vm && !ib->vm->last_flush) { -		ib->vm->last_flush = radeon_fence_ref(ib->fence); -	} + +	if (ib->vm) +		radeon_vm_fence(rdev, ib->vm, ib->fence); +  	radeon_ring_unlock_commit(rdev, ring);  	return 0;  } @@ -283,6 +262,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev)  		r = radeon_ib_test(rdev, i, ring);  		if (r) {  			ring->ready = false; +			rdev->needs_reset = false;  			if (i == RADEON_RING_TYPE_GFX_INDEX) {  				/* oh, oh, that's really bad */ @@ -358,36 +338,6 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,  	}  } -u32 radeon_ring_generic_get_rptr(struct radeon_device *rdev, -				 struct radeon_ring *ring) -{ -	u32 rptr; - -	if (rdev->wb.enabled) -		rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); -	else -		rptr = RREG32(ring->rptr_reg); - -	return rptr; -} - -u32 radeon_ring_generic_get_wptr(struct radeon_device *rdev, -				 struct radeon_ring *ring) -{ -	u32 wptr; - -	wptr = RREG32(ring->wptr_reg); - -	return wptr; -} - -void radeon_ring_generic_set_wptr(struct radeon_device *rdev, -				  struct radeon_ring *ring) -{ -	WREG32(ring->wptr_reg, ring->wptr); -	(void)RREG32(ring->wptr_reg); -} -  /**   * radeon_ring_free_size - update the free size   * @@ -398,13 +348,17 @@ void radeon_ring_generic_set_wptr(struct radeon_device *rdev,   */  void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring)  { -	ring->rptr = radeon_ring_get_rptr(rdev, ring); +	uint32_t rptr = radeon_ring_get_rptr(rdev, ring); +  	/* This works because ring_size is a power of 2 */ -	ring->ring_free_dw = (ring->rptr + (ring->ring_size / 4)); +	ring->ring_free_dw = rptr + (ring->ring_size / 4);  	ring->ring_free_dw -= ring->wptr;  	ring->ring_free_dw &= ring->ptr_mask;  	if (!ring->ring_free_dw) { +		/* this is an empty ring */  		ring->ring_free_dw = ring->ring_size / 4; +		/*  update lockup info to avoid false positive */ +		radeon_ring_lockup_update(rdev, ring);  	}  } @@ -428,19 +382,13 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi  	/* Align requested size with padding so unlock_commit can  	 * pad safely */  	radeon_ring_free_size(rdev, ring); -	if (ring->ring_free_dw == (ring->ring_size / 4)) { -		/* This is an empty ring update lockup info to avoid -		 * false positive. -		 */ -		radeon_ring_lockup_update(ring); -	}  	ndw = (ndw + ring->align_mask) & ~ring->align_mask;  	while (ndw > (ring->ring_free_dw - 1)) {  		radeon_ring_free_size(rdev, ring);  		if (ndw < ring->ring_free_dw) {  			break;  		} -		r = radeon_fence_wait_next_locked(rdev, ring->idx); +		r = radeon_fence_wait_next(rdev, ring->idx);  		if (r)  			return r;  	} @@ -489,7 +437,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)  	while (ring->wptr & ring->align_mask) {  		radeon_ring_write(ring, ring->nop);  	} -	DRM_MEMORYBARRIER(); +	mb();  	radeon_ring_set_wptr(rdev, ring);  } @@ -534,39 +482,17 @@ void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *rin  }  /** - * radeon_ring_force_activity - add some nop packets to the ring - * - * @rdev: radeon_device pointer - * @ring: radeon_ring structure holding ring information - * - * Add some nop packets to the ring to force activity (all asics). - * Used for lockup detection to see if the rptr is advancing. - */ -void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring) -{ -	int r; - -	radeon_ring_free_size(rdev, ring); -	if (ring->rptr == ring->wptr) { -		r = radeon_ring_alloc(rdev, ring, 1); -		if (!r) { -			radeon_ring_write(ring, ring->nop); -			radeon_ring_commit(rdev, ring); -		} -	} -} - -/**   * radeon_ring_lockup_update - update lockup variables   *   * @ring: radeon_ring structure holding ring information   *   * Update the last rptr value and timestamp (all asics).   */ -void radeon_ring_lockup_update(struct radeon_ring *ring) +void radeon_ring_lockup_update(struct radeon_device *rdev, +			       struct radeon_ring *ring)  { -	ring->last_rptr = ring->rptr; -	ring->last_activity = jiffies; +	atomic_set(&ring->last_rptr, radeon_ring_get_rptr(rdev, ring)); +	atomic64_set(&ring->last_activity, jiffies_64);  }  /** @@ -574,40 +500,23 @@ void radeon_ring_lockup_update(struct radeon_ring *ring)   * @rdev:       radeon device structure   * @ring:       radeon_ring structure holding ring information   * - * We don't need to initialize the lockup tracking information as we will either - * have CP rptr to a different value of jiffies wrap around which will force - * initialization of the lockup tracking informations. - * - * A possible false positivie is if we get call after while and last_cp_rptr == - * the current CP rptr, even if it's unlikely it might happen. To avoid this - * if the elapsed time since last call is bigger than 2 second than we return - * false and update the tracking information. Due to this the caller must call - * radeon_ring_test_lockup several time in less than 2sec for lockup to be reported - * the fencing code should be cautious about that. - * - * Caller should write to the ring to force CP to do something so we don't get - * false positive when CP is just gived nothing to do. - * - **/ + */  bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  { -	unsigned long cjiffies, elapsed; +	uint32_t rptr = radeon_ring_get_rptr(rdev, ring); +	uint64_t last = atomic64_read(&ring->last_activity); +	uint64_t elapsed; -	cjiffies = jiffies; -	if (!time_after(cjiffies, ring->last_activity)) { -		/* likely a wrap around */ -		radeon_ring_lockup_update(ring); +	if (rptr != atomic_read(&ring->last_rptr)) { +		/* ring is still working, no lockup */ +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	ring->rptr = radeon_ring_get_rptr(rdev, ring); -	if (ring->rptr != ring->last_rptr) { -		/* CP is still working no lockup */ -		radeon_ring_lockup_update(ring); -		return false; -	} -	elapsed = jiffies_to_msecs(cjiffies - ring->last_activity); + +	elapsed = jiffies_to_msecs(jiffies_64 - last);  	if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) { -		dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); +		dev_err(rdev->dev, "ring %d stalled for more than %llumsec\n", +			ring->idx, elapsed);  		return true;  	}  	/* give a chance to the GPU ... */ @@ -715,22 +624,18 @@ int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring,   * @ring: radeon_ring structure holding ring information   * @ring_size: size of the ring   * @rptr_offs: offset of the rptr writeback location in the WB buffer - * @rptr_reg: MMIO offset of the rptr register - * @wptr_reg: MMIO offset of the wptr register   * @nop: nop packet for this ring   *   * Initialize the driver information for the selected ring (all asics).   * Returns 0 on success, error on failure.   */  int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size, -		     unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, u32 nop) +		     unsigned rptr_offs, u32 nop)  {  	int r;  	ring->ring_size = ring_size;  	ring->rptr_offs = rptr_offs; -	ring->rptr_reg = rptr_reg; -	ring->wptr_reg = wptr_reg;  	ring->nop = nop;  	/* Allocate ring buffer */  	if (ring->ring_obj == NULL) { @@ -769,7 +674,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig  	if (radeon_debugfs_ring_init(rdev, ring)) {  		DRM_ERROR("Failed to register debugfs file for rings !\n");  	} -	radeon_ring_lockup_update(ring); +	radeon_ring_lockup_update(rdev, ring);  	return 0;  } @@ -816,34 +721,52 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)  	struct radeon_device *rdev = dev->dev_private;  	int ridx = *(int*)node->info_ent->data;  	struct radeon_ring *ring = &rdev->ring[ridx]; + +	uint32_t rptr, wptr, rptr_next;  	unsigned count, i, j; -	u32 tmp;  	radeon_ring_free_size(rdev, ring);  	count = (ring->ring_size / 4) - ring->ring_free_dw; -	tmp = radeon_ring_get_wptr(rdev, ring); -	seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp); -	tmp = radeon_ring_get_rptr(rdev, ring); -	seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp); + +	wptr = radeon_ring_get_wptr(rdev, ring); +	seq_printf(m, "wptr: 0x%08x [%5d]\n", +		   wptr, wptr); + +	rptr = radeon_ring_get_rptr(rdev, ring); +	seq_printf(m, "rptr: 0x%08x [%5d]\n", +		   rptr, rptr); +  	if (ring->rptr_save_reg) { -		seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg, -			   RREG32(ring->rptr_save_reg)); -	} -	seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr); -	seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", ring->rptr, ring->rptr); -	seq_printf(m, "last semaphore signal addr : 0x%016llx\n", ring->last_semaphore_signal_addr); -	seq_printf(m, "last semaphore wait addr   : 0x%016llx\n", ring->last_semaphore_wait_addr); +		rptr_next = RREG32(ring->rptr_save_reg); +		seq_printf(m, "rptr next(0x%04x): 0x%08x [%5d]\n", +			   ring->rptr_save_reg, rptr_next, rptr_next); +	} else +		rptr_next = ~0; + +	seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", +		   ring->wptr, ring->wptr); +	seq_printf(m, "last semaphore signal addr : 0x%016llx\n", +		   ring->last_semaphore_signal_addr); +	seq_printf(m, "last semaphore wait addr   : 0x%016llx\n", +		   ring->last_semaphore_wait_addr);  	seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw);  	seq_printf(m, "%u dwords in ring\n", count); + +	if (!ring->ready) +		return 0; +  	/* print 8 dw before current rptr as often it's the last executed  	 * packet that is the root issue  	 */ -	i = (ring->rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask; -	if (ring->ready) { -		for (j = 0; j <= (count + 32); j++) { -			seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]); -			i = (i + 1) & ring->ptr_mask; -		} +	i = (rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask; +	for (j = 0; j <= (count + 32); j++) { +		seq_printf(m, "r[%5d]=0x%08x", i, ring->ring[i]); +		if (rptr == i) +			seq_puts(m, " *"); +		if (rptr_next == i) +			seq_puts(m, " #"); +		seq_puts(m, "\n"); +		i = (i + 1) & ring->ptr_mask;  	}  	return 0;  } @@ -854,6 +777,8 @@ static int cayman_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX;  static int radeon_dma1_index = R600_RING_TYPE_DMA_INDEX;  static int radeon_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX;  static int r600_uvd_index = R600_RING_TYPE_UVD_INDEX; +static int si_vce1_index = TN_RING_TYPE_VCE1_INDEX; +static int si_vce2_index = TN_RING_TYPE_VCE2_INDEX;  static struct drm_info_list radeon_debugfs_ring_info_list[] = {  	{"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_gfx_index}, @@ -862,6 +787,8 @@ static struct drm_info_list radeon_debugfs_ring_info_list[] = {  	{"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_dma1_index},  	{"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_dma2_index},  	{"radeon_ring_uvd", radeon_debugfs_ring_info, 0, &r600_uvd_index}, +	{"radeon_ring_vce1", radeon_debugfs_ring_info, 0, &si_vce1_index}, +	{"radeon_ring_vce2", radeon_debugfs_ring_info, 0, &si_vce2_index},  };  static int radeon_debugfs_sa_info(struct seq_file *m, void *data) diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index f0bac68254b..adcf3e2f07d 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -312,7 +312,7 @@ static bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager,  int radeon_sa_bo_new(struct radeon_device *rdev,  		     struct radeon_sa_manager *sa_manager,  		     struct radeon_sa_bo **sa_bo, -		     unsigned size, unsigned align, bool block) +		     unsigned size, unsigned align)  {  	struct radeon_fence *fences[RADEON_NUM_RINGS];  	unsigned tries[RADEON_NUM_RINGS]; @@ -353,14 +353,11 @@ int radeon_sa_bo_new(struct radeon_device *rdev,  		r = radeon_fence_wait_any(rdev, fences, false);  		spin_lock(&sa_manager->wq.lock);  		/* if we have nothing to wait for block */ -		if (r == -ENOENT && block) { +		if (r == -ENOENT) {  			r = wait_event_interruptible_locked(  				sa_manager->wq,   				radeon_sa_event(sa_manager, size, align)  			); - -		} else if (r == -ENOENT) { -			r = -ENOMEM;  		}  	} while (!r); @@ -402,13 +399,15 @@ void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager,  	spin_lock(&sa_manager->wq.lock);  	list_for_each_entry(i, &sa_manager->olist, olist) { +		uint64_t soffset = i->soffset + sa_manager->gpu_addr; +		uint64_t eoffset = i->eoffset + sa_manager->gpu_addr;  		if (&i->olist == sa_manager->hole) {  			seq_printf(m, ">");  		} else {  			seq_printf(m, " ");  		} -		seq_printf(m, "[0x%08x 0x%08x] size %8d", -			   i->soffset, i->eoffset, i->eoffset - i->soffset); +		seq_printf(m, "[0x%010llx 0x%010llx] size %8lld", +			   soffset, eoffset, eoffset - soffset);  		if (i->fence) {  			seq_printf(m, " protected by 0x%016llx on ring %d",  				   i->fence->seq, i->fence->ring); diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index 8dcc20f53d7..dbd6bcde92d 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -29,19 +29,20 @@   */  #include <drm/drmP.h>  #include "radeon.h" - +#include "radeon_trace.h"  int radeon_semaphore_create(struct radeon_device *rdev,  			    struct radeon_semaphore **semaphore)  { -	int r; +	uint32_t *cpu_addr; +	int i, r;  	*semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);  	if (*semaphore == NULL) {  		return -ENOMEM;  	} -	r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, -			     &(*semaphore)->sa_bo, 8, 8, true); +	r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo, +			     8 * RADEON_NUM_SYNCS, 8);  	if (r) {  		kfree(*semaphore);  		*semaphore = NULL; @@ -49,55 +50,140 @@ int radeon_semaphore_create(struct radeon_device *rdev,  	}  	(*semaphore)->waiters = 0;  	(*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo); -	*((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0; + +	cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo); +	for (i = 0; i < RADEON_NUM_SYNCS; ++i) +		cpu_addr[i] = 0; + +	for (i = 0; i < RADEON_NUM_RINGS; ++i) +		(*semaphore)->sync_to[i] = NULL; +  	return 0;  } -void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring, +bool radeon_semaphore_emit_signal(struct radeon_device *rdev, int ridx,  			          struct radeon_semaphore *semaphore)  { -	--semaphore->waiters; -	radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, false); +	struct radeon_ring *ring = &rdev->ring[ridx]; + +	trace_radeon_semaphore_signale(ridx, semaphore); + +	if (radeon_semaphore_ring_emit(rdev, ridx, ring, semaphore, false)) { +		--semaphore->waiters; + +		/* for debugging lockup only, used by sysfs debug files */ +		ring->last_semaphore_signal_addr = semaphore->gpu_addr; +		return true; +	} +	return false;  } -void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring, +bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ridx,  			        struct radeon_semaphore *semaphore)  { -	++semaphore->waiters; -	radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, true); +	struct radeon_ring *ring = &rdev->ring[ridx]; + +	trace_radeon_semaphore_wait(ridx, semaphore); + +	if (radeon_semaphore_ring_emit(rdev, ridx, ring, semaphore, true)) { +		++semaphore->waiters; + +		/* for debugging lockup only, used by sysfs debug files */ +		ring->last_semaphore_wait_addr = semaphore->gpu_addr; +		return true; +	} +	return false;  } -/* caller must hold ring lock */ +/** + * radeon_semaphore_sync_to - use the semaphore to sync to a fence + * + * @semaphore: semaphore object to add fence to + * @fence: fence to sync to + * + * Sync to the fence using this semaphore object + */ +void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore, +			      struct radeon_fence *fence) +{ +        struct radeon_fence *other; + +        if (!fence) +                return; + +        other = semaphore->sync_to[fence->ring]; +        semaphore->sync_to[fence->ring] = radeon_fence_later(fence, other); +} + +/** + * radeon_semaphore_sync_rings - sync ring to all registered fences + * + * @rdev: radeon_device pointer + * @semaphore: semaphore object to use for sync + * @ring: ring that needs sync + * + * Ensure that all registered fences are signaled before letting + * the ring continue. The caller must hold the ring lock. + */  int radeon_semaphore_sync_rings(struct radeon_device *rdev,  				struct radeon_semaphore *semaphore, -				int signaler, int waiter) +				int ring)  { -	int r; +	unsigned count = 0; +	int i, r; -	/* no need to signal and wait on the same ring */ -	if (signaler == waiter) { -		return 0; -	} +        for (i = 0; i < RADEON_NUM_RINGS; ++i) { +		struct radeon_fence *fence = semaphore->sync_to[i]; -	/* prevent GPU deadlocks */ -	if (!rdev->ring[signaler].ready) { -		dev_err(rdev->dev, "Trying to sync to a disabled ring!"); -		return -EINVAL; -	} +		/* check if we really need to sync */ +                if (!radeon_fence_need_sync(fence, ring)) +			continue; -	r = radeon_ring_alloc(rdev, &rdev->ring[signaler], 8); -	if (r) { -		return r; -	} -	radeon_semaphore_emit_signal(rdev, signaler, semaphore); -	radeon_ring_commit(rdev, &rdev->ring[signaler]); +		/* prevent GPU deadlocks */ +		if (!rdev->ring[i].ready) { +			dev_err(rdev->dev, "Syncing to a disabled ring!"); +			return -EINVAL; +		} + +		if (++count > RADEON_NUM_SYNCS) { +			/* not enough room, wait manually */ +			r = radeon_fence_wait(fence, false); +			if (r) +				return r; +			continue; +		} -	/* we assume caller has already allocated space on waiters ring */ -	radeon_semaphore_emit_wait(rdev, waiter, semaphore); +		/* allocate enough space for sync command */ +		r = radeon_ring_alloc(rdev, &rdev->ring[i], 16); +		if (r) { +			return r; +		} -	/* for debugging lockup only, used by sysfs debug files */ -	rdev->ring[signaler].last_semaphore_signal_addr = semaphore->gpu_addr; -	rdev->ring[waiter].last_semaphore_wait_addr = semaphore->gpu_addr; +		/* emit the signal semaphore */ +		if (!radeon_semaphore_emit_signal(rdev, i, semaphore)) { +			/* signaling wasn't successful wait manually */ +			radeon_ring_undo(&rdev->ring[i]); +			r = radeon_fence_wait(fence, false); +			if (r) +				return r; +			continue; +		} + +		/* we assume caller has already allocated space on waiters ring */ +		if (!radeon_semaphore_emit_wait(rdev, ring, semaphore)) { +			/* waiting wasn't successful wait manually */ +			radeon_ring_undo(&rdev->ring[i]); +			r = radeon_fence_wait(fence, false); +			if (r) +				return r; +			continue; +		} + +		radeon_ring_commit(rdev, &rdev->ring[i]); +		radeon_fence_note_sync(fence, ring); + +		semaphore->gpu_addr += 8; +	}  	return 0;  } diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 4d20910899d..23bb64fd775 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -1810,7 +1810,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,  		}  		if (!buf) {  			DRM_DEBUG("EAGAIN\n"); -			if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image))) +			if (copy_to_user(tex->image, image, sizeof(*image)))  				return -EFAULT;  			return -EAGAIN;  		} @@ -1823,7 +1823,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,  #define RADEON_COPY_MT(_buf, _data, _width) \  	do { \ -		if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\ +		if (copy_from_user(_buf, _data, (_width))) {\  			DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \  			return -EFAULT; \  		} \ @@ -2168,7 +2168,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *  	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)  		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; -	if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes, +	if (copy_from_user(&depth_boxes, clear->depth_boxes,  			       sarea_priv->nbox * sizeof(depth_boxes[0])))  		return -EFAULT; @@ -2436,7 +2436,7 @@ static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file  		return -EINVAL;  	} -	if (DRM_COPY_FROM_USER(&image, +	if (copy_from_user(&image,  			       (drm_radeon_tex_image_t __user *) tex->image,  			       sizeof(image)))  		return -EFAULT; @@ -2460,7 +2460,7 @@ static int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file  	LOCK_TEST_WITH_RETURN(dev, file_priv); -	if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32))) +	if (copy_from_user(&mask, stipple->mask, 32 * sizeof(u32)))  		return -EFAULT;  	RING_SPACE_TEST_WITH_RETURN(dev_priv); @@ -2585,13 +2585,13 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file  		drm_radeon_prim_t prim;  		drm_radeon_tcl_prim_t tclprim; -		if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim))) +		if (copy_from_user(&prim, &vertex->prim[i], sizeof(prim)))  			return -EFAULT;  		if (prim.stateidx != laststate) {  			drm_radeon_state_t state; -			if (DRM_COPY_FROM_USER(&state, +			if (copy_from_user(&state,  					       &vertex->state[prim.stateidx],  					       sizeof(state)))  				return -EFAULT; @@ -2799,7 +2799,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,  	do {  		if (i < cmdbuf->nbox) { -			if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box))) +			if (copy_from_user(&box, &boxes[i], sizeof(box)))  				return -EFAULT;  			/* FIXME The second and subsequent times round  			 * this loop, send a WAIT_UNTIL_3D_IDLE before @@ -3054,7 +3054,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil  		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)  			value = 0;  		else -			value = drm_dev_to_irq(dev); +			value = dev->pdev->irq;  		break;  	case RADEON_PARAM_GART_BASE:  		value = dev_priv->gart_vm_start; @@ -3116,7 +3116,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil  		return -EINVAL;  	} -	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { +	if (copy_to_user(param->value, &value, sizeof(int))) {  		DRM_ERROR("copy_to_user\n");  		return -EFAULT;  	} @@ -3258,4 +3258,4 @@ struct drm_ioctl_desc radeon_ioctls[] = {  	DRM_IOCTL_DEF_DRV(RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH)  }; -int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); +int radeon_max_ioctl = ARRAY_SIZE(radeon_ioctls); diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index f4d6bcee900..3a13e0d1055 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -36,8 +36,8 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)  	struct radeon_bo *vram_obj = NULL;  	struct radeon_bo **gtt_obj = NULL;  	uint64_t gtt_addr, vram_addr; -	unsigned i, n, size; -	int r, ring; +	unsigned n, size; +	int i, r, ring;  	switch (flag) {  	case RADEON_TEST_COPY_DMA: @@ -257,20 +257,36 @@ static int radeon_test_create_and_emit_fence(struct radeon_device *rdev,  					     struct radeon_ring *ring,  					     struct radeon_fence **fence)  { +	uint32_t handle = ring->idx ^ 0xdeafbeef;  	int r;  	if (ring->idx == R600_RING_TYPE_UVD_INDEX) { -		r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL); +		r = radeon_uvd_get_create_msg(rdev, ring->idx, handle, NULL);  		if (r) {  			DRM_ERROR("Failed to get dummy create msg\n");  			return r;  		} -		r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, fence); +		r = radeon_uvd_get_destroy_msg(rdev, ring->idx, handle, fence);  		if (r) {  			DRM_ERROR("Failed to get dummy destroy msg\n");  			return r;  		} + +	} else if (ring->idx == TN_RING_TYPE_VCE1_INDEX || +		   ring->idx == TN_RING_TYPE_VCE2_INDEX) { +		r = radeon_vce_get_create_msg(rdev, ring->idx, handle, NULL); +		if (r) { +			DRM_ERROR("Failed to get dummy create msg\n"); +			return r; +		} + +		r = radeon_vce_get_destroy_msg(rdev, ring->idx, handle, fence); +		if (r) { +			DRM_ERROR("Failed to get dummy destroy msg\n"); +			return r; +		} +  	} else {  		r = radeon_ring_lock(rdev, ring, 64);  		if (r) { @@ -486,6 +502,16 @@ out_cleanup:  		printk(KERN_WARNING "Error while testing ring sync (%d).\n", r);  } +static bool radeon_test_sync_possible(struct radeon_ring *ringA, +				      struct radeon_ring *ringB) +{ +	if (ringA->idx == TN_RING_TYPE_VCE2_INDEX && +	    ringB->idx == TN_RING_TYPE_VCE1_INDEX) +		return false; + +	return true; +} +  void radeon_test_syncing(struct radeon_device *rdev)  {  	int i, j, k; @@ -500,6 +526,9 @@ void radeon_test_syncing(struct radeon_device *rdev)  			if (!ringB->ready)  				continue; +			if (!radeon_test_sync_possible(ringA, ringB)) +				continue; +  			DRM_INFO("Testing syncing between rings %d and %d...\n", i, j);  			radeon_test_ring_sync(rdev, ringA, ringB); @@ -511,6 +540,12 @@ void radeon_test_syncing(struct radeon_device *rdev)  				if (!ringC->ready)  					continue; +				if (!radeon_test_sync_possible(ringA, ringC)) +					continue; + +				if (!radeon_test_sync_possible(ringB, ringC)) +					continue; +  				DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, j, k);  				radeon_test_ring_sync2(rdev, ringA, ringB, ringC); diff --git a/drivers/gpu/drm/radeon/radeon_trace.h b/drivers/gpu/drm/radeon/radeon_trace.h index f7e36781596..f749f2c3bbd 100644 --- a/drivers/gpu/drm/radeon/radeon_trace.h +++ b/drivers/gpu/drm/radeon/radeon_trace.h @@ -47,44 +47,140 @@ TRACE_EVENT(radeon_cs,  		      __entry->fences)  ); +TRACE_EVENT(radeon_vm_grab_id, +	    TP_PROTO(unsigned vmid, int ring), +	    TP_ARGS(vmid, ring), +	    TP_STRUCT__entry( +			     __field(u32, vmid) +			     __field(u32, ring) +			     ), + +	    TP_fast_assign( +			   __entry->vmid = vmid; +			   __entry->ring = ring; +			   ), +	    TP_printk("vmid=%u, ring=%u", __entry->vmid, __entry->ring) +); + +TRACE_EVENT(radeon_vm_bo_update, +	    TP_PROTO(struct radeon_bo_va *bo_va), +	    TP_ARGS(bo_va), +	    TP_STRUCT__entry( +			     __field(u64, soffset) +			     __field(u64, eoffset) +			     __field(u32, flags) +			     ), + +	    TP_fast_assign( +			   __entry->soffset = bo_va->soffset; +			   __entry->eoffset = bo_va->eoffset; +			   __entry->flags = bo_va->flags; +			   ), +	    TP_printk("soffs=%010llx, eoffs=%010llx, flags=%08x", +		      __entry->soffset, __entry->eoffset, __entry->flags) +); + +TRACE_EVENT(radeon_vm_set_page, +	    TP_PROTO(uint64_t pe, uint64_t addr, unsigned count, +		     uint32_t incr, uint32_t flags), +	    TP_ARGS(pe, addr, count, incr, flags), +	    TP_STRUCT__entry( +			     __field(u64, pe) +			     __field(u64, addr) +			     __field(u32, count) +			     __field(u32, incr) +			     __field(u32, flags) +			     ), + +	    TP_fast_assign( +			   __entry->pe = pe; +			   __entry->addr = addr; +			   __entry->count = count; +			   __entry->incr = incr; +			   __entry->flags = flags; +			   ), +	    TP_printk("pe=%010Lx, addr=%010Lx, incr=%u, flags=%08x, count=%u", +		      __entry->pe, __entry->addr, __entry->incr, +		      __entry->flags, __entry->count) +); +  DECLARE_EVENT_CLASS(radeon_fence_request, -	    TP_PROTO(struct drm_device *dev, u32 seqno), +	    TP_PROTO(struct drm_device *dev, int ring, u32 seqno), -	    TP_ARGS(dev, seqno), +	    TP_ARGS(dev, ring, seqno),  	    TP_STRUCT__entry(  			     __field(u32, dev) +			     __field(int, ring)  			     __field(u32, seqno)  			     ),  	    TP_fast_assign(  			   __entry->dev = dev->primary->index; +			   __entry->ring = ring;  			   __entry->seqno = seqno;  			   ), -	    TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno) +	    TP_printk("dev=%u, ring=%d, seqno=%u", +		      __entry->dev, __entry->ring, __entry->seqno)  );  DEFINE_EVENT(radeon_fence_request, radeon_fence_emit, -	    TP_PROTO(struct drm_device *dev, u32 seqno), +	    TP_PROTO(struct drm_device *dev, int ring, u32 seqno), -	    TP_ARGS(dev, seqno) +	    TP_ARGS(dev, ring, seqno)  );  DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_begin, -	    TP_PROTO(struct drm_device *dev, u32 seqno), +	    TP_PROTO(struct drm_device *dev, int ring, u32 seqno), -	    TP_ARGS(dev, seqno) +	    TP_ARGS(dev, ring, seqno)  );  DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_end, -	    TP_PROTO(struct drm_device *dev, u32 seqno), +	    TP_PROTO(struct drm_device *dev, int ring, u32 seqno), + +	    TP_ARGS(dev, ring, seqno) +); + +DECLARE_EVENT_CLASS(radeon_semaphore_request, + +	    TP_PROTO(int ring, struct radeon_semaphore *sem), + +	    TP_ARGS(ring, sem), + +	    TP_STRUCT__entry( +			     __field(int, ring) +			     __field(signed, waiters) +			     __field(uint64_t, gpu_addr) +			     ), + +	    TP_fast_assign( +			   __entry->ring = ring; +			   __entry->waiters = sem->waiters; +			   __entry->gpu_addr = sem->gpu_addr; +			   ), + +	    TP_printk("ring=%u, waiters=%d, addr=%010Lx", __entry->ring, +		      __entry->waiters, __entry->gpu_addr) +); + +DEFINE_EVENT(radeon_semaphore_request, radeon_semaphore_signale, + +	    TP_PROTO(int ring, struct radeon_semaphore *sem), + +	    TP_ARGS(ring, sem) +); + +DEFINE_EVENT(radeon_semaphore_request, radeon_semaphore_wait, + +	    TP_PROTO(int ring, struct radeon_semaphore *sem), -	    TP_ARGS(dev, seqno) +	    TP_ARGS(ring, sem)  );  #endif diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 71245d6f34a..c8a8a5144ec 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -39,12 +39,14 @@  #include <linux/seq_file.h>  #include <linux/slab.h>  #include <linux/swiotlb.h> +#include <linux/debugfs.h>  #include "radeon_reg.h"  #include "radeon.h"  #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)  static int radeon_ttm_debugfs_init(struct radeon_device *rdev); +static void radeon_ttm_debugfs_fini(struct radeon_device *rdev);  static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)  { @@ -142,7 +144,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,  		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA;  #if __OS_HAS_AGP  		if (rdev->flags & RADEON_IS_AGP) { -			if (!(drm_core_has_AGP(rdev->ddev) && rdev->ddev->agp)) { +			if (!rdev->ddev->agp) {  				DRM_ERROR("AGP is not enabled for memory type %u\n",  					  (unsigned)type);  				return -EINVAL; @@ -404,8 +406,14 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,  	if (r) {  memcpy:  		r = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); +		if (r) { +			return r; +		}  	} -	return r; + +	/* update statistics */ +	atomic64_add((u64)bo->num_pages << PAGE_SHIFT, &rdev->num_bytes_moved); +	return 0;  }  static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) @@ -699,7 +707,9 @@ int radeon_ttm_init(struct radeon_device *rdev)  	/* No others user of address space so set it to 0 */  	r = ttm_bo_device_init(&rdev->mman.bdev,  			       rdev->mman.bo_global_ref.ref.object, -			       &radeon_bo_driver, DRM_FILE_PAGE_OFFSET, +			       &radeon_bo_driver, +			       rdev->ddev->anon_inode->i_mapping, +			       DRM_FILE_PAGE_OFFSET,  			       rdev->need_dma32);  	if (r) {  		DRM_ERROR("failed initializing buffer object driver(%d).\n", r); @@ -712,6 +722,9 @@ int radeon_ttm_init(struct radeon_device *rdev)  		DRM_ERROR("Failed initializing VRAM heap.\n");  		return r;  	} +	/* Change the size here instead of the init above so only lpfn is affected */ +	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); +  	r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,  			     RADEON_GEM_DOMAIN_VRAM,  			     NULL, &rdev->stollen_vga_memory); @@ -737,7 +750,6 @@ int radeon_ttm_init(struct radeon_device *rdev)  	}  	DRM_INFO("radeon: %uM of GTT memory ready.\n",  		 (unsigned)(rdev->mc.gtt_size / (1024 * 1024))); -	rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;  	r = radeon_ttm_debugfs_init(rdev);  	if (r) { @@ -753,6 +765,7 @@ void radeon_ttm_fini(struct radeon_device *rdev)  	if (!rdev->mman.initialized)  		return; +	radeon_ttm_debugfs_fini(rdev);  	if (rdev->stollen_vga_memory) {  		r = radeon_bo_reserve(rdev->stollen_vga_memory, false);  		if (r == 0) { @@ -832,16 +845,15 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma)  	return 0;  } - -#define RADEON_DEBUGFS_MEM_TYPES 2 -  #if defined(CONFIG_DEBUG_FS) +  static int radeon_mm_dump_table(struct seq_file *m, void *data)  {  	struct drm_info_node *node = (struct drm_info_node *)m->private; -	struct drm_mm *mm = (struct drm_mm *)node->info_ent->data; +	unsigned ttm_pl = *(int *)node->info_ent->data;  	struct drm_device *dev = node->minor->dev;  	struct radeon_device *rdev = dev->dev_private; +	struct drm_mm *mm = (struct drm_mm *)rdev->mman.bdev.man[ttm_pl].priv;  	int ret;  	struct ttm_bo_global *glob = rdev->mman.bdev.glob; @@ -850,46 +862,169 @@ static int radeon_mm_dump_table(struct seq_file *m, void *data)  	spin_unlock(&glob->lru_lock);  	return ret;  } + +static int ttm_pl_vram = TTM_PL_VRAM; +static int ttm_pl_tt = TTM_PL_TT; + +static struct drm_info_list radeon_ttm_debugfs_list[] = { +	{"radeon_vram_mm", radeon_mm_dump_table, 0, &ttm_pl_vram}, +	{"radeon_gtt_mm", radeon_mm_dump_table, 0, &ttm_pl_tt}, +	{"ttm_page_pool", ttm_page_alloc_debugfs, 0, NULL}, +#ifdef CONFIG_SWIOTLB +	{"ttm_dma_page_pool", ttm_dma_page_alloc_debugfs, 0, NULL}  #endif +}; -static int radeon_ttm_debugfs_init(struct radeon_device *rdev) +static int radeon_ttm_vram_open(struct inode *inode, struct file *filep)  { -#if defined(CONFIG_DEBUG_FS) -	static struct drm_info_list radeon_mem_types_list[RADEON_DEBUGFS_MEM_TYPES+2]; -	static char radeon_mem_types_names[RADEON_DEBUGFS_MEM_TYPES+2][32]; -	unsigned i; +	struct radeon_device *rdev = inode->i_private; +	i_size_write(inode, rdev->mc.mc_vram_size); +	filep->private_data = inode->i_private; +	return 0; +} -	for (i = 0; i < RADEON_DEBUGFS_MEM_TYPES; i++) { -		if (i == 0) -			sprintf(radeon_mem_types_names[i], "radeon_vram_mm"); -		else -			sprintf(radeon_mem_types_names[i], "radeon_gtt_mm"); -		radeon_mem_types_list[i].name = radeon_mem_types_names[i]; -		radeon_mem_types_list[i].show = &radeon_mm_dump_table; -		radeon_mem_types_list[i].driver_features = 0; -		if (i == 0) -			radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_VRAM].priv; -		else -			radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_TT].priv; +static ssize_t radeon_ttm_vram_read(struct file *f, char __user *buf, +				    size_t size, loff_t *pos) +{ +	struct radeon_device *rdev = f->private_data; +	ssize_t result = 0; +	int r; + +	if (size & 0x3 || *pos & 0x3) +		return -EINVAL; + +	while (size) { +		unsigned long flags; +		uint32_t value; + +		if (*pos >= rdev->mc.mc_vram_size) +			return result; + +		spin_lock_irqsave(&rdev->mmio_idx_lock, flags); +		WREG32(RADEON_MM_INDEX, ((uint32_t)*pos) | 0x80000000); +		if (rdev->family >= CHIP_CEDAR) +			WREG32(EVERGREEN_MM_INDEX_HI, *pos >> 31); +		value = RREG32(RADEON_MM_DATA); +		spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); + +		r = put_user(value, (uint32_t *)buf); +		if (r) +			return r; +		result += 4; +		buf += 4; +		*pos += 4; +		size -= 4;  	} -	/* Add ttm page pool to debugfs */ -	sprintf(radeon_mem_types_names[i], "ttm_page_pool"); -	radeon_mem_types_list[i].name = radeon_mem_types_names[i]; -	radeon_mem_types_list[i].show = &ttm_page_alloc_debugfs; -	radeon_mem_types_list[i].driver_features = 0; -	radeon_mem_types_list[i++].data = NULL; -#ifdef CONFIG_SWIOTLB -	if (swiotlb_nr_tbl()) { -		sprintf(radeon_mem_types_names[i], "ttm_dma_page_pool"); -		radeon_mem_types_list[i].name = radeon_mem_types_names[i]; -		radeon_mem_types_list[i].show = &ttm_dma_page_alloc_debugfs; -		radeon_mem_types_list[i].driver_features = 0; -		radeon_mem_types_list[i++].data = NULL; + +	return result; +} + +static const struct file_operations radeon_ttm_vram_fops = { +	.owner = THIS_MODULE, +	.open = radeon_ttm_vram_open, +	.read = radeon_ttm_vram_read, +	.llseek = default_llseek +}; + +static int radeon_ttm_gtt_open(struct inode *inode, struct file *filep) +{ +	struct radeon_device *rdev = inode->i_private; +	i_size_write(inode, rdev->mc.gtt_size); +	filep->private_data = inode->i_private; +	return 0; +} + +static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf, +				   size_t size, loff_t *pos) +{ +	struct radeon_device *rdev = f->private_data; +	ssize_t result = 0; +	int r; + +	while (size) { +		loff_t p = *pos / PAGE_SIZE; +		unsigned off = *pos & ~PAGE_MASK; +		size_t cur_size = min_t(size_t, size, PAGE_SIZE - off); +		struct page *page; +		void *ptr; + +		if (p >= rdev->gart.num_cpu_pages) +			return result; + +		page = rdev->gart.pages[p]; +		if (page) { +			ptr = kmap(page); +			ptr += off; + +			r = copy_to_user(buf, ptr, cur_size); +			kunmap(rdev->gart.pages[p]); +		} else +			r = clear_user(buf, cur_size); + +		if (r) +			return -EFAULT; + +		result += cur_size; +		buf += cur_size; +		*pos += cur_size; +		size -= cur_size;  	} + +	return result; +} + +static const struct file_operations radeon_ttm_gtt_fops = { +	.owner = THIS_MODULE, +	.open = radeon_ttm_gtt_open, +	.read = radeon_ttm_gtt_read, +	.llseek = default_llseek +}; +  #endif -	return radeon_debugfs_add_files(rdev, radeon_mem_types_list, i); +static int radeon_ttm_debugfs_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) +	unsigned count; + +	struct drm_minor *minor = rdev->ddev->primary; +	struct dentry *ent, *root = minor->debugfs_root; + +	ent = debugfs_create_file("radeon_vram", S_IFREG | S_IRUGO, root, +				  rdev, &radeon_ttm_vram_fops); +	if (IS_ERR(ent)) +		return PTR_ERR(ent); +	rdev->mman.vram = ent; + +	ent = debugfs_create_file("radeon_gtt", S_IFREG | S_IRUGO, root, +				  rdev, &radeon_ttm_gtt_fops); +	if (IS_ERR(ent)) +		return PTR_ERR(ent); +	rdev->mman.gtt = ent; + +	count = ARRAY_SIZE(radeon_ttm_debugfs_list); + +#ifdef CONFIG_SWIOTLB +	if (!swiotlb_nr_tbl()) +		--count;  #endif + +	return radeon_debugfs_add_files(rdev, radeon_ttm_debugfs_list, count); +#else +  	return 0; +#endif +} + +static void radeon_ttm_debugfs_fini(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + +	debugfs_remove(rdev->mman.vram); +	rdev->mman.vram = NULL; + +	debugfs_remove(rdev->mman.gtt); +	rdev->mman.gtt = NULL; +#endif  } diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h index 33858364fe8..4e7c3269b18 100644 --- a/drivers/gpu/drm/radeon/radeon_ucode.h +++ b/drivers/gpu/drm/radeon/radeon_ucode.h @@ -52,13 +52,20 @@  #define BONAIRE_RLC_UCODE_SIZE       2048  #define KB_RLC_UCODE_SIZE            2560  #define KV_RLC_UCODE_SIZE            2560 +#define ML_RLC_UCODE_SIZE            2560  /* MC */  #define BTC_MC_UCODE_SIZE            6024  #define CAYMAN_MC_UCODE_SIZE         6037  #define SI_MC_UCODE_SIZE             7769 +#define TAHITI_MC_UCODE_SIZE         7808 +#define PITCAIRN_MC_UCODE_SIZE       7775 +#define VERDE_MC_UCODE_SIZE          7875  #define OLAND_MC_UCODE_SIZE          7863 -#define CIK_MC_UCODE_SIZE            7866 +#define BONAIRE_MC_UCODE_SIZE        7866 +#define BONAIRE_MC2_UCODE_SIZE       7948 +#define HAWAII_MC_UCODE_SIZE         7933 +#define HAWAII_MC2_UCODE_SIZE        8091  /* SDMA */  #define CIK_SDMA_UCODE_SIZE          1050 @@ -143,4 +150,7 @@  #define BONAIRE_SMC_UCODE_START      0x20000  #define BONAIRE_SMC_UCODE_SIZE       0x1FDEC +#define HAWAII_SMC_UCODE_START       0x20000 +#define HAWAII_SMC_UCODE_SIZE        0x1FDEC +  #endif diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index a0f11856ddd..a4ad270e826 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -91,12 +91,15 @@ int radeon_uvd_init(struct radeon_device *rdev)  	case CHIP_VERDE:  	case CHIP_PITCAIRN:  	case CHIP_ARUBA: +	case CHIP_OLAND:  		fw_name = FIRMWARE_TAHITI;  		break;  	case CHIP_BONAIRE:  	case CHIP_KABINI:  	case CHIP_KAVERI: +	case CHIP_HAWAII: +	case CHIP_MULLINS:  		fw_name = FIRMWARE_BONAIRE;  		break; @@ -169,6 +172,8 @@ void radeon_uvd_fini(struct radeon_device *rdev)  	radeon_bo_unref(&rdev->uvd.vcpu_bo); +	radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]); +  	release_firmware(rdev->uvd_fw);  } @@ -240,6 +245,8 @@ void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)  		if (handle != 0 && rdev->uvd.filp[i] == filp) {  			struct radeon_fence *fence; +			radeon_uvd_note_usage(rdev); +  			r = radeon_uvd_get_destroy_msg(rdev,  				R600_RING_TYPE_UVD_INDEX, handle, &fence);  			if (r) { @@ -449,7 +456,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,  	}  	reloc = p->relocs_ptr[(idx / 4)]; -	start = reloc->lobj.gpu_offset; +	start = reloc->gpu_offset;  	end = start + radeon_bo_size(reloc->robj);  	start += offset; @@ -459,6 +466,10 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,  	cmd = radeon_get_ib_value(p, p->idx) >> 1;  	if (cmd < 0x4) { +		if (end <= start) { +			DRM_ERROR("invalid reloc offset %X!\n", offset); +			return -EINVAL; +		}  		if ((end - start) < buf_sizes[cmd]) {  			DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,  				  (unsigned)(end - start), buf_sizes[cmd]); @@ -470,13 +481,14 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,  		return -EINVAL;  	} -	if ((start >> 28) != (end >> 28)) { +	if ((start >> 28) != ((end - 1) >> 28)) {  		DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n",  			  start, end);  		return -EINVAL;  	} -	if (p->rdev->family < CHIP_PALM && (cmd == 0 || cmd == 0x3) && +	/* TODO: is this still necessary on NI+ ? */ +	if ((cmd == 0 || cmd == 0x3) &&  	    (start >> 28) != (p->rdev->uvd.gpu_addr >> 28)) {  		DRM_ERROR("msg/fb buffer %LX-%LX out of 256MB segment!\n",  			  start, end); @@ -619,7 +631,7 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,  	if (r)   		goto err; -	r = radeon_ib_get(rdev, ring, &ib, NULL, 16); +	r = radeon_ib_get(rdev, ring, &ib, NULL, 64);  	if (r)  		goto err; @@ -774,6 +786,8 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)  	if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) {  		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { +			radeon_uvd_count_handles(rdev, &rdev->pm.dpm.sd, +						 &rdev->pm.dpm.hd);  			radeon_dpm_enable_uvd(rdev, false);  		} else {  			radeon_set_uvd_clocks(rdev, 0, 0); @@ -798,7 +812,8 @@ void radeon_uvd_note_usage(struct radeon_device *rdev)  		    (rdev->pm.dpm.hd != hd)) {  			rdev->pm.dpm.sd = sd;  			rdev->pm.dpm.hd = hd; -			streams_changed = true; +			/* disable this for now */ +			/*streams_changed = true;*/  		}  	} diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c new file mode 100644 index 00000000000..aa21c31a846 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -0,0 +1,771 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * Authors: Christian König <christian.koenig@amd.com> + */ + +#include <linux/firmware.h> +#include <linux/module.h> +#include <drm/drmP.h> +#include <drm/drm.h> + +#include "radeon.h" +#include "radeon_asic.h" +#include "sid.h" + +/* 1 second timeout */ +#define VCE_IDLE_TIMEOUT_MS	1000 + +/* Firmware Names */ +#define FIRMWARE_BONAIRE	"radeon/BONAIRE_vce.bin" + +MODULE_FIRMWARE(FIRMWARE_BONAIRE); + +static void radeon_vce_idle_work_handler(struct work_struct *work); + +/** + * radeon_vce_init - allocate memory, load vce firmware + * + * @rdev: radeon_device pointer + * + * First step to get VCE online, allocate memory and load the firmware + */ +int radeon_vce_init(struct radeon_device *rdev) +{ +	static const char *fw_version = "[ATI LIB=VCEFW,"; +	static const char *fb_version = "[ATI LIB=VCEFWSTATS,"; +	unsigned long size; +	const char *fw_name, *c; +	uint8_t start, mid, end; +	int i, r; + +	INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); + +	switch (rdev->family) { +	case CHIP_BONAIRE: +	case CHIP_KAVERI: +	case CHIP_KABINI: +	case CHIP_HAWAII: +	case CHIP_MULLINS: +		fw_name = FIRMWARE_BONAIRE; +		break; + +	default: +		return -EINVAL; +	} + +	r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); +	if (r) { +		dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n", +			fw_name); +		return r; +	} + +	/* search for firmware version */ + +	size = rdev->vce_fw->size - strlen(fw_version) - 9; +	c = rdev->vce_fw->data; +	for (;size > 0; --size, ++c) +		if (strncmp(c, fw_version, strlen(fw_version)) == 0) +			break; + +	if (size == 0) +		return -EINVAL; + +	c += strlen(fw_version); +	if (sscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3) +		return -EINVAL; + +	/* search for feedback version */ + +	size = rdev->vce_fw->size - strlen(fb_version) - 3; +	c = rdev->vce_fw->data; +	for (;size > 0; --size, ++c) +		if (strncmp(c, fb_version, strlen(fb_version)) == 0) +			break; + +	if (size == 0) +		return -EINVAL; + +	c += strlen(fb_version); +	if (sscanf(c, "%2u]", &rdev->vce.fb_version) != 1) +		return -EINVAL; + +	DRM_INFO("Found VCE firmware/feedback version %hhd.%hhd.%hhd / %d!\n", +		 start, mid, end, rdev->vce.fb_version); + +	rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8); + +	/* we can only work with this fw version for now */ +	if (rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) +		return -EINVAL; + +	/* allocate firmware, stack and heap BO */ + +	size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) + +	       RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE; +	r = radeon_bo_create(rdev, size, PAGE_SIZE, true, +			     RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->vce.vcpu_bo); +	if (r) { +		dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); +		return r; +	} + +	r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); +	if (r) { +		radeon_bo_unref(&rdev->vce.vcpu_bo); +		dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); +		return r; +	} + +	r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, +			  &rdev->vce.gpu_addr); +	radeon_bo_unreserve(rdev->vce.vcpu_bo); +	if (r) { +		radeon_bo_unref(&rdev->vce.vcpu_bo); +		dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r); +		return r; +	} + +	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { +		atomic_set(&rdev->vce.handles[i], 0); +		rdev->vce.filp[i] = NULL; +        } + +	return 0; +} + +/** + * radeon_vce_fini - free memory + * + * @rdev: radeon_device pointer + * + * Last step on VCE teardown, free firmware memory + */ +void radeon_vce_fini(struct radeon_device *rdev) +{ +	if (rdev->vce.vcpu_bo == NULL) +		return; + +	radeon_bo_unref(&rdev->vce.vcpu_bo); + +	release_firmware(rdev->vce_fw); +} + +/** + * radeon_vce_suspend - unpin VCE fw memory + * + * @rdev: radeon_device pointer + * + */ +int radeon_vce_suspend(struct radeon_device *rdev) +{ +	int i; + +	if (rdev->vce.vcpu_bo == NULL) +		return 0; + +	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) +		if (atomic_read(&rdev->vce.handles[i])) +			break; + +	if (i == RADEON_MAX_VCE_HANDLES) +		return 0; + +	/* TODO: suspending running encoding sessions isn't supported */ +	return -EINVAL; +} + +/** + * radeon_vce_resume - pin VCE fw memory + * + * @rdev: radeon_device pointer + * + */ +int radeon_vce_resume(struct radeon_device *rdev) +{ +	void *cpu_addr; +	int r; + +	if (rdev->vce.vcpu_bo == NULL) +		return -EINVAL; + +	r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); +	if (r) { +		dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); +		return r; +	} + +	r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr); +	if (r) { +		radeon_bo_unreserve(rdev->vce.vcpu_bo); +		dev_err(rdev->dev, "(%d) VCE map failed\n", r); +		return r; +	} + +	memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size); + +	radeon_bo_kunmap(rdev->vce.vcpu_bo); + +	radeon_bo_unreserve(rdev->vce.vcpu_bo); + +	return 0; +} + +/** + * radeon_vce_idle_work_handler - power off VCE + * + * @work: pointer to work structure + * + * power of VCE when it's not used any more + */ +static void radeon_vce_idle_work_handler(struct work_struct *work) +{ +	struct radeon_device *rdev = +		container_of(work, struct radeon_device, vce.idle_work.work); + +	if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) && +	    (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) { +		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { +			radeon_dpm_enable_vce(rdev, false); +		} else { +			radeon_set_vce_clocks(rdev, 0, 0); +		} +	} else { +		schedule_delayed_work(&rdev->vce.idle_work, +				      msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); +	} +} + +/** + * radeon_vce_note_usage - power up VCE + * + * @rdev: radeon_device pointer + * + * Make sure VCE is powerd up when we want to use it + */ +void radeon_vce_note_usage(struct radeon_device *rdev) +{ +	bool streams_changed = false; +	bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work); +	set_clocks &= schedule_delayed_work(&rdev->vce.idle_work, +					    msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); + +	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { +		/* XXX figure out if the streams changed */ +		streams_changed = false; +	} + +	if (set_clocks || streams_changed) { +		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { +			radeon_dpm_enable_vce(rdev, true); +		} else { +			radeon_set_vce_clocks(rdev, 53300, 40000); +		} +	} +} + +/** + * radeon_vce_free_handles - free still open VCE handles + * + * @rdev: radeon_device pointer + * @filp: drm file pointer + * + * Close all VCE handles still open by this file pointer + */ +void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) +{ +	int i, r; +	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { +		uint32_t handle = atomic_read(&rdev->vce.handles[i]); +		if (!handle || rdev->vce.filp[i] != filp) +			continue; + +		radeon_vce_note_usage(rdev); + +		r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, +					       handle, NULL); +		if (r) +			DRM_ERROR("Error destroying VCE handle (%d)!\n", r); + +		rdev->vce.filp[i] = NULL; +		atomic_set(&rdev->vce.handles[i], 0); +	} +} + +/** + * radeon_vce_get_create_msg - generate a VCE create msg + * + * @rdev: radeon_device pointer + * @ring: ring we should submit the msg to + * @handle: VCE session handle to use + * @fence: optional fence to return + * + * Open up a stream for HW test + */ +int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, +			      uint32_t handle, struct radeon_fence **fence) +{ +	const unsigned ib_size_dw = 1024; +	struct radeon_ib ib; +	uint64_t dummy; +	int i, r; + +	r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); +	if (r) { +		DRM_ERROR("radeon: failed to get ib (%d).\n", r); +		return r; +	} + +	dummy = ib.gpu_addr + 1024; + +	/* stitch together an VCE create msg */ +	ib.length_dw = 0; +	ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ +	ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ +	ib.ptr[ib.length_dw++] = handle; + +	ib.ptr[ib.length_dw++] = 0x00000030; /* len */ +	ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */ +	ib.ptr[ib.length_dw++] = 0x00000000; +	ib.ptr[ib.length_dw++] = 0x00000042; +	ib.ptr[ib.length_dw++] = 0x0000000a; +	ib.ptr[ib.length_dw++] = 0x00000001; +	ib.ptr[ib.length_dw++] = 0x00000080; +	ib.ptr[ib.length_dw++] = 0x00000060; +	ib.ptr[ib.length_dw++] = 0x00000100; +	ib.ptr[ib.length_dw++] = 0x00000100; +	ib.ptr[ib.length_dw++] = 0x0000000c; +	ib.ptr[ib.length_dw++] = 0x00000000; + +	ib.ptr[ib.length_dw++] = 0x00000014; /* len */ +	ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ +	ib.ptr[ib.length_dw++] = upper_32_bits(dummy); +	ib.ptr[ib.length_dw++] = dummy; +	ib.ptr[ib.length_dw++] = 0x00000001; + +	for (i = ib.length_dw; i < ib_size_dw; ++i) +		ib.ptr[i] = 0x0; + +	r = radeon_ib_schedule(rdev, &ib, NULL); +	if (r) { +	        DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); +	} + +	if (fence) +		*fence = radeon_fence_ref(ib.fence); + +	radeon_ib_free(rdev, &ib); + +	return r; +} + +/** + * radeon_vce_get_destroy_msg - generate a VCE destroy msg + * + * @rdev: radeon_device pointer + * @ring: ring we should submit the msg to + * @handle: VCE session handle to use + * @fence: optional fence to return + * + * Close up a stream for HW test or if userspace failed to do so + */ +int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, +			       uint32_t handle, struct radeon_fence **fence) +{ +	const unsigned ib_size_dw = 1024; +	struct radeon_ib ib; +	uint64_t dummy; +	int i, r; + +	r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); +	if (r) { +		DRM_ERROR("radeon: failed to get ib (%d).\n", r); +		return r; +	} + +	dummy = ib.gpu_addr + 1024; + +	/* stitch together an VCE destroy msg */ +	ib.length_dw = 0; +	ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ +	ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ +	ib.ptr[ib.length_dw++] = handle; + +	ib.ptr[ib.length_dw++] = 0x00000014; /* len */ +	ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ +	ib.ptr[ib.length_dw++] = upper_32_bits(dummy); +	ib.ptr[ib.length_dw++] = dummy; +	ib.ptr[ib.length_dw++] = 0x00000001; + +	ib.ptr[ib.length_dw++] = 0x00000008; /* len */ +	ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */ + +	for (i = ib.length_dw; i < ib_size_dw; ++i) +		ib.ptr[i] = 0x0; + +	r = radeon_ib_schedule(rdev, &ib, NULL); +	if (r) { +	        DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); +	} + +	if (fence) +		*fence = radeon_fence_ref(ib.fence); + +	radeon_ib_free(rdev, &ib); + +	return r; +} + +/** + * radeon_vce_cs_reloc - command submission relocation + * + * @p: parser context + * @lo: address of lower dword + * @hi: address of higher dword + * @size: size of checker for relocation buffer + * + * Patch relocation inside command stream with real buffer address + */ +int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, +			unsigned size) +{ +	struct radeon_cs_chunk *relocs_chunk; +	struct radeon_cs_reloc *reloc; +	uint64_t start, end, offset; +	unsigned idx; + +	relocs_chunk = &p->chunks[p->chunk_relocs_idx]; +	offset = radeon_get_ib_value(p, lo); +	idx = radeon_get_ib_value(p, hi); + +	if (idx >= relocs_chunk->length_dw) { +		DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", +			  idx, relocs_chunk->length_dw); +		return -EINVAL; +	} + +	reloc = p->relocs_ptr[(idx / 4)]; +	start = reloc->gpu_offset; +	end = start + radeon_bo_size(reloc->robj); +	start += offset; + +	p->ib.ptr[lo] = start & 0xFFFFFFFF; +	p->ib.ptr[hi] = start >> 32; + +	if (end <= start) { +		DRM_ERROR("invalid reloc offset %llX!\n", offset); +		return -EINVAL; +	} +	if ((end - start) < size) { +		DRM_ERROR("buffer to small (%d / %d)!\n", +			(unsigned)(end - start), size); +		return -EINVAL; +	} + +	return 0; +} + +/** + * radeon_vce_validate_handle - validate stream handle + * + * @p: parser context + * @handle: handle to validate + * + * Validates the handle and return the found session index or -EINVAL + * we we don't have another free session index. + */ +int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle) +{ +	unsigned i; + +	/* validate the handle */ +	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { +		if (atomic_read(&p->rdev->vce.handles[i]) == handle) +			return i; +	} + +	/* handle not found try to alloc a new one */ +	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { +		if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { +			p->rdev->vce.filp[i] = p->filp; +			p->rdev->vce.img_size[i] = 0; +			return i; +		} +	} + +	DRM_ERROR("No more free VCE handles!\n"); +	return -EINVAL; +} + +/** + * radeon_vce_cs_parse - parse and validate the command stream + * + * @p: parser context + * + */ +int radeon_vce_cs_parse(struct radeon_cs_parser *p) +{ +	int session_idx = -1; +	bool destroyed = false; +	uint32_t tmp, handle = 0; +	uint32_t *size = &tmp; +	int i, r; + +	while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) { +		uint32_t len = radeon_get_ib_value(p, p->idx); +		uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); + +		if ((len < 8) || (len & 3)) { +			DRM_ERROR("invalid VCE command length (%d)!\n", len); +                	return -EINVAL; +		} + +		if (destroyed) { +			DRM_ERROR("No other command allowed after destroy!\n"); +			return -EINVAL; +		} + +		switch (cmd) { +		case 0x00000001: // session +			handle = radeon_get_ib_value(p, p->idx + 2); +			session_idx = radeon_vce_validate_handle(p, handle); +			if (session_idx < 0) +				return session_idx; +			size = &p->rdev->vce.img_size[session_idx]; +			break; + +		case 0x00000002: // task info +			break; + +		case 0x01000001: // create +			*size = radeon_get_ib_value(p, p->idx + 8) * +				radeon_get_ib_value(p, p->idx + 10) * +				8 * 3 / 2; +			break; + +		case 0x04000001: // config extension +		case 0x04000002: // pic control +		case 0x04000005: // rate control +		case 0x04000007: // motion estimation +		case 0x04000008: // rdo +			break; + +		case 0x03000001: // encode +			r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, +						*size); +			if (r) +				return r; + +			r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, +						*size / 3); +			if (r) +				return r; +			break; + +		case 0x02000001: // destroy +			destroyed = true; +			break; + +		case 0x05000001: // context buffer +			r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, +						*size * 2); +			if (r) +				return r; +			break; + +		case 0x05000004: // video bitstream buffer +			tmp = radeon_get_ib_value(p, p->idx + 4); +			r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, +						tmp); +			if (r) +				return r; +			break; + +		case 0x05000005: // feedback buffer +			r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, +						4096); +			if (r) +				return r; +			break; + +		default: +			DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); +			return -EINVAL; +		} + +		if (session_idx == -1) { +			DRM_ERROR("no session command at start of IB\n"); +			return -EINVAL; +		} + +		p->idx += len / 4; +	} + +	if (destroyed) { +		/* IB contains a destroy msg, free the handle */ +		for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) +			atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); +	} + +	return 0; +} + +/** + * radeon_vce_semaphore_emit - emit a semaphore command + * + * @rdev: radeon_device pointer + * @ring: engine to use + * @semaphore: address of semaphore + * @emit_wait: true=emit wait, false=emit signal + * + */ +bool radeon_vce_semaphore_emit(struct radeon_device *rdev, +			       struct radeon_ring *ring, +			       struct radeon_semaphore *semaphore, +			       bool emit_wait) +{ +	uint64_t addr = semaphore->gpu_addr; + +	radeon_ring_write(ring, VCE_CMD_SEMAPHORE); +	radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); +	radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); +	radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0)); +	if (!emit_wait) +		radeon_ring_write(ring, VCE_CMD_END); + +	return true; +} + +/** + * radeon_vce_ib_execute - execute indirect buffer + * + * @rdev: radeon_device pointer + * @ib: the IB to execute + * + */ +void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) +{ +	struct radeon_ring *ring = &rdev->ring[ib->ring]; +	radeon_ring_write(ring, VCE_CMD_IB); +	radeon_ring_write(ring, ib->gpu_addr); +	radeon_ring_write(ring, upper_32_bits(ib->gpu_addr)); +	radeon_ring_write(ring, ib->length_dw); +} + +/** + * radeon_vce_fence_emit - add a fence command to the ring + * + * @rdev: radeon_device pointer + * @fence: the fence + * + */ +void radeon_vce_fence_emit(struct radeon_device *rdev, +			   struct radeon_fence *fence) +{ +	struct radeon_ring *ring = &rdev->ring[fence->ring]; +	uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; + +	radeon_ring_write(ring, VCE_CMD_FENCE); +	radeon_ring_write(ring, addr); +	radeon_ring_write(ring, upper_32_bits(addr)); +	radeon_ring_write(ring, fence->seq); +	radeon_ring_write(ring, VCE_CMD_TRAP); +	radeon_ring_write(ring, VCE_CMD_END); +} + +/** + * radeon_vce_ring_test - test if VCE ring is working + * + * @rdev: radeon_device pointer + * @ring: the engine to test on + * + */ +int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) +{ +	uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); +	unsigned i; +	int r; + +	r = radeon_ring_lock(rdev, ring, 16); +	if (r) { +		DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", +			  ring->idx, r); +		return r; +	} +	radeon_ring_write(ring, VCE_CMD_END); +	radeon_ring_unlock_commit(rdev, ring); + +	for (i = 0; i < rdev->usec_timeout; i++) { +	        if (vce_v1_0_get_rptr(rdev, ring) != rptr) +	                break; +	        DRM_UDELAY(1); +	} + +	if (i < rdev->usec_timeout) { +	        DRM_INFO("ring test on %d succeeded in %d usecs\n", +	                 ring->idx, i); +	} else { +	        DRM_ERROR("radeon: ring %d test failed\n", +	                  ring->idx); +	        r = -ETIMEDOUT; +	} + +	return r; +} + +/** + * radeon_vce_ib_test - test if VCE IBs are working + * + * @rdev: radeon_device pointer + * @ring: the engine to test on + * + */ +int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) +{ +	struct radeon_fence *fence = NULL; +	int r; + +	r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); +	if (r) { +		DRM_ERROR("radeon: failed to get create msg (%d).\n", r); +		goto error; +	} + +	r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); +	if (r) { +		DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); +		goto error; +	} + +	r = radeon_fence_wait(fence, false); +	if (r) { +		DRM_ERROR("radeon: fence wait failed (%d).\n", r); +	} else { +	        DRM_INFO("ib test on ring %d succeeded\n", ring->idx); +	} +error: +	radeon_fence_unref(&fence); +	return r; +} diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c new file mode 100644 index 00000000000..725d3669014 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -0,0 +1,1089 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * 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: Dave Airlie + *          Alex Deucher + *          Jerome Glisse + */ +#include <drm/drmP.h> +#include <drm/radeon_drm.h> +#include "radeon.h" +#include "radeon_trace.h" + +/* + * GPUVM + * GPUVM is similar to the legacy gart on older asics, however + * rather than there being a single global gart table + * for the entire GPU, there are multiple VM page tables active + * at any given time.  The VM page tables can contain a mix + * vram pages and system memory pages and system memory pages + * can be mapped as snooped (cached system pages) or unsnooped + * (uncached system pages). + * Each VM has an ID associated with it and there is a page table + * associated with each VMID.  When execting a command buffer, + * the kernel tells the the ring what VMID to use for that command + * buffer.  VMIDs are allocated dynamically as commands are submitted. + * The userspace drivers maintain their own address space and the kernel + * sets up their pages tables accordingly when they submit their + * command buffers and a VMID is assigned. + * Cayman/Trinity support up to 8 active VMs at any given time; + * SI supports 16. + */ + +/** + * radeon_vm_num_pde - return the number of page directory entries + * + * @rdev: radeon_device pointer + * + * Calculate the number of page directory entries (cayman+). + */ +static unsigned radeon_vm_num_pdes(struct radeon_device *rdev) +{ +	return rdev->vm_manager.max_pfn >> radeon_vm_block_size; +} + +/** + * radeon_vm_directory_size - returns the size of the page directory in bytes + * + * @rdev: radeon_device pointer + * + * Calculate the size of the page directory in bytes (cayman+). + */ +static unsigned radeon_vm_directory_size(struct radeon_device *rdev) +{ +	return RADEON_GPU_PAGE_ALIGN(radeon_vm_num_pdes(rdev) * 8); +} + +/** + * radeon_vm_manager_init - init the vm manager + * + * @rdev: radeon_device pointer + * + * Init the vm manager (cayman+). + * Returns 0 for success, error for failure. + */ +int radeon_vm_manager_init(struct radeon_device *rdev) +{ +	int r; + +	if (!rdev->vm_manager.enabled) { +		r = radeon_asic_vm_init(rdev); +		if (r) +			return r; + +		rdev->vm_manager.enabled = true; +	} +	return 0; +} + +/** + * radeon_vm_manager_fini - tear down the vm manager + * + * @rdev: radeon_device pointer + * + * Tear down the VM manager (cayman+). + */ +void radeon_vm_manager_fini(struct radeon_device *rdev) +{ +	int i; + +	if (!rdev->vm_manager.enabled) +		return; + +	for (i = 0; i < RADEON_NUM_VM; ++i) +		radeon_fence_unref(&rdev->vm_manager.active[i]); +	radeon_asic_vm_fini(rdev); +	rdev->vm_manager.enabled = false; +} + +/** + * radeon_vm_get_bos - add the vm BOs to a validation list + * + * @vm: vm providing the BOs + * @head: head of validation list + * + * Add the page directory to the list of BOs to + * validate for command submission (cayman+). + */ +struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, +					  struct radeon_vm *vm, +					  struct list_head *head) +{ +	struct radeon_cs_reloc *list; +	unsigned i, idx; + +	list = kmalloc_array(vm->max_pde_used + 2, +			     sizeof(struct radeon_cs_reloc), GFP_KERNEL); +	if (!list) +		return NULL; + +	/* add the vm page table to the list */ +	list[0].gobj = NULL; +	list[0].robj = vm->page_directory; +	list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM; +	list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM; +	list[0].tv.bo = &vm->page_directory->tbo; +	list[0].tiling_flags = 0; +	list[0].handle = 0; +	list_add(&list[0].tv.head, head); + +	for (i = 0, idx = 1; i <= vm->max_pde_used; i++) { +		if (!vm->page_tables[i].bo) +			continue; + +		list[idx].gobj = NULL; +		list[idx].robj = vm->page_tables[i].bo; +		list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM; +		list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM; +		list[idx].tv.bo = &list[idx].robj->tbo; +		list[idx].tiling_flags = 0; +		list[idx].handle = 0; +		list_add(&list[idx++].tv.head, head); +	} + +	return list; +} + +/** + * radeon_vm_grab_id - allocate the next free VMID + * + * @rdev: radeon_device pointer + * @vm: vm to allocate id for + * @ring: ring we want to submit job to + * + * Allocate an id for the vm (cayman+). + * Returns the fence we need to sync to (if any). + * + * Global and local mutex must be locked! + */ +struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, +				       struct radeon_vm *vm, int ring) +{ +	struct radeon_fence *best[RADEON_NUM_RINGS] = {}; +	unsigned choices[2] = {}; +	unsigned i; + +	/* check if the id is still valid */ +	if (vm->last_id_use && vm->last_id_use == rdev->vm_manager.active[vm->id]) +		return NULL; + +	/* we definately need to flush */ +	radeon_fence_unref(&vm->last_flush); + +	/* skip over VMID 0, since it is the system VM */ +	for (i = 1; i < rdev->vm_manager.nvm; ++i) { +		struct radeon_fence *fence = rdev->vm_manager.active[i]; + +		if (fence == NULL) { +			/* found a free one */ +			vm->id = i; +			trace_radeon_vm_grab_id(vm->id, ring); +			return NULL; +		} + +		if (radeon_fence_is_earlier(fence, best[fence->ring])) { +			best[fence->ring] = fence; +			choices[fence->ring == ring ? 0 : 1] = i; +		} +	} + +	for (i = 0; i < 2; ++i) { +		if (choices[i]) { +			vm->id = choices[i]; +			trace_radeon_vm_grab_id(vm->id, ring); +			return rdev->vm_manager.active[choices[i]]; +		} +	} + +	/* should never happen */ +	BUG(); +	return NULL; +} + +/** + * radeon_vm_flush - hardware flush the vm + * + * @rdev: radeon_device pointer + * @vm: vm we want to flush + * @ring: ring to use for flush + * + * Flush the vm (cayman+). + * + * Global and local mutex must be locked! + */ +void radeon_vm_flush(struct radeon_device *rdev, +		     struct radeon_vm *vm, +		     int ring) +{ +	uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory); + +	/* if we can't remember our last VM flush then flush now! */ +	/* XXX figure out why we have to flush all the time */ +	if (!vm->last_flush || true || pd_addr != vm->pd_gpu_addr) { +		vm->pd_gpu_addr = pd_addr; +		radeon_ring_vm_flush(rdev, ring, vm); +	} +} + +/** + * radeon_vm_fence - remember fence for vm + * + * @rdev: radeon_device pointer + * @vm: vm we want to fence + * @fence: fence to remember + * + * Fence the vm (cayman+). + * Set the fence used to protect page table and id. + * + * Global and local mutex must be locked! + */ +void radeon_vm_fence(struct radeon_device *rdev, +		     struct radeon_vm *vm, +		     struct radeon_fence *fence) +{ +	radeon_fence_unref(&vm->fence); +	vm->fence = radeon_fence_ref(fence); + +	radeon_fence_unref(&rdev->vm_manager.active[vm->id]); +	rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence); + +	radeon_fence_unref(&vm->last_id_use); +	vm->last_id_use = radeon_fence_ref(fence); + +        /* we just flushed the VM, remember that */ +        if (!vm->last_flush) +                vm->last_flush = radeon_fence_ref(fence); +} + +/** + * radeon_vm_bo_find - find the bo_va for a specific vm & bo + * + * @vm: requested vm + * @bo: requested buffer object + * + * Find @bo inside the requested vm (cayman+). + * Search inside the @bos vm list for the requested vm + * Returns the found bo_va or NULL if none is found + * + * Object has to be reserved! + */ +struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, +				       struct radeon_bo *bo) +{ +	struct radeon_bo_va *bo_va; + +	list_for_each_entry(bo_va, &bo->va, bo_list) { +		if (bo_va->vm == vm) { +			return bo_va; +		} +	} +	return NULL; +} + +/** + * radeon_vm_bo_add - add a bo to a specific vm + * + * @rdev: radeon_device pointer + * @vm: requested vm + * @bo: radeon buffer object + * + * Add @bo into the requested vm (cayman+). + * Add @bo to the list of bos associated with the vm + * Returns newly added bo_va or NULL for failure + * + * Object has to be reserved! + */ +struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, +				      struct radeon_vm *vm, +				      struct radeon_bo *bo) +{ +	struct radeon_bo_va *bo_va; + +	bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); +	if (bo_va == NULL) { +		return NULL; +	} +	bo_va->vm = vm; +	bo_va->bo = bo; +	bo_va->soffset = 0; +	bo_va->eoffset = 0; +	bo_va->flags = 0; +	bo_va->valid = false; +	bo_va->ref_count = 1; +	INIT_LIST_HEAD(&bo_va->bo_list); +	INIT_LIST_HEAD(&bo_va->vm_list); +	INIT_LIST_HEAD(&bo_va->vm_status); + +	mutex_lock(&vm->mutex); +	list_add(&bo_va->vm_list, &vm->va); +	list_add_tail(&bo_va->bo_list, &bo->va); +	mutex_unlock(&vm->mutex); + +	return bo_va; +} + +/** + * radeon_vm_clear_bo - initially clear the page dir/table + * + * @rdev: radeon_device pointer + * @bo: bo to clear + */ +static int radeon_vm_clear_bo(struct radeon_device *rdev, +			      struct radeon_bo *bo) +{ +        struct ttm_validate_buffer tv; +        struct ww_acquire_ctx ticket; +        struct list_head head; +	struct radeon_ib ib; +	unsigned entries; +	uint64_t addr; +	int r; + +        memset(&tv, 0, sizeof(tv)); +        tv.bo = &bo->tbo; + +        INIT_LIST_HEAD(&head); +        list_add(&tv.head, &head); + +        r = ttm_eu_reserve_buffers(&ticket, &head); +        if (r) +		return r; + +        r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); +        if (r) +                goto error; + +	addr = radeon_bo_gpu_offset(bo); +	entries = radeon_bo_size(bo) / 8; + +	r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, +			  NULL, entries * 2 + 64); +	if (r) +                goto error; + +	ib.length_dw = 0; + +	radeon_asic_vm_set_page(rdev, &ib, addr, 0, entries, 0, 0); + +	r = radeon_ib_schedule(rdev, &ib, NULL); +	if (r) +                goto error; + +	ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence); +	radeon_ib_free(rdev, &ib); + +	return 0; + +error: +	ttm_eu_backoff_reservation(&ticket, &head); +	return r; +} + +/** + * radeon_vm_bo_set_addr - set bos virtual address inside a vm + * + * @rdev: radeon_device pointer + * @bo_va: bo_va to store the address + * @soffset: requested offset of the buffer in the VM address space + * @flags: attributes of pages (read/write/valid/etc.) + * + * Set offset of @bo_va (cayman+). + * Validate and set the offset requested within the vm address space. + * Returns 0 for success, error for failure. + * + * Object has to be reserved! + */ +int radeon_vm_bo_set_addr(struct radeon_device *rdev, +			  struct radeon_bo_va *bo_va, +			  uint64_t soffset, +			  uint32_t flags) +{ +	uint64_t size = radeon_bo_size(bo_va->bo); +	uint64_t eoffset, last_offset = 0; +	struct radeon_vm *vm = bo_va->vm; +	struct radeon_bo_va *tmp; +	struct list_head *head; +	unsigned last_pfn, pt_idx; +	int r; + +	if (soffset) { +		/* make sure object fit at this offset */ +		eoffset = soffset + size; +		if (soffset >= eoffset) { +			return -EINVAL; +		} + +		last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; +		if (last_pfn > rdev->vm_manager.max_pfn) { +			dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", +				last_pfn, rdev->vm_manager.max_pfn); +			return -EINVAL; +		} + +	} else { +		eoffset = last_pfn = 0; +	} + +	mutex_lock(&vm->mutex); +	head = &vm->va; +	last_offset = 0; +	list_for_each_entry(tmp, &vm->va, vm_list) { +		if (bo_va == tmp) { +			/* skip over currently modified bo */ +			continue; +		} + +		if (soffset >= last_offset && eoffset <= tmp->soffset) { +			/* bo can be added before this one */ +			break; +		} +		if (eoffset > tmp->soffset && soffset < tmp->eoffset) { +			/* bo and tmp overlap, invalid offset */ +			dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", +				bo_va->bo, (unsigned)bo_va->soffset, tmp->bo, +				(unsigned)tmp->soffset, (unsigned)tmp->eoffset); +			mutex_unlock(&vm->mutex); +			return -EINVAL; +		} +		last_offset = tmp->eoffset; +		head = &tmp->vm_list; +	} + +	if (bo_va->soffset) { +		/* add a clone of the bo_va to clear the old address */ +		tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); +		if (!tmp) { +			mutex_unlock(&vm->mutex); +			return -ENOMEM; +		} +		tmp->soffset = bo_va->soffset; +		tmp->eoffset = bo_va->eoffset; +		tmp->vm = vm; +		list_add(&tmp->vm_status, &vm->freed); +	} + +	bo_va->soffset = soffset; +	bo_va->eoffset = eoffset; +	bo_va->flags = flags; +	bo_va->valid = false; +	list_move(&bo_va->vm_list, head); + +	soffset = (soffset / RADEON_GPU_PAGE_SIZE) >> radeon_vm_block_size; +	eoffset = (eoffset / RADEON_GPU_PAGE_SIZE) >> radeon_vm_block_size; + +	BUG_ON(eoffset >= radeon_vm_num_pdes(rdev)); + +	if (eoffset > vm->max_pde_used) +		vm->max_pde_used = eoffset; + +	radeon_bo_unreserve(bo_va->bo); + +	/* walk over the address space and allocate the page tables */ +	for (pt_idx = soffset; pt_idx <= eoffset; ++pt_idx) { +		struct radeon_bo *pt; + +		if (vm->page_tables[pt_idx].bo) +			continue; + +		/* drop mutex to allocate and clear page table */ +		mutex_unlock(&vm->mutex); + +		r = radeon_bo_create(rdev, RADEON_VM_PTE_COUNT * 8, +				     RADEON_GPU_PAGE_SIZE, true, +				     RADEON_GEM_DOMAIN_VRAM, NULL, &pt); +		if (r) +			return r; + +		r = radeon_vm_clear_bo(rdev, pt); +		if (r) { +			radeon_bo_unref(&pt); +			radeon_bo_reserve(bo_va->bo, false); +			return r; +		} + +		/* aquire mutex again */ +		mutex_lock(&vm->mutex); +		if (vm->page_tables[pt_idx].bo) { +			/* someone else allocated the pt in the meantime */ +			mutex_unlock(&vm->mutex); +			radeon_bo_unref(&pt); +			mutex_lock(&vm->mutex); +			continue; +		} + +		vm->page_tables[pt_idx].addr = 0; +		vm->page_tables[pt_idx].bo = pt; +	} + +	mutex_unlock(&vm->mutex); +	return radeon_bo_reserve(bo_va->bo, false); +} + +/** + * radeon_vm_map_gart - get the physical address of a gart page + * + * @rdev: radeon_device pointer + * @addr: the unmapped addr + * + * Look up the physical address of the page that the pte resolves + * to (cayman+). + * Returns the physical address of the page. + */ +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); + +	return result; +} + +/** + * radeon_vm_page_flags - translate page flags to what the hw uses + * + * @flags: flags comming from userspace + * + * Translate the flags the userspace ABI uses to hw flags. + */ +static uint32_t radeon_vm_page_flags(uint32_t flags) +{ +        uint32_t hw_flags = 0; +        hw_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_PTE_VALID : 0; +        hw_flags |= (flags & RADEON_VM_PAGE_READABLE) ? R600_PTE_READABLE : 0; +        hw_flags |= (flags & RADEON_VM_PAGE_WRITEABLE) ? R600_PTE_WRITEABLE : 0; +        if (flags & RADEON_VM_PAGE_SYSTEM) { +                hw_flags |= R600_PTE_SYSTEM; +                hw_flags |= (flags & RADEON_VM_PAGE_SNOOPED) ? R600_PTE_SNOOPED : 0; +        } +        return hw_flags; +} + +/** + * radeon_vm_update_pdes - make sure that page directory is valid + * + * @rdev: radeon_device pointer + * @vm: requested vm + * @start: start of GPU address range + * @end: end of GPU address range + * + * Allocates new page tables if necessary + * and updates the page directory (cayman+). + * Returns 0 for success, error for failure. + * + * Global and local mutex must be locked! + */ +int radeon_vm_update_page_directory(struct radeon_device *rdev, +				    struct radeon_vm *vm) +{ +	struct radeon_bo *pd = vm->page_directory; +	uint64_t pd_addr = radeon_bo_gpu_offset(pd); +	uint32_t incr = RADEON_VM_PTE_COUNT * 8; +	uint64_t last_pde = ~0, last_pt = ~0; +	unsigned count = 0, pt_idx, ndw; +	struct radeon_ib ib; +	int r; + +	/* padding, etc. */ +	ndw = 64; + +	/* assume the worst case */ +	ndw += vm->max_pde_used * 16; + +	/* update too big for an IB */ +	if (ndw > 0xfffff) +		return -ENOMEM; + +	r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, ndw * 4); +	if (r) +		return r; +	ib.length_dw = 0; + +	/* walk over the address space and update the page directory */ +	for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) { +		struct radeon_bo *bo = vm->page_tables[pt_idx].bo; +		uint64_t pde, pt; + +		if (bo == NULL) +			continue; + +		pt = radeon_bo_gpu_offset(bo); +		if (vm->page_tables[pt_idx].addr == pt) +			continue; +		vm->page_tables[pt_idx].addr = pt; + +		pde = pd_addr + pt_idx * 8; +		if (((last_pde + 8 * count) != pde) || +		    ((last_pt + incr * count) != pt)) { + +			if (count) { +				radeon_asic_vm_set_page(rdev, &ib, last_pde, +							last_pt, count, incr, +							R600_PTE_VALID); +			} + +			count = 1; +			last_pde = pde; +			last_pt = pt; +		} else { +			++count; +		} +	} + +	if (count) +		radeon_asic_vm_set_page(rdev, &ib, last_pde, last_pt, count, +					incr, R600_PTE_VALID); + +	if (ib.length_dw != 0) { +		radeon_semaphore_sync_to(ib.semaphore, pd->tbo.sync_obj); +		radeon_semaphore_sync_to(ib.semaphore, vm->last_id_use); +		r = radeon_ib_schedule(rdev, &ib, NULL); +		if (r) { +			radeon_ib_free(rdev, &ib); +			return r; +		} +		radeon_fence_unref(&vm->fence); +		vm->fence = radeon_fence_ref(ib.fence); +		radeon_fence_unref(&vm->last_flush); +	} +	radeon_ib_free(rdev, &ib); + +	return 0; +} + +/** + * radeon_vm_frag_ptes - add fragment information to PTEs + * + * @rdev: radeon_device pointer + * @ib: IB for the update + * @pe_start: first PTE to handle + * @pe_end: last PTE to handle + * @addr: addr those PTEs should point to + * @flags: hw mapping flags + * + * Global and local mutex must be locked! + */ +static void radeon_vm_frag_ptes(struct radeon_device *rdev, +				struct radeon_ib *ib, +				uint64_t pe_start, uint64_t pe_end, +				uint64_t addr, uint32_t flags) +{ +	/** +	 * The MC L1 TLB supports variable sized pages, based on a fragment +	 * field in the PTE. When this field is set to a non-zero value, page +	 * granularity is increased from 4KB to (1 << (12 + frag)). The PTE +	 * flags are considered valid for all PTEs within the fragment range +	 * and corresponding mappings are assumed to be physically contiguous. +	 * +	 * The L1 TLB can store a single PTE for the whole fragment, +	 * significantly increasing the space available for translation +	 * caching. This leads to large improvements in throughput when the +	 * TLB is under pressure. +	 * +	 * The L2 TLB distributes small and large fragments into two +	 * asymmetric partitions. The large fragment cache is significantly +	 * larger. Thus, we try to use large fragments wherever possible. +	 * Userspace can support this by aligning virtual base address and +	 * allocation size to the fragment size. +	 */ + +	/* NI is optimized for 256KB fragments, SI and newer for 64KB */ +	uint64_t frag_flags = rdev->family == CHIP_CAYMAN ? +			R600_PTE_FRAG_256KB : R600_PTE_FRAG_64KB; +	uint64_t frag_align = rdev->family == CHIP_CAYMAN ? 0x200 : 0x80; + +	uint64_t frag_start = ALIGN(pe_start, frag_align); +	uint64_t frag_end = pe_end & ~(frag_align - 1); + +	unsigned count; + +	/* system pages are non continuously */ +	if ((flags & R600_PTE_SYSTEM) || !(flags & R600_PTE_VALID) || +	    (frag_start >= frag_end)) { + +		count = (pe_end - pe_start) / 8; +		radeon_asic_vm_set_page(rdev, ib, pe_start, addr, count, +					RADEON_GPU_PAGE_SIZE, flags); +		return; +	} + +	/* handle the 4K area at the beginning */ +	if (pe_start != frag_start) { +		count = (frag_start - pe_start) / 8; +		radeon_asic_vm_set_page(rdev, ib, pe_start, addr, count, +					RADEON_GPU_PAGE_SIZE, flags); +		addr += RADEON_GPU_PAGE_SIZE * count; +	} + +	/* handle the area in the middle */ +	count = (frag_end - frag_start) / 8; +	radeon_asic_vm_set_page(rdev, ib, frag_start, addr, count, +				RADEON_GPU_PAGE_SIZE, flags | frag_flags); + +	/* handle the 4K area at the end */ +	if (frag_end != pe_end) { +		addr += RADEON_GPU_PAGE_SIZE * count; +		count = (pe_end - frag_end) / 8; +		radeon_asic_vm_set_page(rdev, ib, frag_end, addr, count, +					RADEON_GPU_PAGE_SIZE, flags); +	} +} + +/** + * radeon_vm_update_ptes - make sure that page tables are valid + * + * @rdev: radeon_device pointer + * @vm: requested vm + * @start: start of GPU address range + * @end: end of GPU address range + * @dst: destination address to map to + * @flags: mapping flags + * + * Update the page tables in the range @start - @end (cayman+). + * + * Global and local mutex must be locked! + */ +static void radeon_vm_update_ptes(struct radeon_device *rdev, +				  struct radeon_vm *vm, +				  struct radeon_ib *ib, +				  uint64_t start, uint64_t end, +				  uint64_t dst, uint32_t flags) +{ +	uint64_t mask = RADEON_VM_PTE_COUNT - 1; +	uint64_t last_pte = ~0, last_dst = ~0; +	unsigned count = 0; +	uint64_t addr; + +	start = start / RADEON_GPU_PAGE_SIZE; +	end = end / RADEON_GPU_PAGE_SIZE; + +	/* walk over the address space and update the page tables */ +	for (addr = start; addr < end; ) { +		uint64_t pt_idx = addr >> radeon_vm_block_size; +		struct radeon_bo *pt = vm->page_tables[pt_idx].bo; +		unsigned nptes; +		uint64_t pte; + +		radeon_semaphore_sync_to(ib->semaphore, pt->tbo.sync_obj); + +		if ((addr & ~mask) == (end & ~mask)) +			nptes = end - addr; +		else +			nptes = RADEON_VM_PTE_COUNT - (addr & mask); + +		pte = radeon_bo_gpu_offset(pt); +		pte += (addr & mask) * 8; + +		if ((last_pte + 8 * count) != pte) { + +			if (count) { +				radeon_vm_frag_ptes(rdev, ib, last_pte, +						    last_pte + 8 * count, +						    last_dst, flags); +			} + +			count = nptes; +			last_pte = pte; +			last_dst = dst; +		} else { +			count += nptes; +		} + +		addr += nptes; +		dst += nptes * RADEON_GPU_PAGE_SIZE; +	} + +	if (count) { +		radeon_vm_frag_ptes(rdev, ib, last_pte, +				    last_pte + 8 * count, +				    last_dst, flags); +	} +} + +/** + * radeon_vm_bo_update - map a bo into the vm page table + * + * @rdev: radeon_device pointer + * @vm: requested vm + * @bo: radeon buffer object + * @mem: ttm mem + * + * Fill in the page table entries for @bo (cayman+). + * Returns 0 for success, -EINVAL for failure. + * + * Object have to be reserved and mutex must be locked! + */ +int radeon_vm_bo_update(struct radeon_device *rdev, +			struct radeon_bo_va *bo_va, +			struct ttm_mem_reg *mem) +{ +	struct radeon_vm *vm = bo_va->vm; +	struct radeon_ib ib; +	unsigned nptes, ndw; +	uint64_t addr; +	int r; + + +	if (!bo_va->soffset) { +		dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n", +			bo_va->bo, vm); +		return -EINVAL; +	} + +	if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) +		return 0; + +	bo_va->flags &= ~RADEON_VM_PAGE_VALID; +	bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; +	if (mem) { +		addr = mem->start << PAGE_SHIFT; +		if (mem->mem_type != TTM_PL_SYSTEM) { +			bo_va->flags |= RADEON_VM_PAGE_VALID; +			bo_va->valid = true; +		} +		if (mem->mem_type == TTM_PL_TT) { +			bo_va->flags |= RADEON_VM_PAGE_SYSTEM; +		} else { +			addr += rdev->vm_manager.vram_base_offset; +		} +	} else { +		addr = 0; +		bo_va->valid = false; +	} + +	trace_radeon_vm_bo_update(bo_va); + +	nptes = (bo_va->eoffset - bo_va->soffset) / RADEON_GPU_PAGE_SIZE; + +	/* padding, etc. */ +	ndw = 64; + +	if (radeon_vm_block_size > 11) +		/* reserve space for one header for every 2k dwords */ +		ndw += (nptes >> 11) * 4; +	else +		/* reserve space for one header for +		    every (1 << BLOCK_SIZE) entries */ +		ndw += (nptes >> radeon_vm_block_size) * 4; + +	/* reserve space for pte addresses */ +	ndw += nptes * 2; + +	/* update too big for an IB */ +	if (ndw > 0xfffff) +		return -ENOMEM; + +	r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, ndw * 4); +	if (r) +		return r; +	ib.length_dw = 0; + +	radeon_vm_update_ptes(rdev, vm, &ib, bo_va->soffset, bo_va->eoffset, +			      addr, radeon_vm_page_flags(bo_va->flags)); + +	radeon_semaphore_sync_to(ib.semaphore, vm->fence); +	r = radeon_ib_schedule(rdev, &ib, NULL); +	if (r) { +		radeon_ib_free(rdev, &ib); +		return r; +	} +	radeon_fence_unref(&vm->fence); +	vm->fence = radeon_fence_ref(ib.fence); +	radeon_ib_free(rdev, &ib); +	radeon_fence_unref(&vm->last_flush); + +	return 0; +} + +/** + * radeon_vm_clear_freed - clear freed BOs in the PT + * + * @rdev: radeon_device pointer + * @vm: requested vm + * + * Make sure all freed BOs are cleared in the PT. + * Returns 0 for success. + * + * PTs have to be reserved and mutex must be locked! + */ +int radeon_vm_clear_freed(struct radeon_device *rdev, +			  struct radeon_vm *vm) +{ +	struct radeon_bo_va *bo_va, *tmp; +	int r; + +	list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { +		list_del(&bo_va->vm_status); +		r = radeon_vm_bo_update(rdev, bo_va, NULL); +		kfree(bo_va); +		if (r) +			return r; +	} +	return 0; + +} + +/** + * radeon_vm_bo_rmv - remove a bo to a specific vm + * + * @rdev: radeon_device pointer + * @bo_va: requested bo_va + * + * Remove @bo_va->bo from the requested vm (cayman+). + * + * Object have to be reserved! + */ +void radeon_vm_bo_rmv(struct radeon_device *rdev, +		      struct radeon_bo_va *bo_va) +{ +	struct radeon_vm *vm = bo_va->vm; + +	list_del(&bo_va->bo_list); + +	mutex_lock(&vm->mutex); +	list_del(&bo_va->vm_list); + +	if (bo_va->soffset) { +		bo_va->bo = NULL; +		list_add(&bo_va->vm_status, &vm->freed); +	} else { +		kfree(bo_va); +	} + +	mutex_unlock(&vm->mutex); +} + +/** + * radeon_vm_bo_invalidate - mark the bo as invalid + * + * @rdev: radeon_device pointer + * @vm: requested vm + * @bo: radeon buffer object + * + * Mark @bo as invalid (cayman+). + */ +void radeon_vm_bo_invalidate(struct radeon_device *rdev, +			     struct radeon_bo *bo) +{ +	struct radeon_bo_va *bo_va; + +	list_for_each_entry(bo_va, &bo->va, bo_list) { +		bo_va->valid = false; +	} +} + +/** + * radeon_vm_init - initialize a vm instance + * + * @rdev: radeon_device pointer + * @vm: requested vm + * + * Init @vm fields (cayman+). + */ +int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) +{ +	const unsigned align = min(RADEON_VM_PTB_ALIGN_SIZE, +		RADEON_VM_PTE_COUNT * 8); +	unsigned pd_size, pd_entries, pts_size; +	int r; + +	vm->id = 0; +	vm->ib_bo_va = NULL; +	vm->fence = NULL; +	vm->last_flush = NULL; +	vm->last_id_use = NULL; +	mutex_init(&vm->mutex); +	INIT_LIST_HEAD(&vm->va); +	INIT_LIST_HEAD(&vm->freed); + +	pd_size = radeon_vm_directory_size(rdev); +	pd_entries = radeon_vm_num_pdes(rdev); + +	/* allocate page table array */ +	pts_size = pd_entries * sizeof(struct radeon_vm_pt); +	vm->page_tables = kzalloc(pts_size, GFP_KERNEL); +	if (vm->page_tables == NULL) { +		DRM_ERROR("Cannot allocate memory for page table array\n"); +		return -ENOMEM; +	} + +	r = radeon_bo_create(rdev, pd_size, align, true, +			     RADEON_GEM_DOMAIN_VRAM, NULL, +			     &vm->page_directory); +	if (r) +		return r; + +	r = radeon_vm_clear_bo(rdev, vm->page_directory); +	if (r) { +		radeon_bo_unref(&vm->page_directory); +		vm->page_directory = NULL; +		return r; +	} + +	return 0; +} + +/** + * radeon_vm_fini - tear down a vm instance + * + * @rdev: radeon_device pointer + * @vm: requested vm + * + * Tear down @vm (cayman+). + * Unbind the VM and remove all bos from the vm bo list + */ +void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) +{ +	struct radeon_bo_va *bo_va, *tmp; +	int i, r; + +	if (!list_empty(&vm->va)) { +		dev_err(rdev->dev, "still active bo inside vm\n"); +	} +	list_for_each_entry_safe(bo_va, tmp, &vm->va, vm_list) { +		list_del_init(&bo_va->vm_list); +		r = radeon_bo_reserve(bo_va->bo, false); +		if (!r) { +			list_del_init(&bo_va->bo_list); +			radeon_bo_unreserve(bo_va->bo); +			kfree(bo_va); +		} +	} +	list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) +		kfree(bo_va); + +	for (i = 0; i < radeon_vm_num_pdes(rdev); i++) +		radeon_bo_unref(&vm->page_tables[i].bo); +	kfree(vm->page_tables); + +	radeon_bo_unref(&vm->page_directory); + +	radeon_fence_unref(&vm->fence); +	radeon_fence_unref(&vm->last_flush); +	radeon_fence_unref(&vm->last_id_use); + +	mutex_destroy(&vm->mutex); +} diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman index a072fa8c46b..d46b58d078a 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/cayman +++ b/drivers/gpu/drm/radeon/reg_srcs/cayman @@ -21,7 +21,7 @@ cayman 0x9400  0x000089AC VGT_COMPUTE_THREAD_GOURP_SIZE  0x000089B0 VGT_HS_OFFCHIP_PARAM  0x00008A14 PA_CL_ENHANCE -0x00008A60 PA_SC_LINE_STIPPLE_VALUE +0x00008A60 PA_SU_LINE_STIPPLE_VALUE  0x00008B10 PA_SC_LINE_STIPPLE_STATE  0x00008BF0 PA_SC_ENHANCE  0x00008D8C SQ_DYN_GPR_CNTL_PS_FLUSH_REQ @@ -532,7 +532,7 @@ cayman 0x9400  0x00028B84 PA_SU_POLY_OFFSET_FRONT_OFFSET  0x00028B88 PA_SU_POLY_OFFSET_BACK_SCALE  0x00028B8C PA_SU_POLY_OFFSET_BACK_OFFSET -0x00028B74 VGT_GS_INSTANCE_CNT +0x00028B90 VGT_GS_INSTANCE_CNT  0x00028BD4 PA_SC_CENTROID_PRIORITY_0  0x00028BD8 PA_SC_CENTROID_PRIORITY_1  0x00028BDC PA_SC_LINE_CNTL diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen index b912a37689b..57745c8761c 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/evergreen +++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen @@ -22,7 +22,7 @@ evergreen 0x9400  0x000089A4 VGT_COMPUTE_START_Z  0x000089AC VGT_COMPUTE_THREAD_GOURP_SIZE  0x00008A14 PA_CL_ENHANCE -0x00008A60 PA_SC_LINE_STIPPLE_VALUE +0x00008A60 PA_SU_LINE_STIPPLE_VALUE  0x00008B10 PA_SC_LINE_STIPPLE_STATE  0x00008BF0 PA_SC_ENHANCE  0x00008D8C SQ_DYN_GPR_CNTL_PS_FLUSH_REQ @@ -545,7 +545,7 @@ evergreen 0x9400  0x00028B84 PA_SU_POLY_OFFSET_FRONT_OFFSET  0x00028B88 PA_SU_POLY_OFFSET_BACK_SCALE  0x00028B8C PA_SU_POLY_OFFSET_BACK_OFFSET -0x00028B74 VGT_GS_INSTANCE_CNT +0x00028B90 VGT_GS_INSTANCE_CNT  0x00028C00 PA_SC_LINE_CNTL  0x00028C08 PA_SU_VTX_CNTL  0x00028C0C PA_CL_GB_VERT_CLIP_ADJ diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index 20bfbda7b3f..ec0c6829c1d 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -18,6 +18,7 @@ r600 0x9400  0x00028A3C VGT_GROUP_VECT_1_FMT_CNTL  0x00028A40 VGT_GS_MODE  0x00028A6C VGT_GS_OUT_PRIM_TYPE +0x00028B38 VGT_GS_MAX_VERT_OUT  0x000088C8 VGT_GS_PER_ES  0x000088E8 VGT_GS_PER_VS  0x000088D4 VGT_GS_VERTEX_REUSE diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 9566b5940a5..a0f96decece 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -212,21 +212,16 @@ void rs400_gart_fini(struct radeon_device *rdev)  #define RS400_PTE_WRITEABLE (1 << 2)  #define RS400_PTE_READABLE  (1 << 3) -int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, uint64_t addr)  {  	uint32_t entry;  	u32 *gtt = rdev->gart.ptr; -	if (i < 0 || i > rdev->gart.num_gpu_pages) { -		return -EINVAL; -	} -  	entry = (lower_32_bits(addr) & PAGE_MASK) |  		((upper_32_bits(addr) & 0xff) << 4) |  		RS400_PTE_WRITEABLE | RS400_PTE_READABLE;  	entry = cpu_to_le32(entry);  	gtt[i] = entry; -	return 0;  }  int rs400_mc_wait_for_idle(struct radeon_device *rdev) @@ -484,6 +479,7 @@ int rs400_resume(struct radeon_device *rdev)  int rs400_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r100_cp_disable(rdev);  	radeon_wb_disable(rdev);  	r100_irq_disable(rdev); @@ -493,6 +489,7 @@ int rs400_suspend(struct radeon_device *rdev)  void rs400_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r100_cp_fini(rdev);  	radeon_wb_fini(rdev);  	radeon_ib_pool_fini(rdev); @@ -560,6 +557,9 @@ int rs400_init(struct radeon_device *rdev)  		return r;  	r300_set_reg_safe(rdev); +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->accel_working = true;  	r = rs400_startup(rdev);  	if (r) { diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 6acba8017b9..d1a35cb1c91 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -109,19 +109,7 @@ void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc)  	}  } -void rs600_pre_page_flip(struct radeon_device *rdev, int crtc) -{ -	/* enable the pflip int */ -	radeon_irq_kms_pflip_irq_get(rdev, crtc); -} - -void rs600_post_page_flip(struct radeon_device *rdev, int crtc) -{ -	/* disable the pflip int */ -	radeon_irq_kms_pflip_irq_put(rdev, crtc); -} - -u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  {  	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];  	u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); @@ -148,9 +136,79 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  	/* Unlock the lock, so double-buffering can take place inside vblank */  	tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK;  	WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); +} + +bool rs600_page_flip_pending(struct radeon_device *rdev, int crtc_id) +{ +	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];  	/* Return current update_pending status: */ -	return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING; +	return !!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & +		AVIVO_D1GRPH_SURFACE_UPDATE_PENDING); +} + +void avivo_program_fmt(struct drm_encoder *encoder) +{ +	struct drm_device *dev = encoder->dev; +	struct radeon_device *rdev = dev->dev_private; +	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); +	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); +	int bpc = 0; +	u32 tmp = 0; +	enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE; + +	if (connector) { +		struct radeon_connector *radeon_connector = to_radeon_connector(connector); +		bpc = radeon_get_monitor_bpc(connector); +		dither = radeon_connector->dither; +	} + +	/* LVDS FMT is set up by atom */ +	if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT) +		return; + +	if (bpc == 0) +		return; + +	switch (bpc) { +	case 6: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; +		else +			tmp |= AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN; +		break; +	case 8: +		if (dither == RADEON_FMT_DITHER_ENABLE) +			/* XXX sort out optimal dither settings */ +			tmp |= (AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN | +				AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH); +		else +			tmp |= (AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN | +				AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH); +		break; +	case 10: +	default: +		/* not needed */ +		break; +	} + +	switch (radeon_encoder->encoder_id) { +	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: +		WREG32(AVIVO_TMDSA_BIT_DEPTH_CONTROL, tmp); +		break; +	case ENCODER_OBJECT_ID_INTERNAL_LVTM1: +		WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, tmp); +		break; +	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: +		WREG32(AVIVO_DVOA_BIT_DEPTH_CONTROL, tmp); +		break; +	case ENCODER_OBJECT_ID_INTERNAL_DDI: +		WREG32(AVIVO_DDIA_BIT_DEPTH_CONTROL, tmp); +		break; +	default: +		break; +	}  }  void rs600_pm_misc(struct radeon_device *rdev) @@ -568,24 +626,16 @@ static void rs600_gart_fini(struct radeon_device *rdev)  	radeon_gart_table_vram_free(rdev);  } -#define R600_PTE_VALID     (1 << 0) -#define R600_PTE_SYSTEM    (1 << 1) -#define R600_PTE_SNOOPED   (1 << 2) -#define R600_PTE_READABLE  (1 << 5) -#define R600_PTE_WRITEABLE (1 << 6) - -int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, uint64_t addr)  {  	void __iomem *ptr = (void *)rdev->gart.ptr; -	if (i < 0 || i > rdev->gart.num_gpu_pages) { -		return -EINVAL; -	}  	addr = addr & 0xFFFFFFFFFFFFF000ULL; -	addr |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED; -	addr |= R600_PTE_READABLE | R600_PTE_WRITEABLE; +	if (addr == rdev->dummy_page.addr) +		addr |= R600_PTE_SYSTEM | R600_PTE_SNOOPED; +	else +		addr |= R600_PTE_GART;  	writeq(addr, ptr + (i * 8)); -	return 0;  }  int rs600_irq_set(struct radeon_device *rdev) @@ -723,7 +773,7 @@ int rs600_irq_process(struct radeon_device *rdev)  				wake_up(&rdev->irq.vblank_queue);  			}  			if (atomic_read(&rdev->irq.pflip[0])) -				radeon_crtc_handle_flip(rdev, 0); +				radeon_crtc_handle_vblank(rdev, 0);  		}  		if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {  			if (rdev->irq.crtc_vblank_int[1]) { @@ -732,7 +782,7 @@ int rs600_irq_process(struct radeon_device *rdev)  				wake_up(&rdev->irq.vblank_queue);  			}  			if (atomic_read(&rdev->irq.pflip[1])) -				radeon_crtc_handle_flip(rdev, 1); +				radeon_crtc_handle_vblank(rdev, 1);  		}  		if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {  			queue_hotplug = true; @@ -994,6 +1044,7 @@ int rs600_resume(struct radeon_device *rdev)  int rs600_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r600_audio_fini(rdev);  	r100_cp_disable(rdev);  	radeon_wb_disable(rdev); @@ -1004,6 +1055,7 @@ int rs600_suspend(struct radeon_device *rdev)  void rs600_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r600_audio_fini(rdev);  	r100_cp_fini(rdev);  	radeon_wb_fini(rdev); @@ -1072,6 +1124,9 @@ int rs600_init(struct radeon_device *rdev)  		return r;  	rs600_set_safe_registers(rdev); +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->accel_working = true;  	r = rs600_startup(rdev);  	if (r) { diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 1447d794c22..3462b64369b 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -162,6 +162,16 @@ static void rs690_mc_init(struct radeon_device *rdev)  	base = RREG32_MC(R_000100_MCCFG_FB_LOCATION);  	base = G_000100_MC_FB_START(base) << 16;  	rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); +	/* Some boards seem to be configured for 128MB of sideport memory, +	 * but really only have 64MB.  Just skip the sideport and use +	 * UMA memory. +	 */ +	if (rdev->mc.igp_sideport_enabled && +	    (rdev->mc.real_vram_size == (384 * 1024 * 1024))) { +		base += 128 * 1024 * 1024; +		rdev->mc.real_vram_size -= 128 * 1024 * 1024; +		rdev->mc.mc_vram_size = rdev->mc.real_vram_size; +	}  	/* Use K8 direct mapping for fast fb access. */   	rdev->fastfb_working = false; @@ -345,9 +355,11 @@ static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,  		if (max_bandwidth.full > rdev->pm.sideport_bandwidth.full &&  			rdev->pm.sideport_bandwidth.full)  			max_bandwidth = rdev->pm.sideport_bandwidth; -		read_delay_latency.full = dfixed_const(370 * 800 * 1000); -		read_delay_latency.full = dfixed_div(read_delay_latency, -			rdev->pm.igp_sideport_mclk); +		read_delay_latency.full = dfixed_const(370 * 800); +		a.full = dfixed_const(1000); +		b.full = dfixed_div(rdev->pm.igp_sideport_mclk, a); +		read_delay_latency.full = dfixed_div(read_delay_latency, b); +		read_delay_latency.full = dfixed_mul(read_delay_latency, a);  	} else {  		if (max_bandwidth.full > rdev->pm.k8_bandwidth.full &&  			rdev->pm.k8_bandwidth.full) @@ -488,14 +500,10 @@ static void rs690_compute_mode_priority(struct radeon_device *rdev,  		}  		if (wm0->priority_mark.full > priority_mark02.full)  			priority_mark02.full = wm0->priority_mark.full; -		if (dfixed_trunc(priority_mark02) < 0) -			priority_mark02.full = 0;  		if (wm0->priority_mark_max.full > priority_mark02.full)  			priority_mark02.full = wm0->priority_mark_max.full;  		if (wm1->priority_mark.full > priority_mark12.full)  			priority_mark12.full = wm1->priority_mark.full; -		if (dfixed_trunc(priority_mark12) < 0) -			priority_mark12.full = 0;  		if (wm1->priority_mark_max.full > priority_mark12.full)  			priority_mark12.full = wm1->priority_mark_max.full;  		*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); @@ -526,8 +534,6 @@ static void rs690_compute_mode_priority(struct radeon_device *rdev,  		}  		if (wm0->priority_mark.full > priority_mark02.full)  			priority_mark02.full = wm0->priority_mark.full; -		if (dfixed_trunc(priority_mark02) < 0) -			priority_mark02.full = 0;  		if (wm0->priority_mark_max.full > priority_mark02.full)  			priority_mark02.full = wm0->priority_mark_max.full;  		*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); @@ -555,8 +561,6 @@ static void rs690_compute_mode_priority(struct radeon_device *rdev,  		}  		if (wm1->priority_mark.full > priority_mark12.full)  			priority_mark12.full = wm1->priority_mark.full; -		if (dfixed_trunc(priority_mark12) < 0) -			priority_mark12.full = 0;  		if (wm1->priority_mark_max.full > priority_mark12.full)  			priority_mark12.full = wm1->priority_mark_max.full;  		*d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); @@ -762,6 +766,7 @@ int rs690_resume(struct radeon_device *rdev)  int rs690_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r600_audio_fini(rdev);  	r100_cp_disable(rdev);  	radeon_wb_disable(rdev); @@ -772,6 +777,7 @@ int rs690_suspend(struct radeon_device *rdev)  void rs690_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r600_audio_fini(rdev);  	r100_cp_fini(rdev);  	radeon_wb_fini(rdev); @@ -841,6 +847,9 @@ int rs690_init(struct radeon_device *rdev)  		return r;  	rs600_set_safe_registers(rdev); +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->accel_working = true;  	r = rs690_startup(rdev);  	if (r) { diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index 6af8505cf4d..02f7710de47 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c @@ -623,14 +623,6 @@ int rs780_dpm_enable(struct radeon_device *rdev)  	if (pi->gfx_clock_gating)  		r600_gfx_clockgating_enable(rdev, true); -	if (rdev->irq.installed && (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) { -		ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); -		if (ret) -			return ret; -		rdev->irq.dpm_thermal = true; -		radeon_irq_set(rdev); -	} -  	return 0;  } @@ -815,9 +807,6 @@ static int rs780_parse_power_table(struct radeon_device *rdev)  				  power_info->pplib.ucNumStates, GFP_KERNEL);  	if (!rdev->pm.dpm.ps)  		return -ENOMEM; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < power_info->pplib.ucNumStates; i++) {  		power_state = (union pplib_power_state *) @@ -867,6 +856,10 @@ int rs780_dpm_init(struct radeon_device *rdev)  		return -ENOMEM;  	rdev->pm.dpm.priv = pi; +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = rs780_parse_power_table(rdev);  	if (ret)  		return ret; diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 873eb4b193b..3e21e869015 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -406,8 +406,9 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)  	for (i = 0; i < rdev->num_crtc; i++) {  		if (save->crtc_enabled[i]) {  			tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i]); -			if ((tmp & 0x3) != 0) { -				tmp &= ~0x3; +			if ((tmp & 0x7) != 3) { +				tmp &= ~0x7; +				tmp |= 0x3;  				WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i], tmp);  			}  			tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); @@ -596,6 +597,7 @@ int rv515_resume(struct radeon_device *rdev)  int rv515_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r100_cp_disable(rdev);  	radeon_wb_disable(rdev);  	rs600_irq_disable(rdev); @@ -612,6 +614,7 @@ void rv515_set_safe_registers(struct radeon_device *rdev)  void rv515_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r100_cp_fini(rdev);  	radeon_wb_fini(rdev);  	radeon_ib_pool_fini(rdev); @@ -685,6 +688,9 @@ int rv515_init(struct radeon_device *rdev)  		return r;  	rv515_set_safe_registers(rdev); +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->accel_working = true;  	r = rv515_startup(rdev);  	if (r) { @@ -1155,14 +1161,10 @@ static void rv515_compute_mode_priority(struct radeon_device *rdev,  		}  		if (wm0->priority_mark.full > priority_mark02.full)  			priority_mark02.full = wm0->priority_mark.full; -		if (dfixed_trunc(priority_mark02) < 0) -			priority_mark02.full = 0;  		if (wm0->priority_mark_max.full > priority_mark02.full)  			priority_mark02.full = wm0->priority_mark_max.full;  		if (wm1->priority_mark.full > priority_mark12.full)  			priority_mark12.full = wm1->priority_mark.full; -		if (dfixed_trunc(priority_mark12) < 0) -			priority_mark12.full = 0;  		if (wm1->priority_mark_max.full > priority_mark12.full)  			priority_mark12.full = wm1->priority_mark_max.full;  		*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); @@ -1193,8 +1195,6 @@ static void rv515_compute_mode_priority(struct radeon_device *rdev,  		}  		if (wm0->priority_mark.full > priority_mark02.full)  			priority_mark02.full = wm0->priority_mark.full; -		if (dfixed_trunc(priority_mark02) < 0) -			priority_mark02.full = 0;  		if (wm0->priority_mark_max.full > priority_mark02.full)  			priority_mark02.full = wm0->priority_mark_max.full;  		*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); @@ -1222,8 +1222,6 @@ static void rv515_compute_mode_priority(struct radeon_device *rdev,  		}  		if (wm1->priority_mark.full > priority_mark12.full)  			priority_mark12.full = wm1->priority_mark.full; -		if (dfixed_trunc(priority_mark12) < 0) -			priority_mark12.full = 0;  		if (wm1->priority_mark_max.full > priority_mark12.full)  			priority_mark12.full = wm1->priority_mark_max.full;  		*d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index 5811d277a36..e7045b08571 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -407,9 +407,9 @@ static void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device  	WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC);  } -static u64 rv6xx_clocks_per_unit(u32 unit) +static u32 rv6xx_clocks_per_unit(u32 unit)  { -	u64 tmp = 1 << (2 * unit); +	u32 tmp = 1 << (2 * unit);  	return tmp;  } @@ -417,7 +417,7 @@ static u64 rv6xx_clocks_per_unit(u32 unit)  static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev,  					u32 unscaled_count, u32 unit)  { -	u32 count_per_unit = (u32)rv6xx_clocks_per_unit(unit); +	u32 count_per_unit = rv6xx_clocks_per_unit(unit);  	return (unscaled_count + count_per_unit - 1) / count_per_unit;  } @@ -1546,7 +1546,6 @@ int rv6xx_dpm_enable(struct radeon_device *rdev)  {  	struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);  	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; -	int ret;  	if (r600_dynamicpm_enabled(rdev))  		return -EINVAL; @@ -1594,15 +1593,6 @@ int rv6xx_dpm_enable(struct radeon_device *rdev)  	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);  	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); -	if (rdev->irq.installed && -	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { -		ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); -		if (ret) -			return ret; -		rdev->irq.dpm_thermal = true; -		radeon_irq_set(rdev); -	} -  	rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);  	r600_start_dpm(rdev); @@ -1901,9 +1891,6 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev)  				  power_info->pplib.ucNumStates, GFP_KERNEL);  	if (!rdev->pm.dpm.ps)  		return -ENOMEM; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < power_info->pplib.ucNumStates; i++) {  		power_state = (union pplib_power_state *) @@ -1953,6 +1940,10 @@ int rv6xx_dpm_init(struct radeon_device *rdev)  		return -ENOMEM;  	rdev->pm.dpm.priv = pi; +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = rv6xx_parse_power_table(rdev);  	if (ret)  		return ret; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 9f5846743c9..da8703d8d45 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -801,7 +801,7 @@ u32 rv770_get_xclk(struct radeon_device *rdev)  	return reference_clock;  } -u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  {  	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];  	u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); @@ -835,9 +835,15 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)  	/* Unlock the lock, so double-buffering can take place inside vblank */  	tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK;  	WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); +} + +bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc_id) +{ +	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];  	/* Return current update_pending status: */ -	return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING; +	return !!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & +		AVIVO_D1GRPH_SURFACE_UPDATE_PENDING);  }  /* get temperature in millidegrees */ @@ -1071,7 +1077,8 @@ static void rv770_mc_program(struct radeon_device *rdev)   */  void r700_cp_stop(struct radeon_device *rdev)  { -	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); +	if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);  	WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));  	WREG32(SCRATCH_UMSK, 0);  	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false; @@ -1123,6 +1130,35 @@ void r700_cp_fini(struct radeon_device *rdev)  	radeon_scratch_free(rdev, ring->rptr_save_reg);  } +void rv770_set_clk_bypass_mode(struct radeon_device *rdev) +{ +	u32 tmp, i; + +	if (rdev->flags & RADEON_IS_IGP) +		return; + +	tmp = RREG32(CG_SPLL_FUNC_CNTL_2); +	tmp &= SCLK_MUX_SEL_MASK; +	tmp |= SCLK_MUX_SEL(1) | SCLK_MUX_UPDATE; +	WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + +	for (i = 0; i < rdev->usec_timeout; i++) { +		if (RREG32(CG_SPLL_STATUS) & SPLL_CHG_STATUS) +			break; +		udelay(1); +	} + +	tmp &= ~SCLK_MUX_UPDATE; +	WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + +	tmp = RREG32(MPLL_CNTL_MODE); +	if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) +		tmp &= ~RV730_MPLL_MCLK_SEL; +	else +		tmp &= ~MPLL_MCLK_SEL; +	WREG32(MPLL_CNTL_MODE, tmp); +} +  /*   * Core functions   */ @@ -1291,6 +1327,9 @@ static void rv770_gpu_init(struct radeon_device *rdev)  	if (tmp < rdev->config.rv770.max_simds) {  		rdev->config.rv770.max_simds = tmp;  	} +	tmp = rdev->config.rv770.max_simds - +		r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R7XX_MAX_SIMDS_MASK); +	rdev->config.rv770.active_simds = tmp;  	switch (rdev->config.rv770.max_tile_pipes) {  	case 1: @@ -1665,14 +1704,6 @@ static int rv770_startup(struct radeon_device *rdev)  	rv770_mc_program(rdev); -	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { -		r = r600_init_microcode(rdev); -		if (r) { -			DRM_ERROR("Failed to load firmware!\n"); -			return r; -		} -	} -  	if (rdev->flags & RADEON_IS_AGP) {  		rv770_agp_enable(rdev);  	} else { @@ -1728,14 +1759,12 @@ static int rv770_startup(struct radeon_device *rdev)  	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, -			     R600_CP_RB_RPTR, R600_CP_RB_WPTR,  			     RADEON_CP_PACKET2);  	if (r)  		return r;  	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, -			     DMA_RB_RPTR, DMA_RB_WPTR,  			     DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));  	if (r)  		return r; @@ -1754,7 +1783,6 @@ static int rv770_startup(struct radeon_device *rdev)  	ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];  	if (ring->ring_size) {  		r = radeon_ring_init(rdev, ring, ring->ring_size, 0, -				     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,  				     RADEON_CP_PACKET2);  		if (!r)  			r = uvd_v1_0_init(rdev); @@ -1792,6 +1820,9 @@ int rv770_resume(struct radeon_device *rdev)  	/* init golden registers */  	rv770_init_golden_registers(rdev); +	if (rdev->pm.pm_method == PM_METHOD_DPM) +		radeon_pm_resume(rdev); +  	rdev->accel_working = true;  	r = rv770_startup(rdev);  	if (r) { @@ -1806,6 +1837,7 @@ int rv770_resume(struct radeon_device *rdev)  int rv770_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	r600_audio_fini(rdev);  	uvd_v1_0_fini(rdev);  	radeon_uvd_suspend(rdev); @@ -1876,6 +1908,17 @@ int rv770_init(struct radeon_device *rdev)  	if (r)  		return r; +	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { +		r = r600_init_microcode(rdev); +		if (r) { +			DRM_ERROR("Failed to load firmware!\n"); +			return r; +		} +	} + +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;  	r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -1915,15 +1958,16 @@ int rv770_init(struct radeon_device *rdev)  void rv770_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	r700_cp_fini(rdev);  	r600_dma_fini(rdev);  	r600_irq_fini(rdev);  	radeon_wb_fini(rdev);  	radeon_ib_pool_fini(rdev);  	radeon_irq_kms_fini(rdev); -	rv770_pcie_gart_fini(rdev);  	uvd_v1_0_fini(rdev);  	radeon_uvd_fini(rdev); +	rv770_pcie_gart_fini(rdev);  	r600_vram_scratch_fini(rdev);  	radeon_gem_fini(rdev);  	radeon_fence_driver_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rv770_dma.c b/drivers/gpu/drm/radeon/rv770_dma.c index f9b02e3d683..bbf2e076ee4 100644 --- a/drivers/gpu/drm/radeon/rv770_dma.c +++ b/drivers/gpu/drm/radeon/rv770_dma.c @@ -66,13 +66,8 @@ int rv770_copy_dma(struct radeon_device *rdev,  		return r;  	} -	if (radeon_fence_need_sync(*fence, ring->idx)) { -		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, -					    ring->idx); -		radeon_fence_note_sync(*fence, ring->idx); -	} else { -		radeon_semaphore_free(rdev, &sem, NULL); -	} +	radeon_semaphore_sync_to(sem, *fence); +	radeon_semaphore_sync_rings(rdev, sem, ring->idx);  	for (i = 0; i < num_loops; i++) {  		cur_size_in_dw = size_in_dw; @@ -91,6 +86,7 @@ int rv770_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 913b025ae9b..3c76e1dcdf0 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -1863,8 +1863,8 @@ void rv770_enable_auto_throttle_source(struct radeon_device *rdev,  	}  } -int rv770_set_thermal_temperature_range(struct radeon_device *rdev, -					int min_temp, int max_temp) +static int rv770_set_thermal_temperature_range(struct radeon_device *rdev, +					       int min_temp, int max_temp)  {  	int low_temp = 0 * 1000;  	int high_temp = 255 * 1000; @@ -1966,6 +1966,15 @@ int rv770_dpm_enable(struct radeon_device *rdev)  	if (pi->mg_clock_gating)  		rv770_mg_clock_gating_enable(rdev, true); +	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); + +	return 0; +} + +int rv770_dpm_late_enable(struct radeon_device *rdev) +{ +	int ret; +  	if (rdev->irq.installed &&  	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {  		PPSMC_Result result; @@ -1981,8 +1990,6 @@ int rv770_dpm_enable(struct radeon_device *rdev)  			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");  	} -	rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); -  	return 0;  } @@ -2167,7 +2174,6 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,  	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);  	struct rv7xx_ps *ps = rv770_get_ps(rps);  	u32 sclk, mclk; -	u16 vddc;  	struct rv7xx_pl *pl;  	switch (index) { @@ -2207,8 +2213,8 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,  	/* patch up vddc if necessary */  	if (pl->vddc == 0xff01) { -		if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) -			pl->vddc = vddc; +		if (pi->max_vddc) +			pl->vddc = pi->max_vddc;  	}  	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { @@ -2244,14 +2250,12 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,  		pl->vddci = vddci;  	} -	if (rdev->family >= CHIP_BARTS) { -		if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == -		    ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { -			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk; -			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk; -			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc; -			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci; -		} +	if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == +	    ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { +		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk; +		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk; +		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc; +		rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;  	}  } @@ -2277,9 +2281,6 @@ int rv7xx_parse_power_table(struct radeon_device *rdev)  				  power_info->pplib.ucNumStates, GFP_KERNEL);  	if (!rdev->pm.dpm.ps)  		return -ENOMEM; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < power_info->pplib.ucNumStates; i++) {  		power_state = (union pplib_power_state *) @@ -2351,6 +2352,10 @@ int rv770_dpm_init(struct radeon_device *rdev)  	pi->min_vddc_in_table = 0;  	pi->max_vddc_in_table = 0; +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = rv7xx_parse_power_table(rdev);  	if (ret)  		return ret; @@ -2516,14 +2521,13 @@ u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low)  bool rv770_dpm_vblank_too_short(struct radeon_device *rdev)  {  	u32 vblank_time = r600_dpm_get_vblank_time(rdev); -	u32 switch_limit = 300; - -	/* quirks */ -	/* ASUS K70AF */ -	if ((rdev->pdev->device == 0x9553) && -	    (rdev->pdev->subsystem_vendor == 0x1043) && -	    (rdev->pdev->subsystem_device == 0x1c42)) -		switch_limit = 200; +	u32 switch_limit = 200; /* 300 */ + +	/* RV770 */ +	/* mclk switching doesn't seem to work reliably on desktop RV770s */ +	if ((rdev->family == CHIP_RV770) && +	    !(rdev->flags & RADEON_IS_MOBILITY)) +		switch_limit = 0xffffffff; /* disable mclk switching */  	if (vblank_time < switch_limit)  		return true; diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h index 9244effc6b5..f776634840c 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.h +++ b/drivers/gpu/drm/radeon/rv770_dpm.h @@ -283,8 +283,4 @@ int rv770_read_smc_soft_register(struct radeon_device *rdev,  int rv770_write_smc_soft_register(struct radeon_device *rdev,  				  u16 reg_offset, u32 value); -/* thermal */ -int rv770_set_thermal_temperature_range(struct radeon_device *rdev, -					int min_temp, int max_temp); -  #endif diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 1ae277152cc..3cf1e292154 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -100,14 +100,21 @@  #define	CG_SPLL_FUNC_CNTL_2				0x604  #define		SCLK_MUX_SEL(x)				((x) << 0)  #define		SCLK_MUX_SEL_MASK			(0x1ff << 0) +#define		SCLK_MUX_UPDATE				(1 << 26)  #define	CG_SPLL_FUNC_CNTL_3				0x608  #define		SPLL_FB_DIV(x)				((x) << 0)  #define		SPLL_FB_DIV_MASK			(0x3ffffff << 0)  #define		SPLL_DITHEN				(1 << 28) +#define	CG_SPLL_STATUS					0x60c +#define		SPLL_CHG_STATUS				(1 << 1)  #define	SPLL_CNTL_MODE					0x610  #define		SPLL_DIV_SYNC				(1 << 5) +#define MPLL_CNTL_MODE                                  0x61c +#       define MPLL_MCLK_SEL                            (1 << 11) +#       define RV730_MPLL_MCLK_SEL                      (1 << 25) +  #define	MPLL_AD_FUNC_CNTL				0x624  #define		CLKF(x)					((x) << 0)  #define		CLKF_MASK				(0x7f << 0) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index c354c109496..9e854fd016d 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -39,33 +39,39 @@ MODULE_FIRMWARE("radeon/TAHITI_pfp.bin");  MODULE_FIRMWARE("radeon/TAHITI_me.bin");  MODULE_FIRMWARE("radeon/TAHITI_ce.bin");  MODULE_FIRMWARE("radeon/TAHITI_mc.bin"); +MODULE_FIRMWARE("radeon/TAHITI_mc2.bin");  MODULE_FIRMWARE("radeon/TAHITI_rlc.bin");  MODULE_FIRMWARE("radeon/TAHITI_smc.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_me.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_ce.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_mc.bin"); +MODULE_FIRMWARE("radeon/PITCAIRN_mc2.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_rlc.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_smc.bin");  MODULE_FIRMWARE("radeon/VERDE_pfp.bin");  MODULE_FIRMWARE("radeon/VERDE_me.bin");  MODULE_FIRMWARE("radeon/VERDE_ce.bin");  MODULE_FIRMWARE("radeon/VERDE_mc.bin"); +MODULE_FIRMWARE("radeon/VERDE_mc2.bin");  MODULE_FIRMWARE("radeon/VERDE_rlc.bin");  MODULE_FIRMWARE("radeon/VERDE_smc.bin");  MODULE_FIRMWARE("radeon/OLAND_pfp.bin");  MODULE_FIRMWARE("radeon/OLAND_me.bin");  MODULE_FIRMWARE("radeon/OLAND_ce.bin");  MODULE_FIRMWARE("radeon/OLAND_mc.bin"); +MODULE_FIRMWARE("radeon/OLAND_mc2.bin");  MODULE_FIRMWARE("radeon/OLAND_rlc.bin");  MODULE_FIRMWARE("radeon/OLAND_smc.bin");  MODULE_FIRMWARE("radeon/HAINAN_pfp.bin");  MODULE_FIRMWARE("radeon/HAINAN_me.bin");  MODULE_FIRMWARE("radeon/HAINAN_ce.bin");  MODULE_FIRMWARE("radeon/HAINAN_mc.bin"); +MODULE_FIRMWARE("radeon/HAINAN_mc2.bin");  MODULE_FIRMWARE("radeon/HAINAN_rlc.bin");  MODULE_FIRMWARE("radeon/HAINAN_smc.bin"); +static u32 si_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh);  static void si_pcie_gen3_enable(struct radeon_device *rdev);  static void si_program_aspm(struct radeon_device *rdev);  extern void sumo_rlc_fini(struct radeon_device *rdev); @@ -78,13 +84,13 @@ extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_  extern u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev);  extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);  extern bool evergreen_is_display_hung(struct radeon_device *rdev); -extern void si_dma_vm_set_page(struct radeon_device *rdev, -			       struct radeon_ib *ib, -			       uint64_t pe, -			       uint64_t addr, unsigned count, -			       uint32_t incr, uint32_t flags);  static void si_enable_gui_idle_interrupt(struct radeon_device *rdev,  					 bool enable); +static void si_init_pg(struct radeon_device *rdev); +static void si_init_cg(struct radeon_device *rdev); +static void si_fini_pg(struct radeon_device *rdev); +static void si_fini_cg(struct radeon_device *rdev); +static void si_rlc_stop(struct radeon_device *rdev);  static const u32 verde_rlc_save_restore_register_list[] =  { @@ -1462,41 +1468,38 @@ static const u32 hainan_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = {  };  /* ucode loading */ -static int si_mc_load_microcode(struct radeon_device *rdev) +int si_mc_load_microcode(struct radeon_device *rdev)  {  	const __be32 *fw_data;  	u32 running, blackout = 0;  	u32 *io_mc_regs; -	int i, ucode_size, regs_size; +	int i, regs_size, ucode_size;  	if (!rdev->mc_fw)  		return -EINVAL; +	ucode_size = rdev->mc_fw->size / 4; +  	switch (rdev->family) {  	case CHIP_TAHITI:  		io_mc_regs = (u32 *)&tahiti_io_mc_regs; -		ucode_size = SI_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	case CHIP_PITCAIRN:  		io_mc_regs = (u32 *)&pitcairn_io_mc_regs; -		ucode_size = SI_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	case CHIP_VERDE:  	default:  		io_mc_regs = (u32 *)&verde_io_mc_regs; -		ucode_size = SI_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	case CHIP_OLAND:  		io_mc_regs = (u32 *)&oland_io_mc_regs; -		ucode_size = OLAND_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	case CHIP_HAINAN:  		io_mc_regs = (u32 *)&hainan_io_mc_regs; -		ucode_size = OLAND_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	} @@ -1552,7 +1555,7 @@ static int si_init_microcode(struct radeon_device *rdev)  	const char *chip_name;  	const char *rlc_chip_name;  	size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size; -	size_t smc_req_size; +	size_t smc_req_size, mc2_req_size;  	char fw_name[30];  	int err; @@ -1567,6 +1570,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4;  		mc_req_size = SI_MC_UCODE_SIZE * 4; +		mc2_req_size = TAHITI_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(TAHITI_SMC_UCODE_SIZE, 4);  		break;  	case CHIP_PITCAIRN: @@ -1577,6 +1581,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4;  		mc_req_size = SI_MC_UCODE_SIZE * 4; +		mc2_req_size = PITCAIRN_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(PITCAIRN_SMC_UCODE_SIZE, 4);  		break;  	case CHIP_VERDE: @@ -1587,6 +1592,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4;  		mc_req_size = SI_MC_UCODE_SIZE * 4; +		mc2_req_size = VERDE_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(VERDE_SMC_UCODE_SIZE, 4);  		break;  	case CHIP_OLAND: @@ -1596,7 +1602,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		me_req_size = SI_PM4_UCODE_SIZE * 4;  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4; -		mc_req_size = OLAND_MC_UCODE_SIZE * 4; +		mc_req_size = mc2_req_size = OLAND_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(OLAND_SMC_UCODE_SIZE, 4);  		break;  	case CHIP_HAINAN: @@ -1606,7 +1612,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		me_req_size = SI_PM4_UCODE_SIZE * 4;  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4; -		mc_req_size = OLAND_MC_UCODE_SIZE * 4; +		mc_req_size = mc2_req_size = OLAND_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(HAINAN_SMC_UCODE_SIZE, 4);  		break;  	default: BUG(); @@ -1659,16 +1665,22 @@ static int si_init_microcode(struct radeon_device *rdev)  		err = -EINVAL;  	} -	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); +	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name);  	err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); -	if (err) -		goto out; -	if (rdev->mc_fw->size != mc_req_size) { +	if (err) { +		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); +		err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); +		if (err) +			goto out; +	} +	if ((rdev->mc_fw->size != mc_req_size) && +	    (rdev->mc_fw->size != mc2_req_size)) {  		printk(KERN_ERR  		       "si_mc: Bogus length %zu in firmware \"%s\"\n",  		       rdev->mc_fw->size, fw_name);  		err = -EINVAL;  	} +	DRM_INFO("%s: %zu bytes\n", fw_name, rdev->mc_fw->size);  	snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);  	err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); @@ -1678,6 +1690,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		       fw_name);  		release_firmware(rdev->smc_fw);  		rdev->smc_fw = NULL; +		err = 0;  	} else if (rdev->smc_fw->size != smc_req_size) {  		printk(KERN_ERR  		       "si_smc: Bogus length %zu in firmware \"%s\"\n", @@ -2812,7 +2825,7 @@ static void si_setup_spi(struct radeon_device *rdev,  }  static u32 si_get_rb_disabled(struct radeon_device *rdev, -			      u32 max_rb_num, u32 se_num, +			      u32 max_rb_num_per_se,  			      u32 sh_per_se)  {  	u32 data, mask; @@ -2826,14 +2839,14 @@ static u32 si_get_rb_disabled(struct radeon_device *rdev,  	data >>= BACKEND_DISABLE_SHIFT; -	mask = si_create_bitmask(max_rb_num / se_num / sh_per_se); +	mask = si_create_bitmask(max_rb_num_per_se / sh_per_se);  	return data & mask;  }  static void si_setup_rb(struct radeon_device *rdev,  			u32 se_num, u32 sh_per_se, -			u32 max_rb_num) +			u32 max_rb_num_per_se)  {  	int i, j;  	u32 data, mask; @@ -2843,19 +2856,21 @@ static void si_setup_rb(struct radeon_device *rdev,  	for (i = 0; i < se_num; i++) {  		for (j = 0; j < sh_per_se; j++) {  			si_select_se_sh(rdev, i, j); -			data = si_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se); +			data = si_get_rb_disabled(rdev, max_rb_num_per_se, sh_per_se);  			disabled_rbs |= data << ((i * sh_per_se + j) * TAHITI_RB_BITMAP_WIDTH_PER_SH);  		}  	}  	si_select_se_sh(rdev, 0xffffffff, 0xffffffff);  	mask = 1; -	for (i = 0; i < max_rb_num; i++) { +	for (i = 0; i < max_rb_num_per_se * se_num; i++) {  		if (!(disabled_rbs & mask))  			enabled_rbs |= mask;  		mask <<= 1;  	} +	rdev->config.si.backend_enable_mask = enabled_rbs; +  	for (i = 0; i < se_num; i++) {  		si_select_se_sh(rdev, i, 0xffffffff);  		data = 0; @@ -2886,7 +2901,7 @@ static void si_gpu_init(struct radeon_device *rdev)  	u32 sx_debug_1;  	u32 hdp_host_path_cntl;  	u32 tmp; -	int i, j; +	int i, j, k;  	switch (rdev->family) {  	case CHIP_TAHITI: @@ -3084,6 +3099,14 @@ static void si_gpu_init(struct radeon_device *rdev)  		     rdev->config.si.max_sh_per_se,  		     rdev->config.si.max_cu_per_sh); +	for (i = 0; i < rdev->config.si.max_shader_engines; i++) { +		for (j = 0; j < rdev->config.si.max_sh_per_se; j++) { +			for (k = 0; k < rdev->config.si.max_cu_per_sh; k++) { +				rdev->config.si.active_cus += +					hweight32(si_get_cu_active_bitmap(rdev, i, j)); +			} +		} +	}  	/* set HW defaults for 3D engine */  	WREG32(CP_QUEUE_THRESHOLDS, (ROQ_IB1_START(0x16) | @@ -3172,7 +3195,7 @@ void si_fence_ring_emit(struct radeon_device *rdev,  	/* EVENT_WRITE_EOP - flush caches, send int */  	radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));  	radeon_ring_write(ring, EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) | EVENT_INDEX(5)); -	radeon_ring_write(ring, addr & 0xffffffff); +	radeon_ring_write(ring, lower_32_bits(addr));  	radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | DATA_SEL(1) | INT_SEL(2));  	radeon_ring_write(ring, fence->seq);  	radeon_ring_write(ring, 0); @@ -3205,7 +3228,7 @@ void si_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)  			radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));  			radeon_ring_write(ring, (1 << 8));  			radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); -			radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff); +			radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr));  			radeon_ring_write(ring, next_rptr);  		} @@ -3246,7 +3269,8 @@ static void si_cp_enable(struct radeon_device *rdev, bool enable)  	if (enable)  		WREG32(CP_ME_CNTL, 0);  	else { -		radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); +		if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +			radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);  		WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));  		WREG32(SCRATCH_UMSK, 0);  		rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false; @@ -3430,8 +3454,6 @@ static int si_cp_resume(struct radeon_device *rdev)  	WREG32(CP_RB0_BASE, ring->gpu_addr >> 8); -	ring->rptr = RREG32(CP_RB0_RPTR); -  	/* ring1  - compute only */  	/* Set ring buffer size */  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; @@ -3456,8 +3478,6 @@ static int si_cp_resume(struct radeon_device *rdev)  	WREG32(CP_RB1_BASE, ring->gpu_addr >> 8); -	ring->rptr = RREG32(CP_RB1_RPTR); -  	/* ring2 - compute only */  	/* Set ring buffer size */  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; @@ -3482,8 +3502,6 @@ static int si_cp_resume(struct radeon_device *rdev)  	WREG32(CP_RB2_BASE, ring->gpu_addr >> 8); -	ring->rptr = RREG32(CP_RB2_RPTR); -  	/* start the rings */  	si_cp_start(rdev);  	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = true; @@ -3507,6 +3525,9 @@ static int si_cp_resume(struct radeon_device *rdev)  	si_enable_gui_idle_interrupt(rdev, true); +	if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX) +		radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); +  	return 0;  } @@ -3608,6 +3629,13 @@ static void si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)  	dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",  		 RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); +	/* disable PG/CG */ +	si_fini_pg(rdev); +	si_fini_cg(rdev); + +	/* stop the rlc */ +	si_rlc_stop(rdev); +  	/* Disable CP parsing/prefetching */  	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); @@ -3716,6 +3744,106 @@ static void si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)  	evergreen_print_gpu_status_regs(rdev);  } +static void si_set_clk_bypass_mode(struct radeon_device *rdev) +{ +	u32 tmp, i; + +	tmp = RREG32(CG_SPLL_FUNC_CNTL); +	tmp |= SPLL_BYPASS_EN; +	WREG32(CG_SPLL_FUNC_CNTL, tmp); + +	tmp = RREG32(CG_SPLL_FUNC_CNTL_2); +	tmp |= SPLL_CTLREQ_CHG; +	WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + +	for (i = 0; i < rdev->usec_timeout; i++) { +		if (RREG32(SPLL_STATUS) & SPLL_CHG_STATUS) +			break; +		udelay(1); +	} + +	tmp = RREG32(CG_SPLL_FUNC_CNTL_2); +	tmp &= ~(SPLL_CTLREQ_CHG | SCLK_MUX_UPDATE); +	WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + +	tmp = RREG32(MPLL_CNTL_MODE); +	tmp &= ~MPLL_MCLK_SEL; +	WREG32(MPLL_CNTL_MODE, tmp); +} + +static void si_spll_powerdown(struct radeon_device *rdev) +{ +	u32 tmp; + +	tmp = RREG32(SPLL_CNTL_MODE); +	tmp |= SPLL_SW_DIR_CONTROL; +	WREG32(SPLL_CNTL_MODE, tmp); + +	tmp = RREG32(CG_SPLL_FUNC_CNTL); +	tmp |= SPLL_RESET; +	WREG32(CG_SPLL_FUNC_CNTL, tmp); + +	tmp = RREG32(CG_SPLL_FUNC_CNTL); +	tmp |= SPLL_SLEEP; +	WREG32(CG_SPLL_FUNC_CNTL, tmp); + +	tmp = RREG32(SPLL_CNTL_MODE); +	tmp &= ~SPLL_SW_DIR_CONTROL; +	WREG32(SPLL_CNTL_MODE, tmp); +} + +static void si_gpu_pci_config_reset(struct radeon_device *rdev) +{ +	struct evergreen_mc_save save; +	u32 tmp, i; + +	dev_info(rdev->dev, "GPU pci config reset\n"); + +	/* disable dpm? */ + +	/* disable cg/pg */ +	si_fini_pg(rdev); +	si_fini_cg(rdev); + +	/* Disable CP parsing/prefetching */ +	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); +	/* dma0 */ +	tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET); +	tmp &= ~DMA_RB_ENABLE; +	WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp); +	/* dma1 */ +	tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET); +	tmp &= ~DMA_RB_ENABLE; +	WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp); +	/* XXX other engines? */ + +	/* halt the rlc, disable cp internal ints */ +	si_rlc_stop(rdev); + +	udelay(50); + +	/* disable mem access */ +	evergreen_mc_stop(rdev, &save); +	if (evergreen_mc_wait_for_idle(rdev)) { +		dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); +	} + +	/* set mclk/sclk to bypass */ +	si_set_clk_bypass_mode(rdev); +	/* powerdown spll */ +	si_spll_powerdown(rdev); +	/* disable BM */ +	pci_clear_master(rdev->pdev); +	/* reset */ +	radeon_pci_config_reset(rdev); +	/* wait for asic to come out of reset */ +	for (i = 0; i < rdev->usec_timeout; i++) { +		if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) +			break; +		udelay(1); +	} +} +  int si_asic_reset(struct radeon_device *rdev)  {  	u32 reset_mask; @@ -3725,10 +3853,17 @@ int si_asic_reset(struct radeon_device *rdev)  	if (reset_mask)  		r600_set_bios_scratch_engine_hung(rdev, true); +	/* try soft reset */  	si_gpu_soft_reset(rdev, reset_mask);  	reset_mask = si_gpu_check_soft_reset(rdev); +	/* try pci config reset */ +	if (reset_mask && radeon_hard_reset) +		si_gpu_pci_config_reset(rdev); + +	reset_mask = si_gpu_check_soft_reset(rdev); +  	if (!reset_mask)  		r600_set_bios_scratch_engine_hung(rdev, false); @@ -3751,11 +3886,9 @@ bool si_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  	if (!(reset_mask & (RADEON_RESET_GFX |  			    RADEON_RESET_COMPUTE |  			    RADEON_RESET_CP))) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force CP activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -3876,8 +4009,15 @@ static int si_mc_init(struct radeon_device *rdev)  	rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);  	rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);  	/* size in MB on si */ -	rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL; -	rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL; +	tmp = RREG32(CONFIG_MEMSIZE); +	/* some boards may have garbage in the upper 16 bits */ +	if (tmp & 0xffff0000) { +		DRM_INFO("Probable bad vram size: 0x%08x\n", tmp); +		if (tmp & 0xffff) +			tmp &= 0xffff; +	} +	rdev->mc.mc_vram_size = tmp * 1024ULL * 1024ULL; +	rdev->mc.real_vram_size = rdev->mc.mc_vram_size;  	rdev->mc.visible_vram_size = rdev->mc.aper_size;  	si_vram_gtt_location(rdev, &rdev->mc);  	radeon_update_bandwidth_info(rdev); @@ -3913,18 +4053,21 @@ static int si_pcie_gart_enable(struct radeon_device *rdev)  	WREG32(MC_VM_MX_L1_TLB_CNTL,  	       (0xA << 7) |  	       ENABLE_L1_TLB | +	       ENABLE_L1_FRAGMENT_PROCESSING |  	       SYSTEM_ACCESS_MODE_NOT_IN_SYS |  	       ENABLE_ADVANCED_DRIVER_MODEL |  	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);  	/* Setup L2 cache */  	WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | +	       ENABLE_L2_FRAGMENT_PROCESSING |  	       ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |  	       ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |  	       EFFECTIVE_L2_QUEUE_SIZE(7) |  	       CONTEXT1_IDENTITY_ACCESS_MODE(1));  	WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);  	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY | -	       L2_CACHE_BIGK_FRAGMENT_SIZE(0)); +	       BANK_SELECT(4) | +	       L2_CACHE_BIGK_FRAGMENT_SIZE(4));  	/* setup context0 */  	WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);  	WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12); @@ -3961,6 +4104,7 @@ static int si_pcie_gart_enable(struct radeon_device *rdev)  	       (u32)(rdev->dummy_page.addr >> 12));  	WREG32(VM_CONTEXT1_CNTL2, 4);  	WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) | +				PAGE_TABLE_BLOCK_SIZE(radeon_vm_block_size - 9) |  				RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |  				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |  				DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT | @@ -4662,61 +4806,6 @@ static void si_vm_decode_fault(struct radeon_device *rdev,  	       block, mc_id);  } -/** - * si_vm_set_page - update the page tables using the CP - * - * @rdev: radeon_device pointer - * @ib: indirect buffer to fill with commands - * @pe: addr of the page entry - * @addr: dst addr to write into pe - * @count: number of page entries to update - * @incr: increase next addr by incr bytes - * @flags: access flags - * - * Update the page tables using the CP (SI). - */ -void si_vm_set_page(struct radeon_device *rdev, -		    struct radeon_ib *ib, -		    uint64_t pe, -		    uint64_t addr, unsigned count, -		    uint32_t incr, uint32_t flags) -{ -	uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); -	uint64_t value; -	unsigned ndw; - -	if (rdev->asic->vm.pt_ring_index == RADEON_RING_TYPE_GFX_INDEX) { -		while (count) { -			ndw = 2 + count * 2; -			if (ndw > 0x3FFE) -				ndw = 0x3FFE; - -			ib->ptr[ib->length_dw++] = PACKET3(PACKET3_WRITE_DATA, ndw); -			ib->ptr[ib->length_dw++] = (WRITE_DATA_ENGINE_SEL(0) | -					WRITE_DATA_DST_SEL(1)); -			ib->ptr[ib->length_dw++] = pe; -			ib->ptr[ib->length_dw++] = upper_32_bits(pe); -			for (; ndw > 2; ndw -= 2, --count, pe += 8) { -				if (flags & RADEON_VM_PAGE_SYSTEM) { -					value = radeon_vm_map_gart(rdev, addr); -					value &= 0xFFFFFFFFFFFFF000ULL; -				} else if (flags & RADEON_VM_PAGE_VALID) { -					value = addr; -				} else { -					value = 0; -				} -				addr += incr; -				value |= r600_flags; -				ib->ptr[ib->length_dw++] = value; -				ib->ptr[ib->length_dw++] = upper_32_bits(value); -			} -		} -	} else { -		/* DMA */ -		si_dma_vm_set_page(rdev, ib, pe, addr, count, incr, flags); -	} -} -  void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)  {  	struct radeon_ring *ring = &rdev->ring[ridx]; @@ -5252,8 +5341,8 @@ static void si_enable_hdp_ls(struct radeon_device *rdev,  		WREG32(HDP_MEM_POWER_LS, data);  } -void si_update_cg(struct radeon_device *rdev, -		  u32 block, bool enable) +static void si_update_cg(struct radeon_device *rdev, +			 u32 block, bool enable)  {  	if (block & RADEON_CG_BLOCK_GFX) {  		si_enable_gui_idle_interrupt(rdev, false); @@ -5361,52 +5450,53 @@ void si_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer)  	if (buffer == NULL)  		return; -	buffer[count++] = PACKET3(PACKET3_PREAMBLE_CNTL, 0); -	buffer[count++] = PACKET3_PREAMBLE_BEGIN_CLEAR_STATE; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0)); +	buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_BEGIN_CLEAR_STATE); -	buffer[count++] = PACKET3(PACKET3_CONTEXT_CONTROL, 1); -	buffer[count++] = 0x80000000; -	buffer[count++] = 0x80000000; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_CONTEXT_CONTROL, 1)); +	buffer[count++] = cpu_to_le32(0x80000000); +	buffer[count++] = cpu_to_le32(0x80000000);  	for (sect = rdev->rlc.cs_data; sect->section != NULL; ++sect) {  		for (ext = sect->section; ext->extent != NULL; ++ext) {  			if (sect->id == SECT_CONTEXT) { -				buffer[count++] = PACKET3(PACKET3_SET_CONTEXT_REG, ext->reg_count); -				buffer[count++] = ext->reg_index - 0xa000; +				buffer[count++] = +					cpu_to_le32(PACKET3(PACKET3_SET_CONTEXT_REG, ext->reg_count)); +				buffer[count++] = cpu_to_le32(ext->reg_index - 0xa000);  				for (i = 0; i < ext->reg_count; i++) -					buffer[count++] = ext->extent[i]; +					buffer[count++] = cpu_to_le32(ext->extent[i]);  			} else {  				return;  			}  		}  	} -	buffer[count++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); -	buffer[count++] = PA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_SET_CONTEXT_REG, 1)); +	buffer[count++] = cpu_to_le32(PA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START);  	switch (rdev->family) {  	case CHIP_TAHITI:  	case CHIP_PITCAIRN: -		buffer[count++] = 0x2a00126a; +		buffer[count++] = cpu_to_le32(0x2a00126a);  		break;  	case CHIP_VERDE: -		buffer[count++] = 0x0000124a; +		buffer[count++] = cpu_to_le32(0x0000124a);  		break;  	case CHIP_OLAND: -		buffer[count++] = 0x00000082; +		buffer[count++] = cpu_to_le32(0x00000082);  		break;  	case CHIP_HAINAN: -		buffer[count++] = 0x00000000; +		buffer[count++] = cpu_to_le32(0x00000000);  		break;  	default: -		buffer[count++] = 0x00000000; +		buffer[count++] = cpu_to_le32(0x00000000);  		break;  	} -	buffer[count++] = PACKET3(PACKET3_PREAMBLE_CNTL, 0); -	buffer[count++] = PACKET3_PREAMBLE_END_CLEAR_STATE; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0)); +	buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_END_CLEAR_STATE); -	buffer[count++] = PACKET3(PACKET3_CLEAR_STATE, 0); -	buffer[count++] = 0; +	buffer[count++] = cpu_to_le32(PACKET3(PACKET3_CLEAR_STATE, 0)); +	buffer[count++] = cpu_to_le32(0);  }  static void si_init_pg(struct radeon_device *rdev) @@ -5418,6 +5508,9 @@ static void si_init_pg(struct radeon_device *rdev)  		si_init_ao_cu_mask(rdev);  		if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG) {  			si_init_gfx_cgpg(rdev); +		} else { +			WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8); +			WREG32(RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);  		}  		si_enable_dma_pg(rdev, true);  		si_enable_gfx_cgpg(rdev, true); @@ -5605,7 +5698,7 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)  	}  	if (!ASIC_IS_NODCE(rdev)) { -		WREG32(DACA_AUTODETECT_INT_CONTROL, 0); +		WREG32(DAC_AUTODETECT_INT_CONTROL, 0);  		tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;  		WREG32(DC_HPD1_INT_CONTROL, tmp); @@ -5700,7 +5793,6 @@ int si_irq_set(struct radeon_device *rdev)  	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;  	u32 hpd1 = 0, hpd2 = 0, hpd3 = 0, hpd4 = 0, hpd5 = 0, hpd6 = 0;  	u32 grbm_int_cntl = 0; -	u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;  	u32 dma_cntl, dma_cntl1;  	u32 thermal_int = 0; @@ -5839,16 +5931,22 @@ int si_irq_set(struct radeon_device *rdev)  	}  	if (rdev->num_crtc >= 2) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	if (rdev->num_crtc >= 4) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	if (rdev->num_crtc >= 6) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	if (!ASIC_IS_NODCE(rdev)) { @@ -6005,6 +6103,7 @@ static inline u32 si_get_ih_wptr(struct radeon_device *rdev)  		tmp = RREG32(IH_RB_CNTL);  		tmp |= IH_WPTR_OVERFLOW_CLEAR;  		WREG32(IH_RB_CNTL, tmp); +		wptr &= ~RB_OVERFLOW;  	}  	return (wptr & rdev->ih.ptr_mask);  } @@ -6066,7 +6165,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[0])) -						radeon_crtc_handle_flip(rdev, 0); +						radeon_crtc_handle_vblank(rdev, 0);  					rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D1 vblank\n");  				} @@ -6092,7 +6191,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[1])) -						radeon_crtc_handle_flip(rdev, 1); +						radeon_crtc_handle_vblank(rdev, 1);  					rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D2 vblank\n");  				} @@ -6118,7 +6217,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[2])) -						radeon_crtc_handle_flip(rdev, 2); +						radeon_crtc_handle_vblank(rdev, 2);  					rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D3 vblank\n");  				} @@ -6144,7 +6243,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[3])) -						radeon_crtc_handle_flip(rdev, 3); +						radeon_crtc_handle_vblank(rdev, 3);  					rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D4 vblank\n");  				} @@ -6170,7 +6269,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[4])) -						radeon_crtc_handle_flip(rdev, 4); +						radeon_crtc_handle_vblank(rdev, 4);  					rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D5 vblank\n");  				} @@ -6196,7 +6295,7 @@ restart_ih:  						wake_up(&rdev->irq.vblank_queue);  					}  					if (atomic_read(&rdev->irq.pflip[5])) -						radeon_crtc_handle_flip(rdev, 5); +						radeon_crtc_handle_vblank(rdev, 5);  					rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;  					DRM_DEBUG("IH: D6 vblank\n");  				} @@ -6212,6 +6311,15 @@ restart_ih:  				break;  			}  			break; +		case 8: /* D1 page flip */ +		case 10: /* D2 page flip */ +		case 12: /* D3 page flip */ +		case 14: /* D4 page flip */ +		case 16: /* D5 page flip */ +		case 18: /* D6 page flip */ +			DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); +			radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); +			break;  		case 42: /* HPD hotplug */  			switch (src_data) {  			case 0: @@ -6261,18 +6369,24 @@ restart_ih:  				break;  			}  			break; +		case 124: /* UVD */ +			DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); +			radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); +			break;  		case 146:  		case 147:  			addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);  			status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS); +			/* reset addr and status */ +			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); +			if (addr == 0x0 && status == 0x0) +				break;  			dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);  			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",  				addr);  			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",  				status);  			si_vm_decode_fault(rdev, status, addr); -			/* reset addr and status */ -			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);  			break;  		case 176: /* RINGID0 CP_INT */  			radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); @@ -6363,21 +6477,14 @@ static int si_startup(struct radeon_device *rdev)  	si_mc_program(rdev); -	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || -	    !rdev->rlc_fw || !rdev->mc_fw) { -		r = si_init_microcode(rdev); +	if (!rdev->pm.dpm_enabled) { +		r = si_mc_load_microcode(rdev);  		if (r) { -			DRM_ERROR("Failed to load firmware!\n"); +			DRM_ERROR("Failed to load MC firmware!\n");  			return r;  		}  	} -	r = si_mc_load_microcode(rdev); -	if (r) { -		DRM_ERROR("Failed to load MC firmware!\n"); -		return r; -	} -  	r = si_pcie_gart_enable(rdev);  	if (r)  		return r; @@ -6460,37 +6567,30 @@ static int si_startup(struct radeon_device *rdev)  	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, -			     CP_RB0_RPTR, CP_RB0_WPTR,  			     RADEON_CP_PACKET2);  	if (r)  		return r;  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET, -			     CP_RB1_RPTR, CP_RB1_WPTR,  			     RADEON_CP_PACKET2);  	if (r)  		return r;  	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET, -			     CP_RB2_RPTR, CP_RB2_WPTR,  			     RADEON_CP_PACKET2);  	if (r)  		return r;  	ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, -			     DMA_RB_RPTR + DMA0_REGISTER_OFFSET, -			     DMA_RB_WPTR + DMA0_REGISTER_OFFSET,  			     DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0));  	if (r)  		return r;  	ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];  	r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET, -			     DMA_RB_RPTR + DMA1_REGISTER_OFFSET, -			     DMA_RB_WPTR + DMA1_REGISTER_OFFSET,  			     DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0));  	if (r)  		return r; @@ -6510,7 +6610,6 @@ static int si_startup(struct radeon_device *rdev)  		ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];  		if (ring->ring_size) {  			r = radeon_ring_init(rdev, ring, ring->ring_size, 0, -					     UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,  					     RADEON_CP_PACKET2);  			if (!r)  				r = uvd_v1_0_init(rdev); @@ -6552,6 +6651,9 @@ int si_resume(struct radeon_device *rdev)  	/* init golden registers */  	si_init_golden_registers(rdev); +	if (rdev->pm.pm_method == PM_METHOD_DPM) +		radeon_pm_resume(rdev); +  	rdev->accel_working = true;  	r = si_startup(rdev);  	if (r) { @@ -6566,6 +6668,7 @@ int si_resume(struct radeon_device *rdev)  int si_suspend(struct radeon_device *rdev)  { +	radeon_pm_suspend(rdev);  	dce6_audio_fini(rdev);  	radeon_vm_manager_fini(rdev);  	si_cp_enable(rdev, false); @@ -6639,6 +6742,18 @@ int si_init(struct radeon_device *rdev)  	if (r)  		return r; +	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || +	    !rdev->rlc_fw || !rdev->mc_fw) { +		r = si_init_microcode(rdev); +		if (r) { +			DRM_ERROR("Failed to load firmware!\n"); +			return r; +		} +	} + +	/* Initialize power management */ +	radeon_pm_init(rdev); +  	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];  	ring->ring_obj = NULL;  	r600_ring_init(rdev, ring, 1024 * 1024); @@ -6705,6 +6820,7 @@ int si_init(struct radeon_device *rdev)  void si_fini(struct radeon_device *rdev)  { +	radeon_pm_fini(rdev);  	si_cp_fini(rdev);  	cayman_dma_fini(rdev);  	si_fini_pg(rdev); diff --git a/drivers/gpu/drm/radeon/si_dma.c b/drivers/gpu/drm/radeon/si_dma.c index 49909d23dfc..e24c94b6d14 100644 --- a/drivers/gpu/drm/radeon/si_dma.c +++ b/drivers/gpu/drm/radeon/si_dma.c @@ -24,6 +24,7 @@  #include <drm/drmP.h>  #include "radeon.h"  #include "radeon_asic.h" +#include "radeon_trace.h"  #include "sid.h"  u32 si_gpu_check_soft_reset(struct radeon_device *rdev); @@ -48,11 +49,9 @@ bool si_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)  		mask = RADEON_RESET_DMA1;  	if (!(reset_mask & mask)) { -		radeon_ring_lockup_update(ring); +		radeon_ring_lockup_update(rdev, ring);  		return false;  	} -	/* force ring activities */ -	radeon_ring_force_activity(rdev, ring);  	return radeon_ring_test_lockup(rdev, ring);  } @@ -75,11 +74,30 @@ void si_dma_vm_set_page(struct radeon_device *rdev,  			uint64_t addr, unsigned count,  			uint32_t incr, uint32_t flags)  { -	uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);  	uint64_t value;  	unsigned ndw; -	if (flags & RADEON_VM_PAGE_SYSTEM) { +	trace_radeon_vm_set_page(pe, addr, count, incr, flags); + +	if (flags == R600_PTE_GART) { +		uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8; +		while (count) { +			unsigned bytes = count * 8; +			if (bytes > 0xFFFF8) +				bytes = 0xFFFF8; + +			ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY, +							      1, 0, 0, bytes); +			ib->ptr[ib->length_dw++] = lower_32_bits(pe); +			ib->ptr[ib->length_dw++] = lower_32_bits(src); +			ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; +			ib->ptr[ib->length_dw++] = upper_32_bits(src) & 0xff; + +			pe += bytes; +			src += bytes; +			count -= bytes / 8; +		} +	} else if (flags & R600_PTE_SYSTEM) {  		while (count) {  			ndw = count * 2;  			if (ndw > 0xFFFFE) @@ -90,16 +108,10 @@ void si_dma_vm_set_page(struct radeon_device *rdev,  			ib->ptr[ib->length_dw++] = pe;  			ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff;  			for (; ndw > 0; ndw -= 2, --count, pe += 8) { -				if (flags & RADEON_VM_PAGE_SYSTEM) { -					value = radeon_vm_map_gart(rdev, addr); -					value &= 0xFFFFFFFFFFFFF000ULL; -				} else if (flags & RADEON_VM_PAGE_VALID) { -					value = addr; -				} else { -					value = 0; -				} +				value = radeon_vm_map_gart(rdev, addr); +				value &= 0xFFFFFFFFFFFFF000ULL;  				addr += incr; -				value |= r600_flags; +				value |= flags;  				ib->ptr[ib->length_dw++] = value;  				ib->ptr[ib->length_dw++] = upper_32_bits(value);  			} @@ -110,7 +122,7 @@ void si_dma_vm_set_page(struct radeon_device *rdev,  			if (ndw > 0xFFFFE)  				ndw = 0xFFFFE; -			if (flags & RADEON_VM_PAGE_VALID) +			if (flags & R600_PTE_VALID)  				value = addr;  			else  				value = 0; @@ -118,7 +130,7 @@ void si_dma_vm_set_page(struct radeon_device *rdev,  			ib->ptr[ib->length_dw++] = DMA_PTE_PDE_PACKET(ndw);  			ib->ptr[ib->length_dw++] = pe; /* dst addr */  			ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; -			ib->ptr[ib->length_dw++] = r600_flags; /* mask */ +			ib->ptr[ib->length_dw++] = flags; /* mask */  			ib->ptr[ib->length_dw++] = 0;  			ib->ptr[ib->length_dw++] = value; /* value */  			ib->ptr[ib->length_dw++] = upper_32_bits(value); @@ -199,13 +211,8 @@ int si_copy_dma(struct radeon_device *rdev,  		return r;  	} -	if (radeon_fence_need_sync(*fence, ring->idx)) { -		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, -					    ring->idx); -		radeon_fence_note_sync(*fence, ring->idx); -	} else { -		radeon_semaphore_free(rdev, &sem, NULL); -	} +	radeon_semaphore_sync_to(sem, *fence); +	radeon_semaphore_sync_rings(rdev, sem, ring->idx);  	for (i = 0; i < num_loops; i++) {  		cur_size_in_bytes = size_in_bytes; @@ -213,8 +220,8 @@ int si_copy_dma(struct radeon_device *rdev,  			cur_size_in_bytes = 0xFFFFF;  		size_in_bytes -= cur_size_in_bytes;  		radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 1, 0, 0, cur_size_in_bytes)); -		radeon_ring_write(ring, dst_offset & 0xffffffff); -		radeon_ring_write(ring, src_offset & 0xffffffff); +		radeon_ring_write(ring, lower_32_bits(dst_offset)); +		radeon_ring_write(ring, lower_32_bits(src_offset));  		radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff);  		radeon_ring_write(ring, upper_32_bits(src_offset) & 0xff);  		src_offset += cur_size_in_bytes; @@ -224,6 +231,7 @@ int si_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 9ace28702c7..58918868f89 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1738,6 +1738,8 @@ struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);  struct ni_power_info *ni_get_pi(struct radeon_device *rdev);  struct ni_ps *ni_get_ps(struct radeon_ps *rps); +extern int si_mc_load_microcode(struct radeon_device *rdev); +  static int si_populate_voltage_value(struct radeon_device *rdev,  				     const struct atom_voltage_table *table,  				     u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage); @@ -1753,9 +1755,6 @@ static int si_calculate_sclk_params(struct radeon_device *rdev,  				    u32 engine_clock,  				    SISLANDS_SMC_SCLK_VALUE *sclk); -extern void si_update_cg(struct radeon_device *rdev, -			 u32 block, bool enable); -  static struct si_power_info *si_get_pi(struct radeon_device *rdev)  {          struct si_power_info *pi = rdev->pm.dpm.priv; @@ -1949,6 +1948,10 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)  			si_pi->cac_weights = cac_weights_cape_verde_pro;  			si_pi->dte_data = dte_data_cape_verde;  			break; +		case 0x682C: +			si_pi->cac_weights = cac_weights_cape_verde_pro; +			si_pi->dte_data = dte_data_sun_xt; +			break;  		case 0x6825:  		case 0x6827:  			si_pi->cac_weights = cac_weights_heathrow; @@ -1972,10 +1975,9 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)  			si_pi->dte_data = dte_data_venus_xt;  			break;  		case 0x6823: -			si_pi->cac_weights = cac_weights_chelsea_pro; -			si_pi->dte_data = dte_data_venus_pro; -			break;  		case 0x682B: +		case 0x6822: +		case 0x682A:  			si_pi->cac_weights = cac_weights_chelsea_pro;  			si_pi->dte_data = dte_data_venus_pro;  			break; @@ -1989,6 +1991,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)  		case 0x6601:  		case 0x6621:  		case 0x6603: +		case 0x6605:  			si_pi->cac_weights = cac_weights_mars_pro;  			si_pi->lcac_config = lcac_mars_pro;  			si_pi->cac_override = cac_override_oland; @@ -1999,6 +2002,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)  		case 0x6600:  		case 0x6606:  		case 0x6620: +		case 0x6604:  			si_pi->cac_weights = cac_weights_mars_xt;  			si_pi->lcac_config = lcac_mars_pro;  			si_pi->cac_override = cac_override_oland; @@ -2007,6 +2011,8 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)  			update_dte_from_pl2 = true;  			break;  		case 0x6611: +		case 0x6613: +		case 0x6608:  			si_pi->cac_weights = cac_weights_oland_pro;  			si_pi->lcac_config = lcac_mars_pro;  			si_pi->cac_override = cac_override_oland; @@ -2396,7 +2402,7 @@ static int si_populate_sq_ramping_values(struct radeon_device *rdev,  	if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))  		enable_sq_ramping = false; -	if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) +	if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))  		enable_sq_ramping = false;  	for (i = 0; i < state->performance_level_count; i++) { @@ -3589,6 +3595,10 @@ static void si_program_display_gap(struct radeon_device *rdev)  		WREG32(DCCG_DISP_SLOW_SELECT_REG, tmp);  	} +	/* Setting this to false forces the performance state to low if the crtcs are disabled. +	 * This can be a problem on PowerXpress systems or if you want to use the card +	 * for offscreen rendering or compute if there are no crtcs enabled. +	 */  	si_notify_smc_display_change(rdev, rdev->pm.dpm.new_active_crtc_count > 0);  } @@ -4553,7 +4563,7 @@ static int si_init_smc_table(struct radeon_device *rdev)  		table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;  	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY) -		table->systemFlags |= PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH; +		table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH;  	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE) {  		table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT_PROG_GPIO; @@ -5208,7 +5218,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,  					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;  			}  			j++; -			if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) +			if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)  				return -EINVAL;  			if (!pi->mem_gddr5) { @@ -5218,7 +5228,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,  					table->mc_reg_table_entry[k].mc_data[j] =  						(table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;  				j++; -				if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) +				if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)  					return -EINVAL;  			}  			break; @@ -5231,7 +5241,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,  					(temp_reg & 0xffff0000) |  					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);  			j++; -			if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) +			if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)  				return -EINVAL;  			break;  		default: @@ -5409,7 +5419,7 @@ static void si_populate_mc_reg_addresses(struct radeon_device *rdev,  	for (i = 0, j = 0; j < si_pi->mc_reg_table.last; j++) {  		if (si_pi->mc_reg_table.valid_flag & (1 << j)) { -			if (i >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE) +			if (i >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)  				break;  			mc_reg_table->address[i].s0 =  				cpu_to_be16(si_pi->mc_reg_table.mc_reg_address[j].s0); @@ -5749,6 +5759,11 @@ static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev,  void si_dpm_setup_asic(struct radeon_device *rdev)  { +	int r; + +	r = si_mc_load_microcode(rdev); +	if (r) +		DRM_ERROR("Failed to load MC firmware!\n");  	rv770_get_memory_type(rdev);  	si_read_clock_registers(rdev);  	si_enable_acpi_power_management(rdev); @@ -5786,13 +5801,6 @@ int si_dpm_enable(struct radeon_device *rdev)  	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;  	int ret; -	si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			    RADEON_CG_BLOCK_MC | -			    RADEON_CG_BLOCK_SDMA | -			    RADEON_CG_BLOCK_BIF | -			    RADEON_CG_BLOCK_UVD | -			    RADEON_CG_BLOCK_HDP), false); -  	if (si_is_smc_running(rdev))  		return -EINVAL;  	if (pi->voltage_control) @@ -5895,6 +5903,17 @@ int si_dpm_enable(struct radeon_device *rdev)  	si_enable_sclk_control(rdev, true);  	si_start_dpm(rdev); +	si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); + +	ni_update_current_ps(rdev, boot_ps); + +	return 0; +} + +int si_dpm_late_enable(struct radeon_device *rdev) +{ +	int ret; +  	if (rdev->irq.installed &&  	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {  		PPSMC_Result result; @@ -5910,17 +5929,6 @@ int si_dpm_enable(struct radeon_device *rdev)  			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");  	} -	si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); - -	si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			    RADEON_CG_BLOCK_MC | -			    RADEON_CG_BLOCK_SDMA | -			    RADEON_CG_BLOCK_BIF | -			    RADEON_CG_BLOCK_UVD | -			    RADEON_CG_BLOCK_HDP), true); - -	ni_update_current_ps(rdev, boot_ps); -  	return 0;  } @@ -5929,13 +5937,6 @@ void si_dpm_disable(struct radeon_device *rdev)  	struct rv7xx_power_info *pi = rv770_get_pi(rdev);  	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; -	si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			    RADEON_CG_BLOCK_MC | -			    RADEON_CG_BLOCK_SDMA | -			    RADEON_CG_BLOCK_BIF | -			    RADEON_CG_BLOCK_UVD | -			    RADEON_CG_BLOCK_HDP), false); -  	if (!si_is_smc_running(rdev))  		return;  	si_disable_ulv(rdev); @@ -6000,13 +6001,6 @@ int si_dpm_set_power_state(struct radeon_device *rdev)  	struct radeon_ps *old_ps = &eg_pi->current_rps;  	int ret; -	si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			    RADEON_CG_BLOCK_MC | -			    RADEON_CG_BLOCK_SDMA | -			    RADEON_CG_BLOCK_BIF | -			    RADEON_CG_BLOCK_UVD | -			    RADEON_CG_BLOCK_HDP), false); -  	ret = si_disable_ulv(rdev);  	if (ret) {  		DRM_ERROR("si_disable_ulv failed\n"); @@ -6099,13 +6093,6 @@ int si_dpm_set_power_state(struct radeon_device *rdev)  		return ret;  	} -	si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | -			    RADEON_CG_BLOCK_MC | -			    RADEON_CG_BLOCK_SDMA | -			    RADEON_CG_BLOCK_BIF | -			    RADEON_CG_BLOCK_UVD | -			    RADEON_CG_BLOCK_HDP), true); -  	return 0;  } @@ -6291,9 +6278,6 @@ static int si_parse_power_table(struct radeon_device *rdev)  	if (!rdev->pm.dpm.ps)  		return -ENOMEM;  	power_state_offset = (u8 *)state_array->states; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < state_array->ucNumEntries; i++) {  		u8 *idx;  		power_state = (union pplib_power_state *)power_state_offset; @@ -6370,6 +6354,10 @@ int si_dpm_init(struct radeon_device *rdev)  	pi->min_vddc_in_table = 0;  	pi->max_vddc_in_table = 0; +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = si_parse_power_table(rdev);  	if (ret)  		return ret; @@ -6492,7 +6480,8 @@ void si_dpm_fini(struct radeon_device *rdev)  void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,  						    struct seq_file *m)  { -	struct radeon_ps *rps = rdev->pm.dpm.current_ps; +	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); +	struct radeon_ps *rps = &eg_pi->current_rps;  	struct ni_ps *ps = ni_get_ps(rps);  	struct rv7xx_pl *pl;  	u32 current_index = diff --git a/drivers/gpu/drm/radeon/si_smc.c b/drivers/gpu/drm/radeon/si_smc.c index d422a1cbf72..e80efcf0c23 100644 --- a/drivers/gpu/drm/radeon/si_smc.c +++ b/drivers/gpu/drm/radeon/si_smc.c @@ -28,6 +28,7 @@  #include "sid.h"  #include "ppsmc.h"  #include "radeon_ucode.h" +#include "sislands_smc.h"  static int si_set_smc_sram_address(struct radeon_device *rdev,  				   u32 smc_address, u32 limit) diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 52d2ab6b67a..fd414d34d88 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -94,6 +94,8 @@  #define	CG_SPLL_FUNC_CNTL_2				0x604  #define		SCLK_MUX_SEL(x)				((x) << 0)  #define		SCLK_MUX_SEL_MASK			(0x1ff << 0) +#define		SPLL_CTLREQ_CHG				(1 << 23) +#define		SCLK_MUX_UPDATE				(1 << 26)  #define	CG_SPLL_FUNC_CNTL_3				0x608  #define		SPLL_FB_DIV(x)				((x) << 0)  #define		SPLL_FB_DIV_MASK			(0x3ffffff << 0) @@ -101,9 +103,12 @@  #define		SPLL_DITHEN				(1 << 28)  #define	CG_SPLL_FUNC_CNTL_4				0x60c +#define	SPLL_STATUS					0x614 +#define		SPLL_CHG_STATUS				(1 << 1)  #define	SPLL_CNTL_MODE					0x618 -#	define SPLL_REFCLK_SEL(x)			((x) << 8) -#	define SPLL_REFCLK_SEL_MASK			0xFF00 +#define		SPLL_SW_DIR_CONTROL			(1 << 0) +#	define SPLL_REFCLK_SEL(x)			((x) << 26) +#	define SPLL_REFCLK_SEL_MASK			(3 << 26)  #define	CG_SPLL_SPREAD_SPECTRUM				0x620  #define		SSEN					(1 << 0) @@ -357,6 +362,7 @@  #define		READ_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 16)  #define		WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT		(1 << 18)  #define		WRITE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 19) +#define		PAGE_TABLE_BLOCK_SIZE(x)			(((x) & 0xF) << 24)  #define VM_CONTEXT1_CNTL				0x1414  #define VM_CONTEXT0_CNTL2				0x1430  #define VM_CONTEXT1_CNTL2				0x1434 @@ -478,7 +484,7 @@  #define		STATE3_MASK				(0x1f << 15)  #define		STATE3_SHIFT				15 -#define	MC_SEQ_TRAIN_WAKEUP_CNTL			0x2808 +#define	MC_SEQ_TRAIN_WAKEUP_CNTL			0x28e8  #define		TRAIN_DONE_D0      			(1 << 30)  #define		TRAIN_DONE_D1      			(1 << 31) @@ -559,6 +565,8 @@  #       define MRDCK0_BYPASS                            (1 << 24)  #       define MRDCK1_BYPASS                            (1 << 25) +#define	MPLL_CNTL_MODE					0x2bb0 +#       define MPLL_MCLK_SEL                            (1 << 11)  #define	MPLL_FUNC_CNTL					0x2bb4  #define		BWCTRL(x)				((x) << 20)  #define		BWCTRL_MASK				(0xff << 20) @@ -683,6 +691,51 @@   * bit5 = 176.4 kHz   * bit6 = 192 kHz   */ + +#define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC         0x37 +#       define VIDEO_LIPSYNC(x)                           (((x) & 0xff) << 0) +#       define AUDIO_LIPSYNC(x)                           (((x) & 0xff) << 8) +/* VIDEO_LIPSYNC, AUDIO_LIPSYNC + * 0   = invalid + * x   = legal delay value + * 255 = sync not supported + */ +#define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_HBR             0x38 +#       define HBR_CAPABLE                                (1 << 0) /* enabled by default */ + +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO0               0x3a +#       define MANUFACTURER_ID(x)                        (((x) & 0xffff) << 0) +#       define PRODUCT_ID(x)                             (((x) & 0xffff) << 16) +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO1               0x3b +#       define SINK_DESCRIPTION_LEN(x)                   (((x) & 0xff) << 0) +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO2               0x3c +#       define PORT_ID0(x)                               (((x) & 0xffffffff) << 0) +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO3               0x3d +#       define PORT_ID1(x)                               (((x) & 0xffffffff) << 0) +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO4               0x3e +#       define DESCRIPTION0(x)                           (((x) & 0xff) << 0) +#       define DESCRIPTION1(x)                           (((x) & 0xff) << 8) +#       define DESCRIPTION2(x)                           (((x) & 0xff) << 16) +#       define DESCRIPTION3(x)                           (((x) & 0xff) << 24) +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO5               0x3f +#       define DESCRIPTION4(x)                           (((x) & 0xff) << 0) +#       define DESCRIPTION5(x)                           (((x) & 0xff) << 8) +#       define DESCRIPTION6(x)                           (((x) & 0xff) << 16) +#       define DESCRIPTION7(x)                           (((x) & 0xff) << 24) +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO6               0x40 +#       define DESCRIPTION8(x)                           (((x) & 0xff) << 0) +#       define DESCRIPTION9(x)                           (((x) & 0xff) << 8) +#       define DESCRIPTION10(x)                          (((x) & 0xff) << 16) +#       define DESCRIPTION11(x)                          (((x) & 0xff) << 24) +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO7               0x41 +#       define DESCRIPTION12(x)                          (((x) & 0xff) << 0) +#       define DESCRIPTION13(x)                          (((x) & 0xff) << 8) +#       define DESCRIPTION14(x)                          (((x) & 0xff) << 16) +#       define DESCRIPTION15(x)                          (((x) & 0xff) << 24) +#define AZ_F0_CODEC_PIN_CONTROL_SINK_INFO8               0x42 +#       define DESCRIPTION16(x)                          (((x) & 0xff) << 0) +#       define DESCRIPTION17(x)                          (((x) & 0xff) << 8) +  #define AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL          0x54  #       define AUDIO_ENABLED                             (1 << 31) @@ -770,7 +823,7 @@  #       define GRPH_PFLIP_INT_MASK                      (1 << 0)  #       define GRPH_PFLIP_INT_TYPE                      (1 << 8) -#define	DACA_AUTODETECT_INT_CONTROL			0x66c8 +#define	DAC_AUTODETECT_INT_CONTROL			0x67c8  #define DC_HPD1_INT_STATUS                              0x601c  #define DC_HPD2_INT_STATUS                              0x6028 @@ -1553,7 +1606,7 @@   * 6. COMMAND [30:21] | BYTE_COUNT [20:0]   */  #              define PACKET3_CP_DMA_DST_SEL(x)    ((x) << 20) -                /* 0 - SRC_ADDR +                /* 0 - DST_ADDR  		 * 1 - GDS  		 */  #              define PACKET3_CP_DMA_ENGINE(x)     ((x) << 27) @@ -1568,7 +1621,7 @@  #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)  /* COMMAND */  #              define PACKET3_CP_DMA_DIS_WC        (1 << 21) -#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23) +#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)                  /* 0 - none  		 * 1 - 8 in 16  		 * 2 - 8 in 32 @@ -1746,4 +1799,51 @@  #define	DMA_PACKET_CONSTANT_FILL			  0xd  #define	DMA_PACKET_NOP					  0xf +#define VCE_STATUS					0x20004 +#define VCE_VCPU_CNTL					0x20014 +#define		VCE_CLK_EN				(1 << 0) +#define VCE_VCPU_CACHE_OFFSET0				0x20024 +#define VCE_VCPU_CACHE_SIZE0				0x20028 +#define VCE_VCPU_CACHE_OFFSET1				0x2002c +#define VCE_VCPU_CACHE_SIZE1				0x20030 +#define VCE_VCPU_CACHE_OFFSET2				0x20034 +#define VCE_VCPU_CACHE_SIZE2				0x20038 +#define VCE_SOFT_RESET					0x20120 +#define 	VCE_ECPU_SOFT_RESET			(1 << 0) +#define 	VCE_FME_SOFT_RESET			(1 << 2) +#define VCE_RB_BASE_LO2					0x2016c +#define VCE_RB_BASE_HI2					0x20170 +#define VCE_RB_SIZE2					0x20174 +#define VCE_RB_RPTR2					0x20178 +#define VCE_RB_WPTR2					0x2017c +#define VCE_RB_BASE_LO					0x20180 +#define VCE_RB_BASE_HI					0x20184 +#define VCE_RB_SIZE					0x20188 +#define VCE_RB_RPTR					0x2018c +#define VCE_RB_WPTR					0x20190 +#define VCE_CLOCK_GATING_A				0x202f8 +#define VCE_CLOCK_GATING_B				0x202fc +#define VCE_UENC_CLOCK_GATING				0x205bc +#define VCE_UENC_REG_CLOCK_GATING			0x205c0 +#define VCE_FW_REG_STATUS				0x20e10 +#	define VCE_FW_REG_STATUS_BUSY			(1 << 0) +#	define VCE_FW_REG_STATUS_PASS			(1 << 3) +#	define VCE_FW_REG_STATUS_DONE			(1 << 11) +#define VCE_LMI_FW_START_KEYSEL				0x20e18 +#define VCE_LMI_FW_PERIODIC_CTRL			0x20e20 +#define VCE_LMI_CTRL2					0x20e74 +#define VCE_LMI_CTRL					0x20e98 +#define VCE_LMI_VM_CTRL					0x20ea0 +#define VCE_LMI_SWAP_CNTL				0x20eb4 +#define VCE_LMI_SWAP_CNTL1				0x20eb8 +#define VCE_LMI_CACHE_CTRL				0x20ef4 + +#define VCE_CMD_NO_OP					0x00000000 +#define VCE_CMD_END					0x00000001 +#define VCE_CMD_IB					0x00000002 +#define VCE_CMD_FENCE					0x00000003 +#define VCE_CMD_TRAP					0x00000004 +#define VCE_CMD_IB_AUTO					0x00000005 +#define VCE_CMD_SEMAPHORE				0x00000006 +  #endif diff --git a/drivers/gpu/drm/radeon/sislands_smc.h b/drivers/gpu/drm/radeon/sislands_smc.h index 5578e983702..10e945a4947 100644 --- a/drivers/gpu/drm/radeon/sislands_smc.h +++ b/drivers/gpu/drm/radeon/sislands_smc.h @@ -374,8 +374,6 @@ typedef struct Smc_SIslands_DTE_Configuration Smc_SIslands_DTE_Configuration;  #pragma pack(pop) -int si_set_smc_sram_address(struct radeon_device *rdev, -			    u32 smc_address, u32 limit);  int si_copy_bytes_to_smc(struct radeon_device *rdev,  			 u32 smc_start_address,  			 const u8 *src, u32 byte_count, u32 limit); diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index 96ea6db8bf5..3f0e8d7b8db 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -71,7 +71,7 @@ static const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] =  	SUMO_DTC_DFLT_14,  }; -struct sumo_ps *sumo_get_ps(struct radeon_ps *rps) +static struct sumo_ps *sumo_get_ps(struct radeon_ps *rps)  {  	struct sumo_ps *ps = rps->ps_priv; @@ -1202,14 +1202,10 @@ static void sumo_update_requested_ps(struct radeon_device *rdev,  int sumo_dpm_enable(struct radeon_device *rdev)  {  	struct sumo_power_info *pi = sumo_get_pi(rdev); -	int ret;  	if (sumo_dpm_enabled(rdev))  		return -EINVAL; -	ret = sumo_enable_clock_power_gating(rdev); -	if (ret) -		return ret;  	sumo_program_bootup_state(rdev);  	sumo_init_bsp(rdev);  	sumo_reset_am(rdev); @@ -1233,6 +1229,19 @@ int sumo_dpm_enable(struct radeon_device *rdev)  	if (pi->enable_boost)  		sumo_enable_boost_timer(rdev); +	sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps); + +	return 0; +} + +int sumo_dpm_late_enable(struct radeon_device *rdev) +{ +	int ret; + +	ret = sumo_enable_clock_power_gating(rdev); +	if (ret) +		return ret; +  	if (rdev->irq.installed &&  	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {  		ret = sumo_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); @@ -1242,8 +1251,6 @@ int sumo_dpm_enable(struct radeon_device *rdev)  		radeon_irq_set(rdev);  	} -	sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps); -  	return 0;  } @@ -1477,9 +1484,6 @@ static int sumo_parse_power_table(struct radeon_device *rdev)  	if (!rdev->pm.dpm.ps)  		return -ENOMEM;  	power_state_offset = (u8 *)state_array->states; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < state_array->ucNumEntries; i++) {  		u8 *idx;  		power_state = (union pplib_power_state *)power_state_offset; @@ -1765,6 +1769,10 @@ int sumo_dpm_init(struct radeon_device *rdev)  	sumo_construct_boot_and_acpi_state(rdev); +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = sumo_parse_power_table(rdev);  	if (ret)  		return ret; @@ -1800,7 +1808,7 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev  						      struct seq_file *m)  {  	struct sumo_power_info *pi = sumo_get_pi(rdev); -	struct radeon_ps *rps = rdev->pm.dpm.current_ps; +	struct radeon_ps *rps = &pi->current_rps;  	struct sumo_ps *ps = sumo_get_ps(rps);  	struct sumo_pl *pl;  	u32 current_index = diff --git a/drivers/gpu/drm/radeon/sumo_smc.c b/drivers/gpu/drm/radeon/sumo_smc.c index 18abba5b581..fb081d2ae37 100644 --- a/drivers/gpu/drm/radeon/sumo_smc.c +++ b/drivers/gpu/drm/radeon/sumo_smc.c @@ -31,7 +31,6 @@  #define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY  27  #define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20  20 -struct sumo_ps *sumo_get_ps(struct radeon_ps *rps);  struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev);  static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id) diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 7f998bf1cc9..32e50be9c4a 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -342,14 +342,14 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,  					     struct radeon_ps *new_rps,  					     struct radeon_ps *old_rps); -struct trinity_ps *trinity_get_ps(struct radeon_ps *rps) +static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)  {  	struct trinity_ps *ps = rps->ps_priv;  	return ps;  } -struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev) +static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)  {  	struct trinity_power_info *pi = rdev->pm.dpm.priv; @@ -1082,7 +1082,6 @@ void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable)  int trinity_dpm_enable(struct radeon_device *rdev)  {  	struct trinity_power_info *pi = trinity_get_pi(rdev); -	int ret;  	trinity_acquire_mutex(rdev); @@ -1091,7 +1090,6 @@ int trinity_dpm_enable(struct radeon_device *rdev)  		return -EINVAL;  	} -	trinity_enable_clock_power_gating(rdev);  	trinity_program_bootup_state(rdev);  	sumo_program_vc(rdev, 0x00C00033);  	trinity_start_am(rdev); @@ -1105,6 +1103,18 @@ int trinity_dpm_enable(struct radeon_device *rdev)  	trinity_dpm_bapm_enable(rdev, false);  	trinity_release_mutex(rdev); +	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps); + +	return 0; +} + +int trinity_dpm_late_enable(struct radeon_device *rdev) +{ +	int ret; + +	trinity_acquire_mutex(rdev); +	trinity_enable_clock_power_gating(rdev); +  	if (rdev->irq.installed &&  	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {  		ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); @@ -1115,8 +1125,7 @@ int trinity_dpm_enable(struct radeon_device *rdev)  		rdev->irq.dpm_thermal = true;  		radeon_irq_set(rdev);  	} - -	trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps); +	trinity_release_mutex(rdev);  	return 0;  } @@ -1685,9 +1694,6 @@ static int trinity_parse_power_table(struct radeon_device *rdev)  	if (!rdev->pm.dpm.ps)  		return -ENOMEM;  	power_state_offset = (u8 *)state_array->states; -	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); -	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); -	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);  	for (i = 0; i < state_array->ucNumEntries; i++) {  		u8 *idx;  		power_state = (union pplib_power_state *)power_state_offset; @@ -1868,14 +1874,23 @@ int trinity_dpm_init(struct radeon_device *rdev)  	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)  		pi->at[i] = TRINITY_AT_DFLT; -	pi->enable_bapm = true; +	/* There are stability issues reported on with +	 * bapm enabled when switching between AC and battery +	 * power.  At the same time, some MSI boards hang +	 * if it's not enabled and dpm is enabled.  Just enable +	 * it for MSI boards right now. +	 */ +	if (rdev->pdev->subsystem_vendor == 0x1462) +		pi->enable_bapm = true; +	else +		pi->enable_bapm = false;  	pi->enable_nbps_policy = true;  	pi->enable_sclk_ds = true;  	pi->enable_gfx_power_gating = true;  	pi->enable_gfx_clock_gating = true; -	pi->enable_mg_clock_gating = true; -	pi->enable_gfx_dynamic_mgpg = true; /* ??? */ -	pi->override_dynamic_mgpg = true; +	pi->enable_mg_clock_gating = false; +	pi->enable_gfx_dynamic_mgpg = false; +	pi->override_dynamic_mgpg = false;  	pi->enable_auto_thermal_throttling = true;  	pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */  	pi->uvd_dpm = true; /* ??? */ @@ -1886,6 +1901,10 @@ int trinity_dpm_init(struct radeon_device *rdev)  	trinity_construct_boot_state(rdev); +	ret = r600_get_platform_caps(rdev); +	if (ret) +		return ret; +  	ret = trinity_parse_power_table(rdev);  	if (ret)  		return ret; @@ -1917,7 +1936,8 @@ void trinity_dpm_print_power_state(struct radeon_device *rdev,  void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,  							 struct seq_file *m)  { -	struct radeon_ps *rps = rdev->pm.dpm.current_ps; +	struct trinity_power_info *pi = trinity_get_pi(rdev); +	struct radeon_ps *rps = &pi->current_rps;  	struct trinity_ps *ps = trinity_get_ps(rps);  	struct trinity_pl *pl;  	u32 current_index = diff --git a/drivers/gpu/drm/radeon/trinity_smc.c b/drivers/gpu/drm/radeon/trinity_smc.c index 9672bcbc731..99dd0455334 100644 --- a/drivers/gpu/drm/radeon/trinity_smc.c +++ b/drivers/gpu/drm/radeon/trinity_smc.c @@ -27,9 +27,6 @@  #include "trinity_dpm.h"  #include "ppsmc.h" -struct trinity_ps *trinity_get_ps(struct radeon_ps *rps); -struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev); -  static int trinity_notify_message_to_smu(struct radeon_device *rdev, u32 id)  {  	int i; diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index 3100fa9cb52..be42c812520 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -83,7 +83,10 @@ int uvd_v1_0_init(struct radeon_device *rdev)  	int r;  	/* raise clocks while booting up the VCPU */ -	radeon_set_uvd_clocks(rdev, 53300, 40000); +	if (rdev->family < CHIP_RV740) +		radeon_set_uvd_clocks(rdev, 10000, 10000); +	else +		radeon_set_uvd_clocks(rdev, 53300, 40000);  	r = uvd_v1_0_start(rdev);  	if (r) @@ -212,8 +215,8 @@ int uvd_v1_0_start(struct radeon_device *rdev)  	/* enable VCPU clock */  	WREG32(UVD_VCPU_CNTL,  1 << 9); -	/* enable UMC and NC0 */ -	WREG32_P(UVD_LMI_CTRL2, 1 << 13, ~((1 << 8) | (1 << 13))); +	/* enable UMC */ +	WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));  	/* boot up the VCPU */  	WREG32(UVD_SOFT_RESET, 0); @@ -262,7 +265,7 @@ int uvd_v1_0_start(struct radeon_device *rdev)  	/* Initialize the ring buffer's read and write pointers */  	WREG32(UVD_RBC_RB_RPTR, 0x0); -	ring->wptr = ring->rptr = RREG32(UVD_RBC_RB_RPTR); +	ring->wptr = RREG32(UVD_RBC_RB_RPTR);  	WREG32(UVD_RBC_RB_WPTR, ring->wptr);  	/* set the ring address */ @@ -357,7 +360,7 @@ int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)   *   * Emit a semaphore command (either wait or signal) to the UVD ring.   */ -void uvd_v1_0_semaphore_emit(struct radeon_device *rdev, +bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,  			     struct radeon_ring *ring,  			     struct radeon_semaphore *semaphore,  			     bool emit_wait) @@ -372,6 +375,8 @@ void uvd_v1_0_semaphore_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));  	radeon_ring_write(ring, emit_wait ? 1 : 0); + +	return true;  }  /** @@ -405,7 +410,10 @@ int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)  	struct radeon_fence *fence = NULL;  	int r; -	r = radeon_set_uvd_clocks(rdev, 53300, 40000); +	if (rdev->family < CHIP_RV740) +		r = radeon_set_uvd_clocks(rdev, 10000, 10000); +	else +		r = radeon_set_uvd_clocks(rdev, 53300, 40000);  	if (r) {  		DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);  		return r; diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c index b19ef495108..8bfdadd5659 100644 --- a/drivers/gpu/drm/radeon/uvd_v2_2.c +++ b/drivers/gpu/drm/radeon/uvd_v2_2.c @@ -45,7 +45,7 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));  	radeon_ring_write(ring, fence->seq);  	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); -	radeon_ring_write(ring, addr & 0xffffffff); +	radeon_ring_write(ring, lower_32_bits(addr));  	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));  	radeon_ring_write(ring, upper_32_bits(addr) & 0xff);  	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); @@ -57,7 +57,6 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, 0);  	radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));  	radeon_ring_write(ring, 2); -	return;  }  /** @@ -153,6 +152,7 @@ int uvd_v2_2_resume(struct radeon_device *rdev)  		chip_id = 0x01000015;  		break;  	case CHIP_PITCAIRN: +	case CHIP_OLAND:  		chip_id = 0x01000016;  		break;  	case CHIP_ARUBA: diff --git a/drivers/gpu/drm/radeon/uvd_v3_1.c b/drivers/gpu/drm/radeon/uvd_v3_1.c index 5b6fa1f62d4..d722db2cf34 100644 --- a/drivers/gpu/drm/radeon/uvd_v3_1.c +++ b/drivers/gpu/drm/radeon/uvd_v3_1.c @@ -37,7 +37,7 @@   *   * Emit a semaphore command (either wait or signal) to the UVD ring.   */ -void uvd_v3_1_semaphore_emit(struct radeon_device *rdev, +bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev,  			     struct radeon_ring *ring,  			     struct radeon_semaphore *semaphore,  			     bool emit_wait) @@ -52,4 +52,6 @@ void uvd_v3_1_semaphore_emit(struct radeon_device *rdev,  	radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));  	radeon_ring_write(ring, 0x80 | (emit_wait ? 1 : 0)); + +	return true;  } diff --git a/drivers/gpu/drm/radeon/vce_v1_0.c b/drivers/gpu/drm/radeon/vce_v1_0.c new file mode 100644 index 00000000000..b44d9c842f7 --- /dev/null +++ b/drivers/gpu/drm/radeon/vce_v1_0.c @@ -0,0 +1,187 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * Authors: Christian König <christian.koenig@amd.com> + */ + +#include <linux/firmware.h> +#include <drm/drmP.h> +#include "radeon.h" +#include "radeon_asic.h" +#include "sid.h" + +/** + * vce_v1_0_get_rptr - get read pointer + * + * @rdev: radeon_device pointer + * @ring: radeon_ring pointer + * + * Returns the current hardware read pointer + */ +uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev, +			   struct radeon_ring *ring) +{ +	if (ring->idx == TN_RING_TYPE_VCE1_INDEX) +		return RREG32(VCE_RB_RPTR); +	else +		return RREG32(VCE_RB_RPTR2); +} + +/** + * vce_v1_0_get_wptr - get write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon_ring pointer + * + * Returns the current hardware write pointer + */ +uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev, +			   struct radeon_ring *ring) +{ +	if (ring->idx == TN_RING_TYPE_VCE1_INDEX) +		return RREG32(VCE_RB_WPTR); +	else +		return RREG32(VCE_RB_WPTR2); +} + +/** + * vce_v1_0_set_wptr - set write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon_ring pointer + * + * Commits the write pointer to the hardware + */ +void vce_v1_0_set_wptr(struct radeon_device *rdev, +		       struct radeon_ring *ring) +{ +	if (ring->idx == TN_RING_TYPE_VCE1_INDEX) +		WREG32(VCE_RB_WPTR, ring->wptr); +	else +		WREG32(VCE_RB_WPTR2, ring->wptr); +} + +/** + * vce_v1_0_start - start VCE block + * + * @rdev: radeon_device pointer + * + * Setup and start the VCE block + */ +int vce_v1_0_start(struct radeon_device *rdev) +{ +	struct radeon_ring *ring; +	int i, j, r; + +	/* set BUSY flag */ +	WREG32_P(VCE_STATUS, 1, ~1); + +	ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; +	WREG32(VCE_RB_RPTR, ring->wptr); +	WREG32(VCE_RB_WPTR, ring->wptr); +	WREG32(VCE_RB_BASE_LO, ring->gpu_addr); +	WREG32(VCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); +	WREG32(VCE_RB_SIZE, ring->ring_size / 4); + +	ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; +	WREG32(VCE_RB_RPTR2, ring->wptr); +	WREG32(VCE_RB_WPTR2, ring->wptr); +	WREG32(VCE_RB_BASE_LO2, ring->gpu_addr); +	WREG32(VCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); +	WREG32(VCE_RB_SIZE2, ring->ring_size / 4); + +	WREG32_P(VCE_VCPU_CNTL, VCE_CLK_EN, ~VCE_CLK_EN); + +	WREG32_P(VCE_SOFT_RESET, +		 VCE_ECPU_SOFT_RESET | +		 VCE_FME_SOFT_RESET, ~( +		 VCE_ECPU_SOFT_RESET | +		 VCE_FME_SOFT_RESET)); + +	mdelay(100); + +	WREG32_P(VCE_SOFT_RESET, 0, ~( +		 VCE_ECPU_SOFT_RESET | +		 VCE_FME_SOFT_RESET)); + +	for (i = 0; i < 10; ++i) { +		uint32_t status; +		for (j = 0; j < 100; ++j) { +			status = RREG32(VCE_STATUS); +			if (status & 2) +				break; +			mdelay(10); +		} +		r = 0; +		if (status & 2) +			break; + +		DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); +		WREG32_P(VCE_SOFT_RESET, VCE_ECPU_SOFT_RESET, ~VCE_ECPU_SOFT_RESET); +		mdelay(10); +		WREG32_P(VCE_SOFT_RESET, 0, ~VCE_ECPU_SOFT_RESET); +		mdelay(10); +		r = -1; +	} + +	/* clear BUSY flag */ +	WREG32_P(VCE_STATUS, 0, ~1); + +	if (r) { +		DRM_ERROR("VCE not responding, giving up!!!\n"); +		return r; +	} + +	return 0; +} + +int vce_v1_0_init(struct radeon_device *rdev) +{ +	struct radeon_ring *ring; +	int r; + +	r = vce_v1_0_start(rdev); +	if (r) +		return r; + +	ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; +	ring->ready = true; +	r = radeon_ring_test(rdev, TN_RING_TYPE_VCE1_INDEX, ring); +	if (r) { +		ring->ready = false; +		return r; +	} + +	ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; +	ring->ready = true; +	r = radeon_ring_test(rdev, TN_RING_TYPE_VCE2_INDEX, ring); +	if (r) { +		ring->ready = false; +		return r; +	} + +	DRM_INFO("VCE initialized successfully.\n"); + +	return 0; +} diff --git a/drivers/gpu/drm/radeon/vce_v2_0.c b/drivers/gpu/drm/radeon/vce_v2_0.c new file mode 100644 index 00000000000..1ac7bb825a1 --- /dev/null +++ b/drivers/gpu/drm/radeon/vce_v2_0.c @@ -0,0 +1,181 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * Authors: Christian König <christian.koenig@amd.com> + */ + +#include <linux/firmware.h> +#include <drm/drmP.h> +#include "radeon.h" +#include "radeon_asic.h" +#include "cikd.h" + +static void vce_v2_0_set_sw_cg(struct radeon_device *rdev, bool gated) +{ +	u32 tmp; + +	if (gated) { +		tmp = RREG32(VCE_CLOCK_GATING_B); +		tmp |= 0xe70000; +		WREG32(VCE_CLOCK_GATING_B, tmp); + +		tmp = RREG32(VCE_UENC_CLOCK_GATING); +		tmp |= 0xff000000; +		WREG32(VCE_UENC_CLOCK_GATING, tmp); + +		tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); +		tmp &= ~0x3fc; +		WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); + +		WREG32(VCE_CGTT_CLK_OVERRIDE, 0); +    } else { +		tmp = RREG32(VCE_CLOCK_GATING_B); +		tmp |= 0xe7; +		tmp &= ~0xe70000; +		WREG32(VCE_CLOCK_GATING_B, tmp); + +		tmp = RREG32(VCE_UENC_CLOCK_GATING); +		tmp |= 0x1fe000; +		tmp &= ~0xff000000; +		WREG32(VCE_UENC_CLOCK_GATING, tmp); + +		tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); +		tmp |= 0x3fc; +		WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); +	} +} + +static void vce_v2_0_set_dyn_cg(struct radeon_device *rdev, bool gated) +{ +	u32 orig, tmp; + +	tmp = RREG32(VCE_CLOCK_GATING_B); +	tmp &= ~0x00060006; +	if (gated) { +		tmp |= 0xe10000; +	} else { +		tmp |= 0xe1; +		tmp &= ~0xe10000; +	} +	WREG32(VCE_CLOCK_GATING_B, tmp); + +	orig = tmp = RREG32(VCE_UENC_CLOCK_GATING); +	tmp &= ~0x1fe000; +	tmp &= ~0xff000000; +	if (tmp != orig) +		WREG32(VCE_UENC_CLOCK_GATING, tmp); + +	orig = tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); +	tmp &= ~0x3fc; +	if (tmp != orig) +		WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); + +	if (gated) +		WREG32(VCE_CGTT_CLK_OVERRIDE, 0); +} + +static void vce_v2_0_disable_cg(struct radeon_device *rdev) +{ +	WREG32(VCE_CGTT_CLK_OVERRIDE, 7); +} + +void vce_v2_0_enable_mgcg(struct radeon_device *rdev, bool enable) +{ +	bool sw_cg = false; + +	if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_VCE_MGCG)) { +		if (sw_cg) +			vce_v2_0_set_sw_cg(rdev, true); +		else +			vce_v2_0_set_dyn_cg(rdev, true); +	} else { +		vce_v2_0_disable_cg(rdev); + +		if (sw_cg) +			vce_v2_0_set_sw_cg(rdev, false); +		else +			vce_v2_0_set_dyn_cg(rdev, false); +	} +} + +static void vce_v2_0_init_cg(struct radeon_device *rdev) +{ +	u32 tmp; + +	tmp = RREG32(VCE_CLOCK_GATING_A); +	tmp &= ~(CGC_CLK_GATE_DLY_TIMER_MASK | CGC_CLK_GATER_OFF_DLY_TIMER_MASK); +	tmp |= (CGC_CLK_GATE_DLY_TIMER(0) | CGC_CLK_GATER_OFF_DLY_TIMER(4)); +	tmp |= CGC_UENC_WAIT_AWAKE; +	WREG32(VCE_CLOCK_GATING_A, tmp); + +	tmp = RREG32(VCE_UENC_CLOCK_GATING); +	tmp &= ~(CLOCK_ON_DELAY_MASK | CLOCK_OFF_DELAY_MASK); +	tmp |= (CLOCK_ON_DELAY(0) | CLOCK_OFF_DELAY(4)); +	WREG32(VCE_UENC_CLOCK_GATING, tmp); + +	tmp = RREG32(VCE_CLOCK_GATING_B); +	tmp |= 0x10; +	tmp &= ~0x100000; +	WREG32(VCE_CLOCK_GATING_B, tmp); +} + +int vce_v2_0_resume(struct radeon_device *rdev) +{ +	uint64_t addr = rdev->vce.gpu_addr; +	uint32_t size; + +	WREG32_P(VCE_CLOCK_GATING_A, 0, ~(1 << 16)); +	WREG32_P(VCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); +	WREG32_P(VCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); +	WREG32(VCE_CLOCK_GATING_B, 0xf7); + +	WREG32(VCE_LMI_CTRL, 0x00398000); +	WREG32_P(VCE_LMI_CACHE_CTRL, 0x0, ~0x1); +	WREG32(VCE_LMI_SWAP_CNTL, 0); +	WREG32(VCE_LMI_SWAP_CNTL1, 0); +	WREG32(VCE_LMI_VM_CTRL, 0); + +	size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size); +	WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff); +	WREG32(VCE_VCPU_CACHE_SIZE0, size); + +	addr += size; +	size = RADEON_VCE_STACK_SIZE; +	WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff); +	WREG32(VCE_VCPU_CACHE_SIZE1, size); + +	addr += size; +	size = RADEON_VCE_HEAP_SIZE; +	WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff); +	WREG32(VCE_VCPU_CACHE_SIZE2, size); + +	WREG32_P(VCE_LMI_CTRL2, 0x0, ~0x100); + +	WREG32_P(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, +		 ~VCE_SYS_INT_TRAP_INTERRUPT_EN); + +	vce_v2_0_init_cg(rdev); + +	return 0; +}  | 
