/drivers/video/drm/i915/main.c |
---|
186,7 → 186,7 |
if( GetService("DISPLAY") != 0 ) |
return 0; |
printf("\ni915 v3.17-rc2 build %s %s\nusage: i915 [options]\n" |
printf("\ni915 v3.17-rc3 build %s %s\nusage: i915 [options]\n" |
"-pm=<0,1> Enable powersavings, fbc, downclocking, etc. (default: 1 - true)\n", |
__DATE__, __TIME__); |
printf("-rc6=<-1,0-7> Enable power-saving render C-state 6.\n" |
/drivers/video/drm/radeon/Makefile |
---|
34,7 → 34,6 |
$(DRV_INCLUDES)/drm/drmP.h \ |
$(DRV_INCLUDES)/drm/drm_edid.h \ |
$(DRV_INCLUDES)/drm/drm_crtc.h \ |
$(DRV_INCLUDES)/drm/drm_mode.h \ |
$(DRV_INCLUDES)/drm/drm_mm.h \ |
atom.h \ |
radeon.h \ |
41,11 → 40,20 |
radeon_asic.h |
NAME_SRC= \ |
main.c \ |
pci.c \ |
../ttm/ttm_bo.c \ |
../ttm/ttm_bo_manager.c \ |
../ttm/ttm_bo_util.c \ |
../ttm/ttm_execbuf_util.c \ |
../ttm/ttm_memory.c \ |
../ttm/ttm_page_alloc.c \ |
../ttm/ttm_tt.c \ |
$(DRM_TOPDIR)/drm_cache.c \ |
$(DRM_TOPDIR)/drm_crtc.c \ |
$(DRM_TOPDIR)/drm_crtc_helper.c \ |
$(DRM_TOPDIR)/drm_dp_helper.c \ |
$(DRM_TOPDIR)/drm_drv.c \ |
$(DRM_TOPDIR)/drm_edid.c \ |
$(DRM_TOPDIR)/drm_fb_helper.c \ |
$(DRM_TOPDIR)/drm_gem.c \ |
53,26 → 61,42 |
$(DRM_TOPDIR)/drm_irq.c \ |
$(DRM_TOPDIR)/drm_mm.c \ |
$(DRM_TOPDIR)/drm_modes.c \ |
$(DRM_TOPDIR)/drm_modeset_lock.c \ |
$(DRM_TOPDIR)/drm_pci.c \ |
$(DRM_TOPDIR)/drm_plane_helper.c \ |
$(DRM_TOPDIR)/drm_probe_helper.c \ |
$(DRM_TOPDIR)/drm_rect.c \ |
$(DRM_TOPDIR)/drm_stub.c \ |
$(DRM_TOPDIR)/drm_vma_manager.c \ |
$(DRM_TOPDIR)/i2c/i2c-core.c \ |
$(DRM_TOPDIR)/i2c/i2c-algo-bit.c \ |
bitmap.c \ |
hmm.c \ |
r700_vs.c \ |
radeon_device.c \ |
evergreen.c \ |
evergreen_blit_shaders.c \ |
evergreen_blit_kms.c \ |
evergreen_hdmi.c \ |
cayman_blit_shaders.c \ |
radeon_clocks.c \ |
atom.c \ |
ni.c \ |
atombios_crtc.c \ |
atombios_dp.c \ |
atombios_encoders.c \ |
atombios_i2c.c \ |
btc_dpm.c \ |
cayman_blit_shaders.c \ |
ci_dpm.c \ |
ci_smc.c \ |
cik.c \ |
cik_blit_shaders.c \ |
cik_sdma.c \ |
cypress_dpm.c \ |
dce3_1_afmt.c \ |
dce6_afmt.c \ |
evergreen.c \ |
evergreen_blit_shaders.c \ |
evergreen_cs.c \ |
evergreen_dma.c \ |
evergreen_hdmi.c \ |
kv_dpm.c \ |
kv_smc.c \ |
ni.c \ |
ni_dma.c \ |
ni_dpm.c \ |
radeon_agp.c \ |
radeon_asic.c \ |
radeon_atombios.c \ |
80,6 → 104,8 |
radeon_bios.c \ |
radeon_combios.c \ |
radeon_connectors.c \ |
radeon_cs.c \ |
radeon_clocks.c \ |
radeon_display.c \ |
radeon_encoders.c \ |
radeon_fence.c \ |
87,35 → 113,65 |
radeon_gart.c \ |
radeon_gem.c \ |
radeon_i2c.c \ |
radeon_ib.c \ |
radeon_irq_kms.c \ |
radeon_legacy_crtc.c \ |
radeon_legacy_encoders.c \ |
radeon_legacy_tv.c \ |
radeon_object_kos.c \ |
radeon_object.c \ |
radeon_pm.c \ |
radeon_ring.c \ |
radeon_sa.c \ |
radeon_semaphore.c \ |
radeon_test.c \ |
radeon_ttm.c \ |
radeon_ucode.c \ |
radeon_uvd.c \ |
radeon_vce.c \ |
radeon_vm.c \ |
rdisplay_kms.c \ |
r100.c \ |
r200.c \ |
r300.c \ |
r420.c \ |
rv515.c \ |
rv730_dpm.c \ |
rv740_dpm.c \ |
r520.c \ |
r600.c \ |
r600_blit_kms.c \ |
r600_audio.c \ |
r600_blit_shaders.c \ |
r600_cs.c \ |
r600_dma.c \ |
r600_dpm.c \ |
r600_hdmi.c \ |
rs400.c \ |
rs600.c \ |
rs690.c \ |
rv6xx_dpm.c \ |
rs780_dpm.c \ |
rv770.c \ |
rv770_dma.c \ |
rv770_dpm.c \ |
rv770_smc.c \ |
rdisplay.c \ |
rdisplay_kms.c \ |
cmdline.c \ |
si.c \ |
si_blit_shaders.c \ |
si_dma.c \ |
si_dpm.c \ |
si_smc.c \ |
sumo_dpm.c \ |
sumo_smc.c \ |
trinity_dpm.c \ |
trinity_smc.c \ |
utils.c \ |
uvd_v1_0.c \ |
uvd_v2_2.c \ |
uvd_v3_1.c \ |
uvd_v4_2.c \ |
vce_v1_0.c \ |
vce_v2_0.c \ |
fwblob.asm |
FW_BINS= \ |
/drivers/video/drm/radeon/Makefile.lto |
---|
7,24 → 7,28 |
DEFINES = -D__KERNEL__ -DCONFIG_X86_32 |
DRV_TOPDIR = $(CURDIR)/../../.. |
DDK_TOPDIR = d:\kos\kolibri\drivers\ddk |
DRV_INCLUDES = /d/kos/kolibri/drivers/include |
DRM_TOPDIR = $(CURDIR)/.. |
DRV_INCLUDES = $(DRV_TOPDIR)/include |
INCLUDES = -I$(DRV_INCLUDES)/linux/uapi -I$(DRV_INCLUDES)/linux \ |
-I$(DRV_INCLUDES)/linux/asm -I$(DRV_INCLUDES)/drm \ |
-I./ -I$(DRV_INCLUDES) |
INCLUDES = -I$(DRV_INCLUDES) -I$(DRV_INCLUDES)/drm \ |
-I$(DRV_INCLUDES)/linux |
CFLAGS_OPT = -Os -march=i686 -fomit-frame-pointer -fno-builtin-printf -mno-stack-arg-probe -mpreferred-stack-boundary=2 -mincoming-stack-boundary=2 -flto |
CFLAGS_OPT = -Os -march=i686 -fno-ident -fomit-frame-pointer -fno-builtin-printf -mno-ms-bitfields |
CFLAGS_OPT+= -mno-stack-arg-probe -mpreferred-stack-boundary=2 -mincoming-stack-boundary=2 -flto |
CFLAGS = -c $(INCLUDES) $(DEFINES) $(CFLAGS_OPT) |
LIBPATH:= $(DRV_TOPDIR)/ddk |
LIBPATH:= $(DDK_TOPDIR) |
LIBS:= -lddk -lcore |
LIBS:= -lddk -lcore -lgcc |
LDFLAGS = -nostdlib,-shared,-s,-Map,atikms.map,--image-base,0,--file-alignment,512,--section-alignment,4096 |
PE_FLAGS = --major-os-version,0,--minor-os-version,7,--major-subsystem-version,0,--minor-subsystem-version,5,--subsystem,native |
LDFLAGS = -nostdlib,-shared,-s,$(PE_FLAGS),--image-base,0,--file-alignment,512,--section-alignment,4096 |
NAME:= atikms |
HFILES:= $(DRV_INCLUDES)/linux/types.h \ |
34,7 → 38,6 |
$(DRV_INCLUDES)/drm/drmP.h \ |
$(DRV_INCLUDES)/drm/drm_edid.h \ |
$(DRV_INCLUDES)/drm/drm_crtc.h \ |
$(DRV_INCLUDES)/drm/drm_mode.h \ |
$(DRV_INCLUDES)/drm/drm_mm.h \ |
atom.h \ |
radeon.h \ |
41,29 → 44,63 |
radeon_asic.h |
NAME_SRC= \ |
main.c \ |
pci.c \ |
../ttm/ttm_bo.c \ |
../ttm/ttm_bo_manager.c \ |
../ttm/ttm_bo_util.c \ |
../ttm/ttm_execbuf_util.c \ |
../ttm/ttm_memory.c \ |
../ttm/ttm_page_alloc.c \ |
../ttm/ttm_tt.c \ |
$(DRM_TOPDIR)/drm_cache.c \ |
$(DRM_TOPDIR)/drm_crtc.c \ |
$(DRM_TOPDIR)/drm_crtc_helper.c \ |
$(DRM_TOPDIR)/drm_dp_i2c_helper.c \ |
$(DRM_TOPDIR)/drm_dp_helper.c \ |
$(DRM_TOPDIR)/drm_drv.c \ |
$(DRM_TOPDIR)/drm_edid.c \ |
$(DRM_TOPDIR)/drm_fb_helper.c \ |
$(DRM_TOPDIR)/drm_gem.c \ |
$(DRM_TOPDIR)/drm_global.c \ |
$(DRM_TOPDIR)/drm_irq.c \ |
$(DRM_TOPDIR)/drm_mm.c \ |
$(DRM_TOPDIR)/drm_modes.c \ |
$(DRM_TOPDIR)/drm_modeset_lock.c \ |
$(DRM_TOPDIR)/drm_pci.c \ |
$(DRM_TOPDIR)/drm_plane_helper.c \ |
$(DRM_TOPDIR)/drm_probe_helper.c \ |
$(DRM_TOPDIR)/drm_rect.c \ |
$(DRM_TOPDIR)/drm_stub.c \ |
$(DRM_TOPDIR)/drm_vma_manager.c \ |
$(DRM_TOPDIR)/i2c/i2c-core.c \ |
$(DRM_TOPDIR)/i2c/i2c-algo-bit.c \ |
r700_vs.c \ |
hmm.c \ |
radeon_device.c \ |
atom.c \ |
atombios_crtc.c \ |
atombios_dp.c \ |
atombios_encoders.c \ |
atombios_i2c.c \ |
btc_dpm.c \ |
cayman_blit_shaders.c \ |
ci_dpm.c \ |
ci_smc.c \ |
cik.c \ |
cik_blit_shaders.c \ |
cik_sdma.c \ |
cypress_dpm.c \ |
dce3_1_afmt.c \ |
dce6_afmt.c \ |
evergreen.c \ |
evergreen_blit_shaders.c \ |
evergreen_blit_kms.c \ |
evergreen_cs.c \ |
evergreen_dma.c \ |
evergreen_hdmi.c \ |
cayman_blit_shaders.c \ |
radeon_clocks.c \ |
atom.c \ |
kv_dpm.c \ |
kv_smc.c \ |
ni.c \ |
ni_dma.c \ |
ni_dpm.c \ |
radeon_agp.c \ |
radeon_asic.c \ |
radeon_atombios.c \ |
71,45 → 108,74 |
radeon_bios.c \ |
radeon_combios.c \ |
radeon_connectors.c \ |
atombios_crtc.c \ |
atombios_dp.c \ |
atombios_encoders.c \ |
atombios_i2c.c \ |
radeon_cs.c \ |
radeon_clocks.c \ |
radeon_display.c \ |
radeon_encoders.c \ |
radeon_fence.c \ |
radeon_fb.c \ |
radeon_gart.c \ |
radeon_gem.c \ |
radeon_i2c.c \ |
radeon_ib.c \ |
radeon_irq_kms.c \ |
radeon_legacy_crtc.c \ |
radeon_legacy_encoders.c \ |
radeon_legacy_tv.c \ |
radeon_display.c \ |
radeon_gart.c \ |
radeon_object.c \ |
radeon_pm.c \ |
radeon_ring.c \ |
radeon_object_kos.c \ |
radeon_sa.c \ |
radeon_semaphore.c \ |
radeon_pm.c \ |
radeon_test.c \ |
radeon_ttm.c \ |
radeon_ucode.c \ |
radeon_uvd.c \ |
radeon_vce.c \ |
radeon_vm.c \ |
rdisplay_kms.c \ |
r100.c \ |
r200.c \ |
r300.c \ |
r420.c \ |
rv515.c \ |
rv730_dpm.c \ |
rv740_dpm.c \ |
r520.c \ |
r600.c \ |
r600_blit_kms.c \ |
r600_audio.c \ |
r600_blit_shaders.c \ |
r600_cs.c \ |
r600_dma.c \ |
r600_dpm.c \ |
r600_hdmi.c \ |
rs400.c \ |
rs600.c \ |
rs690.c \ |
rv6xx_dpm.c \ |
rs780_dpm.c \ |
rv770.c \ |
radeon_fb.c \ |
rv770_dma.c \ |
rv770_dpm.c \ |
rv770_smc.c \ |
rdisplay.c \ |
rdisplay_kms.c \ |
cmdline.c \ |
si.c \ |
si_blit_shaders.c \ |
si_dma.c \ |
si_dpm.c \ |
si_smc.c \ |
sumo_dpm.c \ |
sumo_smc.c \ |
trinity_dpm.c \ |
trinity_smc.c \ |
utils.c \ |
uvd_v1_0.c \ |
uvd_v2_2.c \ |
uvd_v3_1.c \ |
uvd_v4_2.c \ |
vce_v1_0.c \ |
vce_v2_0.c \ |
fwblob.asm |
FW_BINS= \ |
152,6 → 218,8 |
NAME_OBJS = $(patsubst %.S, %.o, $(patsubst %.asm, %.o,\ |
$(patsubst %.c, %.o, $(NAME_SRC)))) |
all: $(NAME).dll |
$(NAME).dll: $(NAME_OBJS) $(FW_BINS) $(SRC_DEP) $(HFILES) $(LIBPATH)/libcore.a $(LIBPATH)/libddk.a atikms.lds Makefile.lto |
/drivers/video/drm/radeon/ObjectID.h |
---|
69,6 → 69,8 |
#define ENCODER_OBJECT_ID_ALMOND 0x22 |
#define ENCODER_OBJECT_ID_TRAVIS 0x23 |
#define ENCODER_OBJECT_ID_NUTMEG 0x22 |
#define ENCODER_OBJECT_ID_HDMI_ANX9805 0x26 |
/* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */ |
#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 0x13 |
#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 0x14 |
86,6 → 88,8 |
#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 0x20 |
#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 0x21 |
#define ENCODER_OBJECT_ID_INTERNAL_VCE 0x24 |
#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 0x25 |
#define ENCODER_OBJECT_ID_INTERNAL_AMCLK 0x27 |
#define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO 0xFF |
364,6 → 368,14 |
GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ |
ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT) |
#define ENCODER_INTERNAL_UNIPHY3_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ |
ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 << OBJECT_ID_SHIFT) |
#define ENCODER_INTERNAL_UNIPHY3_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ |
ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 << OBJECT_ID_SHIFT) |
#define ENCODER_GENERAL_EXTERNAL_DVO_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ |
ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT) |
392,6 → 404,10 |
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ |
ENCODER_OBJECT_ID_INTERNAL_VCE << OBJECT_ID_SHIFT) |
#define ENCODER_HDMI_ANX9805_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ |
ENCODER_OBJECT_ID_HDMI_ANX9805 << OBJECT_ID_SHIFT) |
/****************************************************/ |
/* Connector Object ID definition - Shared with BIOS */ |
/****************************************************/ |
461,6 → 477,14 |
GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) |
#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID5 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) |
#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID6 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) |
#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) |
473,6 → 497,10 |
GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) |
#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) |
#define CONNECTOR_VGA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT) |
541,6 → 569,18 |
GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT) |
#define CONNECTOR_HDMI_TYPE_A_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT) |
#define CONNECTOR_HDMI_TYPE_A_ENUM_ID5 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT) |
#define CONNECTOR_HDMI_TYPE_A_ENUM_ID6 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT) |
#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ |
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ |
CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT) |
/drivers/video/drm/radeon/atom.c |
---|
725,7 → 725,7 |
SDEBUG(" target: 0x%04X\n", target); |
if (execute) { |
if (ctx->last_jump == (ctx->start + target)) { |
cjiffies = GetTimerTicks(); |
cjiffies = jiffies; |
if (time_after(cjiffies, ctx->last_jump_jiffies)) { |
cjiffies -= ctx->last_jump_jiffies; |
if ((jiffies_to_msecs(cjiffies) > 5000)) { |
734,11 → 734,11 |
} |
} else { |
/* jiffies wrap around we will just wait a little longer */ |
ctx->last_jump_jiffies = GetTimerTicks(); |
ctx->last_jump_jiffies = jiffies; |
} |
} else { |
ctx->last_jump = ctx->start + target; |
ctx->last_jump_jiffies = GetTimerTicks(); |
ctx->last_jump_jiffies = jiffies; |
} |
*ptr = ctx->start + target; |
} |
1220,6 → 1220,8 |
int r; |
mutex_lock(&ctx->mutex); |
/* reset data block */ |
ctx->data_block = 0; |
/* reset reg block */ |
ctx->reg_block = 0; |
/* reset fb window */ |
1226,6 → 1228,9 |
ctx->fb_base = 0; |
/* reset io mode */ |
ctx->io_mode = ATOM_IO_MM; |
/* reset divmul */ |
ctx->divmul[0] = 0; |
ctx->divmul[1] = 0; |
r = atom_execute_table_locked(ctx, index, params); |
mutex_unlock(&ctx->mutex); |
return r; |
/drivers/video/drm/radeon/atombios.h |
---|
74,6 → 74,8 |
#define ATOM_PPLL2 1 |
#define ATOM_DCPLL 2 |
#define ATOM_PPLL0 2 |
#define ATOM_PPLL3 3 |
#define ATOM_EXT_PLL1 8 |
#define ATOM_EXT_PLL2 9 |
#define ATOM_EXT_CLOCK 10 |
259,7 → 261,7 |
USHORT AdjustDisplayPll; //Atomic Table, used by various SW componentes. |
USHORT AdjustMemoryController; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock |
USHORT EnableASIC_StaticPwrMgt; //Atomic Table, only used by Bios |
USHORT ASIC_StaticPwrMgtStatusChange; //Obsolete , only used by Bios |
USHORT SetUniphyInstance; //Atomic Table, only used by Bios |
USHORT DAC_LoadDetection; //Atomic Table, directly used by various SW components,latest version 1.2 |
USHORT LVTMAEncoderControl; //Atomic Table,directly used by various SW components,latest version 1.3 |
USHORT HW_Misc_Operation; //Atomic Table, directly used by various SW components,latest version 1.1 |
271,7 → 273,7 |
USHORT TVEncoderControl; //Function Table,directly used by various SW components,latest version 1.1 |
USHORT PatchMCSetting; //only used by BIOS |
USHORT MC_SEQ_Control; //only used by BIOS |
USHORT TV1OutputControl; //Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead |
USHORT Gfx_Harvesting; //Atomic Table, Obsolete from Ry6xx, Now only used by BIOS for GFX harvesting |
USHORT EnableScaler; //Atomic Table, used only by Bios |
USHORT BlankCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 |
USHORT EnableCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 |
328,7 → 330,7 |
#define UNIPHYTransmitterControl DIG1TransmitterControl |
#define LVTMATransmitterControl DIG2TransmitterControl |
#define SetCRTC_DPM_State GetConditionalGoldenSetting |
#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange |
#define ASIC_StaticPwrMgtStatusChange SetUniphyInstance |
#define HPDInterruptService ReadHWAssistedI2CStatus |
#define EnableVGA_Access GetSCLKOverMCLKRatio |
#define EnableYUV GetDispObjectInfo |
338,8 → 340,8 |
#define TMDSAEncoderControl PatchMCSetting |
#define LVDSEncoderControl MC_SEQ_Control |
#define LCD1OutputControl HW_Misc_Operation |
#define TV1OutputControl Gfx_Harvesting |
typedef struct _ATOM_MASTER_COMMAND_TABLE |
{ |
ATOM_COMMON_TABLE_HEADER sHeader; |
478,11 → 480,11 |
typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 |
{ |
#if ATOM_BIG_ENDIAN |
ULONG ucPostDiv; //return parameter: post divider which is used to program to register directly |
ULONG ucPostDiv:8; //return parameter: post divider which is used to program to register directly |
ULONG ulClock:24; //Input= target clock, output = actual clock |
#else |
ULONG ulClock:24; //Input= target clock, output = actual clock |
ULONG ucPostDiv; //return parameter: post divider which is used to program to register directly |
ULONG ucPostDiv:8; //return parameter: post divider which is used to program to register directly |
#endif |
}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4; |
504,6 → 506,32 |
UCHAR ucReserved; |
}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5; |
typedef struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 |
{ |
ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter |
ULONG ulReserved[2]; |
}COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6; |
//ATOM_COMPUTE_CLOCK_FREQ.ulComputeClockFlag |
#define COMPUTE_GPUCLK_INPUT_FLAG_CLK_TYPE_MASK 0x0f |
#define COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK 0x00 |
#define COMPUTE_GPUCLK_INPUT_FLAG_SCLK 0x01 |
typedef struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 |
{ |
COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 ulClock; //Output Parameter: ucPostDiv=DFS divider |
ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter: PLL FB divider |
UCHAR ucPllRefDiv; //Output Parameter: PLL ref divider |
UCHAR ucPllPostDiv; //Output Parameter: PLL post divider |
UCHAR ucPllCntlFlag; //Output Flags: control flag |
UCHAR ucReserved; |
}COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6; |
//ucPllCntlFlag |
#define SPLL_CNTL_FLAG_VCO_MODE_MASK 0x03 |
// ucInputFlag |
#define ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN 1 // 1-StrobeMode, 0-PerformanceMode |
1683,9 → 1711,12 |
#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 |
typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2 |
{ |
2102,6 → 2133,17 |
}DVO_ENCODER_CONTROL_PARAMETERS_V3; |
#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 DVO_ENCODER_CONTROL_PARAMETERS_V3 |
typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V1_4 |
{ |
USHORT usPixelClock; |
UCHAR ucDVOConfig; |
UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT |
UCHAR ucBitPerColor; //please refer to definition of PANEL_xBIT_PER_COLOR |
UCHAR ucReseved[3]; |
}DVO_ENCODER_CONTROL_PARAMETERS_V1_4; |
#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 DVO_ENCODER_CONTROL_PARAMETERS_V1_4 |
//ucTableFormatRevision=1 |
//ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for |
// bit1=0: non-coherent mode |
2183,7 → 2225,7 |
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 |
2200,9 → 2242,10 |
//SET_VOLTAGE_PARAMETERS_V3.ucVoltageMode |
#define ATOM_SET_VOLTAGE 0 //Set voltage Level |
#define ATOM_INIT_VOLTAGE_REGULATOR 3 //Init Regulator |
#define ATOM_SET_VOLTAGE_PHASE 4 //Set Vregulator Phase |
#define ATOM_GET_MAX_VOLTAGE 6 //Get Max Voltage, not used in SetVoltageTable v1.3 |
#define ATOM_GET_VOLTAGE_LEVEL 6 //Get Voltage level from vitual voltage ID |
#define ATOM_SET_VOLTAGE_PHASE 4 //Set Vregulator Phase, only for SVID/PVID regulator |
#define ATOM_GET_MAX_VOLTAGE 6 //Get Max Voltage, not used from SetVoltageTable v1.3 |
#define ATOM_GET_VOLTAGE_LEVEL 6 //Get Voltage level from vitual voltage ID, not used for SetVoltage v1.4 |
#define ATOM_GET_LEAKAGE_ID 8 //Get Leakage Voltage Id ( starting from SMU7x IP ), SetVoltage v1.4 |
// define vitual voltage id in usVoltageLevel |
#define ATOM_VIRTUAL_VOLTAGE_ID0 0xff01 |
2209,6 → 2252,10 |
#define ATOM_VIRTUAL_VOLTAGE_ID1 0xff02 |
#define ATOM_VIRTUAL_VOLTAGE_ID2 0xff03 |
#define ATOM_VIRTUAL_VOLTAGE_ID3 0xff04 |
#define ATOM_VIRTUAL_VOLTAGE_ID4 0xff05 |
#define ATOM_VIRTUAL_VOLTAGE_ID5 0xff06 |
#define ATOM_VIRTUAL_VOLTAGE_ID6 0xff07 |
#define ATOM_VIRTUAL_VOLTAGE_ID7 0xff08 |
typedef struct _SET_VOLTAGE_PS_ALLOCATION |
{ |
2245,15 → 2292,36 |
#define ATOM_GET_VOLTAGE_VID 0x00 |
#define ATOM_GET_VOTLAGE_INIT_SEQ 0x03 |
#define ATOM_GET_VOLTTAGE_PHASE_PHASE_VID 0x04 |
#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 |
/****************************************************************************/ |
2628,7 → 2696,8 |
ULONG ulFirmwareRevision; |
ULONG ulDefaultEngineClock; //In 10Khz unit |
ULONG ulDefaultMemoryClock; //In 10Khz unit |
ULONG ulReserved[2]; |
ULONG ulSPLL_OutputFreq; //In 10Khz unit |
ULONG ulGPUPLL_OutputFreq; //In 10Khz unit |
ULONG ulReserved1; //Was ulMaxEngineClockPLL_Output; //In 10Khz unit* |
ULONG ulReserved2; //Was ulMaxMemoryClockPLL_Output; //In 10Khz unit* |
ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit |
3813,6 → 3882,14 |
UCHAR ucGPIO_ID; |
}ATOM_GPIO_PIN_ASSIGNMENT; |
//ucGPIO_ID pre-define id for multiple usage |
//from SMU7.x, if ucGPIO_ID=PP_AC_DC_SWITCH_GPIO_PINID in GPIO_LUTTable, AC/DC swithing feature is enable |
#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 |
{ |
ATOM_COMMON_TABLE_HEADER sHeader; |
4074,6 → 4151,7 |
//usCaps |
#define EXT_DISPLAY_PATH_CAPS__HBR2_DISABLE 0x01 |
#define EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN 0x02 |
typedef struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO |
{ |
4084,7 → 4162,8 |
UCHAR uc3DStereoPinId; // use for eDP panel |
UCHAR ucRemoteDisplayConfig; |
UCHAR uceDPToLVDSRxId; |
UCHAR Reserved[4]; // for potential expansion |
UCHAR ucFixDPVoltageSwing; // usCaps[1]=1, this indicate DP_LANE_SET value |
UCHAR Reserved[3]; // for potential expansion |
}ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO; |
//Related definitions, all records are different but they have a commond header |
4115,10 → 4194,10 |
#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 |
{ |
4343,6 → 4422,31 |
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 |
/****************************************************************************/ |
4416,6 → 4520,13 |
#define VOLTAGE_CONTROL_ID_CHL822x 0x08 |
#define VOLTAGE_CONTROL_ID_VT1586M 0x09 |
#define VOLTAGE_CONTROL_ID_UP1637 0x0A |
#define VOLTAGE_CONTROL_ID_CHL8214 0x0B |
#define VOLTAGE_CONTROL_ID_UP1801 0x0C |
#define VOLTAGE_CONTROL_ID_ST6788A 0x0D |
#define VOLTAGE_CONTROL_ID_CHLIR3564SVI2 0x0E |
#define VOLTAGE_CONTROL_ID_AD527x 0x0F |
#define VOLTAGE_CONTROL_ID_NCP81022 0x10 |
#define VOLTAGE_CONTROL_ID_LTC2635 0x11 |
typedef struct _ATOM_VOLTAGE_OBJECT |
{ |
4458,6 → 4569,16 |
USHORT usSize; //Size of Object |
}ATOM_VOLTAGE_OBJECT_HEADER_V3; |
// ATOM_VOLTAGE_OBJECT_HEADER_V3.ucVoltageMode |
#define VOLTAGE_OBJ_GPIO_LUT 0 //VOLTAGE and GPIO Lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_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_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 |
{ |
ULONG ulVoltageId; // The Voltage ID which is used to program GPIO register |
4473,7 → 4594,7 |
typedef struct _ATOM_I2C_VOLTAGE_OBJECT_V3 |
{ |
ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; |
ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = VOLTAGE_OBJ_VR_I2C_INIT_SEQ |
UCHAR ucVoltageRegulatorId; //Indicate Voltage Regulator Id |
UCHAR ucVoltageControlI2cLine; |
UCHAR ucVoltageControlAddress; |
4482,9 → 4603,13 |
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; |
ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = VOLTAGE_OBJ_GPIO_LUT or VOLTAGE_OBJ_PHASE_LUT |
UCHAR ucVoltageGpioCntlId; // default is 0 which indicate control through CG VID mode |
UCHAR ucGpioEntryNum; // indiate the entry numbers of Votlage/Gpio value Look up table |
UCHAR ucPhaseDelay; // phase delay in unit of micro second |
4495,7 → 4620,7 |
typedef struct _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 |
{ |
ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; |
ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = 0x10/0x11/0x12 |
UCHAR ucLeakageCntlId; // default is 0 |
UCHAR ucLeakageEntryNum; // indicate the entry number of LeakageId/Voltage Lut table |
UCHAR ucReserved[2]; |
4503,10 → 4628,27 |
LEAKAGE_VOLTAGE_LUT_ENTRY_V2 asLeakageIdLut[1]; |
}ATOM_LEAKAGE_VOLTAGE_OBJECT_V3; |
typedef struct _ATOM_SVID2_VOLTAGE_OBJECT_V3 |
{ |
ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = VOLTAGE_OBJ_SVID2 |
// 14:7 – PSI0_VID |
// 6 – PSI0_EN |
// 5 – PSI1 |
// 4:2 – load line slope trim. |
// 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 ucSVDGpioId; //0~31 indicate GPIO0~31 |
UCHAR ucSVCGpioId; //0~31 indicate GPIO0~31 |
ULONG ulReserved; |
}ATOM_SVID2_VOLTAGE_OBJECT_V3; |
typedef union _ATOM_VOLTAGE_OBJECT_V3{ |
ATOM_GPIO_VOLTAGE_OBJECT_V3 asGpioVoltageObj; |
ATOM_I2C_VOLTAGE_OBJECT_V3 asI2cVoltageObj; |
ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 asLeakageObj; |
ATOM_SVID2_VOLTAGE_OBJECT_V3 asSVID2Obj; |
}ATOM_VOLTAGE_OBJECT_V3; |
typedef struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 |
4536,6 → 4678,64 |
ATOM_ASIC_PROFILE_VOLTAGE asVoltage; |
}ATOM_ASIC_PROFILING_INFO; |
typedef struct _ATOM_ASIC_PROFILING_INFO_V2_1 |
{ |
ATOM_COMMON_TABLE_HEADER asHeader; |
UCHAR ucLeakageBinNum; // indicate the entry number of LeakageId/Voltage Lut table |
USHORT usLeakageBinArrayOffset; // offset of USHORT Leakage Bin list array ( from lower LeakageId to higher) |
UCHAR ucElbVDDC_Num; |
USHORT usElbVDDC_IdArrayOffset; // offset of USHORT virtual VDDC voltage id ( 0xff01~0xff08 ) |
USHORT usElbVDDC_LevelArrayOffset; // offset of 2 dimension voltage level USHORT array |
UCHAR ucElbVDDCI_Num; |
USHORT usElbVDDCI_IdArrayOffset; // offset of USHORT virtual VDDCI voltage id ( 0xff01~0xff08 ) |
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 |
4652,6 → 4852,8 |
#define SYS_INFO_LVDSMISC__888_BPC 0x04 |
#define SYS_INFO_LVDSMISC__OVERRIDE_EN 0x08 |
#define SYS_INFO_LVDSMISC__BLON_ACTIVE_LOW 0x10 |
// new since Trinity |
#define SYS_INFO_LVDSMISC__TRAVIS_LVDS_VOL_OVERRIDE_EN 0x20 |
// not used any more |
#define SYS_INFO_LVDSMISC__VSYNC_ACTIVE_LOW 0x04 |
4752,6 → 4954,29 |
ATOM_INTEGRATED_SYSTEM_INFO_V6 sIntegratedSysInfo; |
ULONG ulPowerplayTable[128]; |
}ATOM_FUSION_SYSTEM_INFO_V1; |
typedef struct _ATOM_TDP_CONFIG_BITS |
{ |
#if ATOM_BIG_ENDIAN |
ULONG uReserved:2; |
ULONG uTDP_Value:14; // Original TDP value in tens of milli watts |
ULONG uCTDP_Value:14; // Override value in tens of milli watts |
ULONG uCTDP_Enable:2; // = (uCTDP_Value > uTDP_Value? 2: (uCTDP_Value < uTDP_Value)) |
#else |
ULONG uCTDP_Enable:2; // = (uCTDP_Value > uTDP_Value? 2: (uCTDP_Value < uTDP_Value)) |
ULONG uCTDP_Value:14; // Override value in tens of milli watts |
ULONG uTDP_Value:14; // Original TDP value in tens of milli watts |
ULONG uReserved:2; |
#endif |
}ATOM_TDP_CONFIG_BITS; |
typedef union _ATOM_TDP_CONFIG |
{ |
ATOM_TDP_CONFIG_BITS TDP_config; |
ULONG TDP_config_all; |
}ATOM_TDP_CONFIG; |
/********************************************************************************************************************** |
ATOM_FUSION_SYSTEM_INFO_V1 Description |
sIntegratedSysInfo: refer to ATOM_INTEGRATED_SYSTEM_INFO_V6 definition. |
4784,7 → 5009,8 |
UCHAR ucMemoryType; |
UCHAR ucUMAChannelNumber; |
UCHAR strVBIOSMsg[40]; |
ULONG ulReserved[20]; |
ATOM_TDP_CONFIG asTdpConfig; |
ULONG ulReserved[19]; |
ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5]; |
ULONG ulGMCRestoreResetTime; |
ULONG ulMinimumNClk; |
4809,7 → 5035,7 |
USHORT GnbTdpLimit; |
USHORT usMaxLVDSPclkFreqInSingleLink; |
UCHAR ucLvdsMisc; |
UCHAR ucLVDSReserved; |
UCHAR ucTravisLVDSVolAdjust; |
UCHAR ucLVDSPwrOnSeqDIGONtoDE_in4Ms; |
UCHAR ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms; |
UCHAR ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms; |
4817,7 → 5043,7 |
UCHAR ucLVDSOffToOnDelay_in4Ms; |
UCHAR ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms; |
UCHAR ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms; |
UCHAR ucLVDSReserved1; |
UCHAR ucMinAllowedBL_Level; |
ULONG ulLCDBitDepthControlVal; |
ULONG ulNbpStateMemclkFreq[4]; |
USHORT usNBP2Voltage; |
4846,6 → 5072,7 |
#define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01 |
#define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE 0x02 |
#define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT 0x08 |
#define SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS 0x10 |
/********************************************************************************************************************** |
ATOM_INTEGRATED_SYSTEM_INFO_V1_7 Description |
4945,6 → 5172,9 |
[bit2] LVDS 888bit per color mode =0: 666 bit per color =1:888 bit per color |
[bit3] LVDS parameter override enable =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used |
[bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low ) |
[bit5] Travid LVDS output voltage override enable, when =1, use ucTravisLVDSVolAdjust value to overwrite Traivs register LVDS_CTRL_4 |
ucTravisLVDSVolAdjust When ucLVDSMisc[5]=1,it means platform SBIOS want to overwrite TravisLVDSVoltage. Then VBIOS will use ucTravisLVDSVolAdjust |
value to program Travis register LVDS_CTRL_4 |
ucLVDSPwrOnSeqDIGONtoDE_in4Ms: LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ). |
=0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
4964,18 → 5194,241 |
=0 means to use VBIOS default delay which is 125 ( 500ms ). |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucLVDSPwrOnVARY_BLtoBLON_in4Ms: LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. |
ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms: |
LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. |
=0 means to use VBIOS default delay which is 0 ( 0ms ). |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucLVDSPwrOffBLONtoVARY_BL_in4Ms: LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. |
ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms: |
LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. |
=0 means to use VBIOS default delay which is 0 ( 0ms ). |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucMinAllowedBL_Level: Lowest LCD backlight PWM level. This is customer platform specific parameters. By default it is 0. |
ulNbpStateMemclkFreq[4]: system memory clock frequncey in unit of 10Khz in different NB pstate. |
**********************************************************************************************************************/ |
// this IntegrateSystemInfoTable is used for Kaveri & Kabini APU |
typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 |
{ |
ATOM_COMMON_TABLE_HEADER sHeader; |
ULONG ulBootUpEngineClock; |
ULONG ulDentistVCOFreq; |
ULONG ulBootUpUMAClock; |
ATOM_CLK_VOLT_CAPABILITY sDISPCLK_Voltage[4]; |
ULONG ulBootUpReqDisplayVector; |
ULONG ulVBIOSMisc; |
ULONG ulGPUCapInfo; |
ULONG ulDISP_CLK2Freq; |
USHORT usRequestedPWMFreqInHz; |
UCHAR ucHtcTmpLmt; |
UCHAR ucHtcHystLmt; |
ULONG ulReserved2; |
ULONG ulSystemConfig; |
ULONG ulCPUCapInfo; |
ULONG ulReserved3; |
USHORT usGPUReservedSysMemSize; |
USHORT usExtDispConnInfoOffset; |
USHORT usPanelRefreshRateRange; |
UCHAR ucMemoryType; |
UCHAR ucUMAChannelNumber; |
UCHAR strVBIOSMsg[40]; |
ATOM_TDP_CONFIG asTdpConfig; |
ULONG ulReserved[19]; |
ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5]; |
ULONG ulGMCRestoreResetTime; |
ULONG ulReserved4; |
ULONG ulIdleNClk; |
ULONG ulDDR_DLL_PowerUpTime; |
ULONG ulDDR_PLL_PowerUpTime; |
USHORT usPCIEClkSSPercentage; |
USHORT usPCIEClkSSType; |
USHORT usLvdsSSPercentage; |
USHORT usLvdsSSpreadRateIn10Hz; |
USHORT usHDMISSPercentage; |
USHORT usHDMISSpreadRateIn10Hz; |
USHORT usDVISSPercentage; |
USHORT usDVISSpreadRateIn10Hz; |
ULONG ulGPUReservedSysMemBaseAddrLo; |
ULONG ulGPUReservedSysMemBaseAddrHi; |
ULONG ulReserved5[3]; |
USHORT usMaxLVDSPclkFreqInSingleLink; |
UCHAR ucLvdsMisc; |
UCHAR ucTravisLVDSVolAdjust; |
UCHAR ucLVDSPwrOnSeqDIGONtoDE_in4Ms; |
UCHAR ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms; |
UCHAR ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms; |
UCHAR ucLVDSPwrOffSeqDEtoDIGON_in4Ms; |
UCHAR ucLVDSOffToOnDelay_in4Ms; |
UCHAR ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms; |
UCHAR ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms; |
UCHAR ucMinAllowedBL_Level; |
ULONG ulLCDBitDepthControlVal; |
ULONG ulNbpStateMemclkFreq[4]; |
ULONG ulReserved6; |
ULONG ulNbpStateNClkFreq[4]; |
USHORT usNBPStateVoltage[4]; |
USHORT usBootUpNBVoltage; |
USHORT usReserved2; |
ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo; |
}ATOM_INTEGRATED_SYSTEM_INFO_V1_8; |
/********************************************************************************************************************** |
ATOM_INTEGRATED_SYSTEM_INFO_V1_8 Description |
ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock |
ulDentistVCOFreq: Dentist VCO clock in 10kHz unit. |
ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit. |
sDISPCLK_Voltage: Report Display clock frequency requirement on GNB voltage(up to 4 voltage levels). |
ulBootUpReqDisplayVector: VBIOS boot up display IDs, following are supported devices in Trinity projects: |
ATOM_DEVICE_CRT1_SUPPORT 0x0001 |
ATOM_DEVICE_DFP1_SUPPORT 0x0008 |
ATOM_DEVICE_DFP6_SUPPORT 0x0040 |
ATOM_DEVICE_DFP2_SUPPORT 0x0080 |
ATOM_DEVICE_DFP3_SUPPORT 0x0200 |
ATOM_DEVICE_DFP4_SUPPORT 0x0400 |
ATOM_DEVICE_DFP5_SUPPORT 0x0800 |
ATOM_DEVICE_LCD1_SUPPORT 0x0002 |
ulVBIOSMisc: Miscellenous flags for VBIOS requirement and interface |
bit[0]=0: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is not supported by SBIOS. |
=1: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is supported by SBIOS. |
bit[1]=0: INT15 callback function Get boot display( ax=4e08, bl=01h) is not supported by SBIOS |
=1: INT15 callback function Get boot display( ax=4e08, bl=01h) is supported by SBIOS |
bit[2]=0: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is not supported by SBIOS |
=1: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is supported by SBIOS |
bit[3]=0: VBIOS fast boot is disable |
=1: VBIOS fast boot is enable. ( VBIOS skip display device detection in every set mode if LCD panel is connect and LID is open) |
ulGPUCapInfo: bit[0~2]= Reserved |
bit[3]=0: Enable AUX HW mode detection logic |
=1: Disable AUX HW mode detection logic |
bit[4]=0: Disable DFS bypass feature |
=1: Enable DFS bypass feature |
usRequestedPWMFreqInHz: When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW). |
Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0; |
When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below: |
1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use; |
VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result, |
Changing BL using VBIOS function is functional in both driver and non-driver present environment; |
and enabling VariBri under the driver environment from PP table is optional. |
2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating |
that BL control from GPU is expected. |
VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1 |
Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but |
it's per platform |
and enabling VariBri under the driver environment from PP table is optional. |
ucHtcTmpLmt: Refer to D18F3x64 bit[22:16], HtcTmpLmt. Threshold on value to enter HTC_active state. |
ucHtcHystLmt: Refer to D18F3x64 bit[27:24], HtcHystLmt. |
To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt. |
ulSystemConfig: Bit[0]=0: PCIE Power Gating Disabled |
=1: PCIE Power Gating Enabled |
Bit[1]=0: DDR-DLL shut-down feature disabled. |
1: DDR-DLL shut-down feature enabled. |
Bit[2]=0: DDR-PLL Power down feature disabled. |
1: DDR-PLL Power down feature enabled. |
Bit[3]=0: GNB DPM is disabled |
=1: GNB DPM is enabled |
ulCPUCapInfo: TBD |
usExtDispConnInfoOffset: Offset to sExtDispConnInfo inside the structure |
usPanelRefreshRateRange: Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set |
to indicate a range. |
SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004 |
SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008 |
SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010 |
SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020 |
ucMemoryType: [3:0]=1:DDR1;=2:DDR2;=3:DDR3;=5:GDDR5; [7:4] is reserved. |
ucUMAChannelNumber: System memory channel numbers. |
strVBIOSMsg[40]: VBIOS boot up customized message string |
sAvail_SCLK[5]: Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high |
ulGMCRestoreResetTime: GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns. |
ulIdleNClk: NCLK speed while memory runs in self-refresh state, used to calculate self-refresh latency. Unit in 10kHz. |
ulDDR_DLL_PowerUpTime: DDR PHY DLL power up time. Unit in ns. |
ulDDR_PLL_PowerUpTime: DDR PHY PLL power up time. Unit in ns. |
usPCIEClkSSPercentage: PCIE Clock Spread Spectrum Percentage in unit 0.01%; 100 mean 1%. |
usPCIEClkSSType: PCIE Clock Spread Spectrum Type. 0 for Down spread(default); 1 for Center spread. |
usLvdsSSPercentage: LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting. |
usLvdsSSpreadRateIn10Hz: LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. |
usHDMISSPercentage: HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting. |
usHDMISSpreadRateIn10Hz: HDMI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. |
usDVISSPercentage: DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting. |
usDVISSpreadRateIn10Hz: DVI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. |
usGPUReservedSysMemSize: Reserved system memory size for ACP engine in APU GNB, units in MB. 0/2/4MB based on CMOS options, current default could be 0MB. KV only, not on KB. |
ulGPUReservedSysMemBaseAddrLo: Low 32 bits base address to the reserved system memory. |
ulGPUReservedSysMemBaseAddrHi: High 32 bits base address to the reserved system memory. |
usMaxLVDSPclkFreqInSingleLink: Max pixel clock LVDS panel single link, if=0 means VBIOS use default threhold, right now it is 85Mhz |
ucLVDSMisc: [bit0] LVDS 888bit panel mode =0: LVDS 888 panel in LDI mode, =1: LVDS 888 panel in FPDI mode |
[bit1] LVDS panel lower and upper link mapping =0: lower link and upper link not swap, =1: lower link and upper link are swapped |
[bit2] LVDS 888bit per color mode =0: 666 bit per color =1:888 bit per color |
[bit3] LVDS parameter override enable =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used |
[bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low ) |
[bit5] Travid LVDS output voltage override enable, when =1, use ucTravisLVDSVolAdjust value to overwrite Traivs register LVDS_CTRL_4 |
ucTravisLVDSVolAdjust When ucLVDSMisc[5]=1,it means platform SBIOS want to overwrite TravisLVDSVoltage. Then VBIOS will use ucTravisLVDSVolAdjust |
value to program Travis register LVDS_CTRL_4 |
ucLVDSPwrOnSeqDIGONtoDE_in4Ms: |
LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ). |
=0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucLVDSPwrOnDEtoVARY_BL_in4Ms: |
LVDS power up sequence time in unit of 4ms., time delay from DE( data enable ) active to Vary Brightness enable signal active( VARY_BL ). |
=0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucLVDSPwrOffVARY_BLtoDE_in4Ms: |
LVDS power down sequence time in unit of 4ms, time delay from data enable ( DE ) signal off to LCDVCC (DIGON) off. |
=0 mean use VBIOS default delay which is 8 ( 32ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucLVDSPwrOffDEtoDIGON_in4Ms: |
LVDS power down sequence time in unit of 4ms, time delay from vary brightness enable signal( VARY_BL) off to data enable ( DE ) signal off. |
=0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucLVDSOffToOnDelay_in4Ms: |
LVDS power down sequence time in unit of 4ms. Time delay from DIGON signal off to DIGON signal active. |
=0 means to use VBIOS default delay which is 125 ( 500ms ). |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms: |
LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. |
=0 means to use VBIOS default delay which is 0 ( 0ms ). |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms: |
LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. |
=0 means to use VBIOS default delay which is 0 ( 0ms ). |
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable. |
ucMinAllowedBL_Level: Lowest LCD backlight PWM level. This is customer platform specific parameters. By default it is 0. |
ulLCDBitDepthControlVal: GPU display control encoder bit dither control setting, used to program register mmFMT_BIT_DEPTH_CONTROL |
ulNbpStateMemclkFreq[4]: system memory clock frequncey in unit of 10Khz in different NB P-State(P0, P1, P2 & P3). |
ulNbpStateNClkFreq[4]: NB P-State NClk frequency in different NB P-State |
usNBPStateVoltage[4]: NB P-State (P0/P1 & P2/P3) voltage; NBP3 refers to lowes voltage |
usBootUpNBVoltage: NB P-State voltage during boot up before driver loaded |
sExtDispConnInfo: Display connector information table provided to VBIOS |
**********************************************************************************************************************/ |
// this Table is used for Kaveri/Kabini APU |
typedef struct _ATOM_FUSION_SYSTEM_INFO_V2 |
{ |
ATOM_INTEGRATED_SYSTEM_INFO_V1_8 sIntegratedSysInfo; // refer to ATOM_INTEGRATED_SYSTEM_INFO_V1_8 definition |
ULONG ulPowerplayTable[128]; // Update comments here to link new powerplay table definition structure |
}ATOM_FUSION_SYSTEM_INFO_V2; |
/**************************************************************************/ |
// This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design |
//Memory SS Info Table |
5036,12 → 5489,14 |
#define ASIC_INTERNAL_SS_ON_DCPLL 8 |
#define ASIC_EXTERNAL_SS_ON_DP_CLOCK 9 |
#define ASIC_INTERNAL_VCE_SS 10 |
#define ASIC_INTERNAL_GPUPLL_SS 11 |
typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2 |
{ |
ULONG ulTargetClockRange; //For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz |
//For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 ) |
USHORT usSpreadSpectrumPercentage; //in unit of 0.01% |
USHORT usSpreadSpectrumPercentage; //in unit of 0.01% or 0.001%, decided by ucSpreadSpectrumMode bit4 |
USHORT usSpreadRateIn10Hz; //in unit of 10Hz, modulation freq |
UCHAR ucClockIndication; //Indicate which clock source needs SS |
UCHAR ucSpreadSpectrumMode; //Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS |
5079,6 → 5534,11 |
UCHAR ucReserved[2]; |
}ATOM_ASIC_SS_ASSIGNMENT_V3; |
//ATOM_ASIC_SS_ASSIGNMENT_V3.ucSpreadSpectrumMode |
#define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01 |
#define SS_MODE_V3_EXTERNAL_SS_MASK 0x02 |
#define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 |
typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 |
{ |
ATOM_COMMON_TABLE_HEADER sHeader; |
5447,6 → 5907,8 |
#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 |
5719,6 → 6181,7 |
#define INDIRECT_IO_PCIE 3 |
#define INDIRECT_IO_PCIEP 4 |
#define INDIRECT_IO_NBMISC 5 |
#define INDIRECT_IO_SMU 5 |
#define INDIRECT_IO_PLL_READ INDIRECT_IO_PLL | INDIRECT_READ |
#define INDIRECT_IO_PLL_WRITE INDIRECT_IO_PLL | INDIRECT_WRITE |
5730,6 → 6193,8 |
#define INDIRECT_IO_PCIEP_WRITE INDIRECT_IO_PCIEP | INDIRECT_WRITE |
#define INDIRECT_IO_NBMISC_READ INDIRECT_IO_NBMISC | INDIRECT_READ |
#define INDIRECT_IO_NBMISC_WRITE INDIRECT_IO_NBMISC | INDIRECT_WRITE |
#define INDIRECT_IO_SMU_READ INDIRECT_IO_SMU | INDIRECT_READ |
#define INDIRECT_IO_SMU_WRITE INDIRECT_IO_SMU | INDIRECT_WRITE |
typedef struct _ATOM_OEM_INFO |
{ |
5875,8 → 6340,10 |
#define _64Mx32 0x43 |
#define _128Mx8 0x51 |
#define _128Mx16 0x52 |
#define _128Mx32 0x53 |
#define _256Mx8 0x61 |
#define _256Mx16 0x62 |
#define _512Mx8 0x71 |
#define SAMSUNG 0x1 |
#define INFINEON 0x2 |
5893,7 → 6360,9 |
#define PROMOS MOSEL |
#define KRETON INFINEON |
#define ELIXIR NANYA |
#define MEZZA ELPIDA |
/////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// |
#define UCODE_ROM_START_ADDRESS 0x1b800 |
6621,10 → 7090,15 |
UCHAR ucMaxActiveDispEngineNum; |
UCHAR ucMaxPPLLNum; |
UCHAR ucCoreRefClkSource; // value of CORE_REF_CLK_SOURCE |
UCHAR ucReserved[3]; |
UCHAR ucDispCaps; |
UCHAR ucReserved[2]; |
ASIC_TRANSMITTER_INFO_V2 asTransmitterInfo[1]; // for alligment only |
}ATOM_DISP_OUT_INFO_V3; |
//ucDispCaps |
#define DISPLAY_CAPS__DP_PCLK_FROM_PPLL 0x01 |
#define DISPLAY_CAPS__FORCE_DISPDEV_CONNECTED 0x02 |
typedef enum CORE_REF_CLK_SOURCE{ |
CLOCK_SRC_XTALIN=0, |
CLOCK_SRC_XO_IN=1, |
6829,6 → 7303,17 |
USHORT usPhyPllSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings |
}DIG_TRANSMITTER_INFO_HEADER_V3_1; |
typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_2{ |
ATOM_COMMON_TABLE_HEADER sHeader; |
USHORT usDPVsPreEmphSettingOffset; // offset of PHY_ANALOG_SETTING_INFO * with DP Voltage Swing and Pre-Emphasis for each Link clock |
USHORT usPhyAnalogRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with None-DP mode Analog Setting's register Info |
USHORT usPhyAnalogSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with None-DP mode Analog Setting for each link clock range |
USHORT usPhyPllRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy Pll register Info |
USHORT usPhyPllSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings |
USHORT usDPSSRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy SS Pll register Info |
USHORT usDPSSSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy SS Pll Settings |
}DIG_TRANSMITTER_INFO_HEADER_V3_2; |
typedef struct _CLOCK_CONDITION_REGESTER_INFO{ |
USHORT usRegisterIndex; |
UCHAR ucStartBit; |
6852,6 → 7337,12 |
ULONG ulRegVal; |
}PHY_CONDITION_REG_VAL; |
typedef struct _PHY_CONDITION_REG_VAL_V2{ |
ULONG ulCondition; |
UCHAR ucCondition2; |
ULONG ulRegVal; |
}PHY_CONDITION_REG_VAL_V2; |
typedef struct _PHY_CONDITION_REG_INFO{ |
USHORT usRegIndex; |
USHORT usSize; |
6858,6 → 7349,12 |
PHY_CONDITION_REG_VAL asRegVal[1]; |
}PHY_CONDITION_REG_INFO; |
typedef struct _PHY_CONDITION_REG_INFO_V2{ |
USHORT usRegIndex; |
USHORT usSize; |
PHY_CONDITION_REG_VAL_V2 asRegVal[1]; |
}PHY_CONDITION_REG_INFO_V2; |
typedef struct _PHY_ANALOG_SETTING_INFO{ |
UCHAR ucEncodeMode; |
UCHAR ucPhySel; |
6865,6 → 7362,25 |
PHY_CONDITION_REG_INFO asAnalogSetting[1]; |
}PHY_ANALOG_SETTING_INFO; |
typedef struct _PHY_ANALOG_SETTING_INFO_V2{ |
UCHAR ucEncodeMode; |
UCHAR ucPhySel; |
USHORT usSize; |
PHY_CONDITION_REG_INFO_V2 asAnalogSetting[1]; |
}PHY_ANALOG_SETTING_INFO_V2; |
typedef struct _GFX_HAVESTING_PARAMETERS { |
UCHAR ucGfxBlkId; //GFX blk id to be harvested, like CU, RB or PRIM |
UCHAR ucReserved; //reserved |
UCHAR ucActiveUnitNumPerSH; //requested active CU/RB/PRIM number per shader array |
UCHAR ucMaxUnitNumPerSH; //max CU/RB/PRIM number per shader array |
} GFX_HAVESTING_PARAMETERS; |
//ucGfxBlkId |
#define GFX_HARVESTING_CU_ID 0 |
#define GFX_HARVESTING_RB_ID 1 |
#define GFX_HARVESTING_PRIM_ID 2 |
/****************************************************************************/ |
//Portion VI: Definitinos for vbios MC scratch registers that driver used |
/****************************************************************************/ |
6875,8 → 7391,17 |
#define MC_MISC0__MEMORY_TYPE__GDDR3 0x30000000 |
#define MC_MISC0__MEMORY_TYPE__GDDR4 0x40000000 |
#define MC_MISC0__MEMORY_TYPE__GDDR5 0x50000000 |
#define MC_MISC0__MEMORY_TYPE__HBM 0x60000000 |
#define MC_MISC0__MEMORY_TYPE__DDR3 0xB0000000 |
#define ATOM_MEM_TYPE_DDR_STRING "DDR" |
#define ATOM_MEM_TYPE_DDR2_STRING "DDR2" |
#define ATOM_MEM_TYPE_GDDR3_STRING "GDDR3" |
#define ATOM_MEM_TYPE_GDDR4_STRING "GDDR4" |
#define ATOM_MEM_TYPE_GDDR5_STRING "GDDR5" |
#define ATOM_MEM_TYPE_HBM_STRING "HBM" |
#define ATOM_MEM_TYPE_DDR3_STRING "DDR3" |
/****************************************************************************/ |
//Portion VI: Definitinos being oboselete |
/****************************************************************************/ |
7239,566 → 7764,7 |
ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; |
}ATOM_POWERPLAY_INFO_V3; |
/* New PPlib */ |
/**************************************************************************/ |
typedef struct _ATOM_PPLIB_THERMALCONTROLLER |
{ |
UCHAR ucType; // one of ATOM_PP_THERMALCONTROLLER_* |
UCHAR ucI2cLine; // as interpreted by DAL I2C |
UCHAR ucI2cAddress; |
UCHAR ucFanParameters; // Fan Control Parameters. |
UCHAR ucFanMinRPM; // Fan Minimum RPM (hundreds) -- for display purposes only. |
UCHAR ucFanMaxRPM; // Fan Maximum RPM (hundreds) -- for display purposes only. |
UCHAR ucReserved; // ---- |
UCHAR ucFlags; // to be defined |
} ATOM_PPLIB_THERMALCONTROLLER; |
#define ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f |
#define ATOM_PP_FANPARAMETERS_NOFAN 0x80 // No fan is connected to this controller. |
#define ATOM_PP_THERMALCONTROLLER_NONE 0 |
#define ATOM_PP_THERMALCONTROLLER_LM63 1 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_ADM1032 2 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_ADM1030 3 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_MUA6649 4 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_LM64 5 |
#define ATOM_PP_THERMALCONTROLLER_F75375 6 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_RV6xx 7 |
#define ATOM_PP_THERMALCONTROLLER_RV770 8 |
#define ATOM_PP_THERMALCONTROLLER_ADT7473 9 |
#define ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO 11 |
#define ATOM_PP_THERMALCONTROLLER_EVERGREEN 12 |
#define ATOM_PP_THERMALCONTROLLER_EMC2103 13 /* 0x0D */ // Only fan control will be implemented, do NOT show this in PPGen. |
#define ATOM_PP_THERMALCONTROLLER_SUMO 14 /* 0x0E */ // Sumo type, used internally |
#define ATOM_PP_THERMALCONTROLLER_NISLANDS 15 |
#define ATOM_PP_THERMALCONTROLLER_SISLANDS 16 |
#define ATOM_PP_THERMALCONTROLLER_LM96163 17 |
// Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal. |
// We probably should reserve the bit 0x80 for this use. |
// To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here). |
// The driver can pick the correct internal controller based on the ASIC. |
#define ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 // ADT7473 Fan Control + Internal Thermal Controller |
#define ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL 0x8D // EMC2103 Fan Control + Internal Thermal Controller |
typedef struct _ATOM_PPLIB_STATE |
{ |
UCHAR ucNonClockStateIndex; |
UCHAR ucClockStateIndices[1]; // variable-sized |
} ATOM_PPLIB_STATE; |
typedef struct _ATOM_PPLIB_FANTABLE |
{ |
UCHAR ucFanTableFormat; // Change this if the table format changes or version changes so that the other fields are not the same. |
UCHAR ucTHyst; // Temperature hysteresis. Integer. |
USHORT usTMin; // The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. |
USHORT usTMed; // The middle temperature where we change slopes. |
USHORT usTHigh; // The high point above TMed for adjusting the second slope. |
USHORT usPWMMin; // The minimum PWM value in percent (0.01% increments). |
USHORT usPWMMed; // The PWM value (in percent) at TMed. |
USHORT usPWMHigh; // The PWM value at THigh. |
} ATOM_PPLIB_FANTABLE; |
typedef struct _ATOM_PPLIB_FANTABLE2 |
{ |
ATOM_PPLIB_FANTABLE basicTable; |
USHORT usTMax; // The max temperature |
} ATOM_PPLIB_FANTABLE2; |
typedef struct _ATOM_PPLIB_EXTENDEDHEADER |
{ |
USHORT usSize; |
ULONG ulMaxEngineClock; // For Overdrive. |
ULONG ulMaxMemoryClock; // For Overdrive. |
// Add extra system parameters here, always adjust size to include all fields. |
USHORT usVCETableOffset; //points to ATOM_PPLIB_VCE_Table |
USHORT usUVDTableOffset; //points to ATOM_PPLIB_UVD_Table |
} ATOM_PPLIB_EXTENDEDHEADER; |
//// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps |
#define ATOM_PP_PLATFORM_CAP_BACKBIAS 1 |
#define ATOM_PP_PLATFORM_CAP_POWERPLAY 2 |
#define ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 4 |
#define ATOM_PP_PLATFORM_CAP_ASPM_L0s 8 |
#define ATOM_PP_PLATFORM_CAP_ASPM_L1 16 |
#define ATOM_PP_PLATFORM_CAP_HARDWAREDC 32 |
#define ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY 64 |
#define ATOM_PP_PLATFORM_CAP_STEPVDDC 128 |
#define ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL 256 |
#define ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL 512 |
#define ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 1024 |
#define ATOM_PP_PLATFORM_CAP_HTLINKCONTROL 2048 |
#define ATOM_PP_PLATFORM_CAP_MVDDCONTROL 4096 |
#define ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT 0x2000 // Go to boot state on alerts, e.g. on an AC->DC transition. |
#define ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT 0x4000 // Do NOT wait for VBLANK during an alert (e.g. AC->DC transition). |
#define ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000 // Does the driver control VDDCI independently from VDDC. |
#define ATOM_PP_PLATFORM_CAP_REGULATOR_HOT 0x00010000 // Enable the 'regulator hot' feature. |
#define ATOM_PP_PLATFORM_CAP_BACO 0x00020000 // Does the driver supports BACO state. |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE |
{ |
ATOM_COMMON_TABLE_HEADER sHeader; |
UCHAR ucDataRevision; |
UCHAR ucNumStates; |
UCHAR ucStateEntrySize; |
UCHAR ucClockInfoSize; |
UCHAR ucNonClockSize; |
// offset from start of this table to array of ucNumStates ATOM_PPLIB_STATE structures |
USHORT usStateArrayOffset; |
// offset from start of this table to array of ASIC-specific structures, |
// currently ATOM_PPLIB_CLOCK_INFO. |
USHORT usClockInfoArrayOffset; |
// offset from start of this table to array of ATOM_PPLIB_NONCLOCK_INFO |
USHORT usNonClockInfoArrayOffset; |
USHORT usBackbiasTime; // in microseconds |
USHORT usVoltageTime; // in microseconds |
USHORT usTableSize; //the size of this structure, or the extended structure |
ULONG ulPlatformCaps; // See ATOM_PPLIB_CAPS_* |
ATOM_PPLIB_THERMALCONTROLLER sThermalController; |
USHORT usBootClockInfoOffset; |
USHORT usBootNonClockInfoOffset; |
} ATOM_PPLIB_POWERPLAYTABLE; |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE2 |
{ |
ATOM_PPLIB_POWERPLAYTABLE basicTable; |
UCHAR ucNumCustomThermalPolicy; |
USHORT usCustomThermalPolicyArrayOffset; |
}ATOM_PPLIB_POWERPLAYTABLE2, *LPATOM_PPLIB_POWERPLAYTABLE2; |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE3 |
{ |
ATOM_PPLIB_POWERPLAYTABLE2 basicTable2; |
USHORT usFormatID; // To be used ONLY by PPGen. |
USHORT usFanTableOffset; |
USHORT usExtendendedHeaderOffset; |
} ATOM_PPLIB_POWERPLAYTABLE3, *LPATOM_PPLIB_POWERPLAYTABLE3; |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE4 |
{ |
ATOM_PPLIB_POWERPLAYTABLE3 basicTable3; |
ULONG ulGoldenPPID; // PPGen use only |
ULONG ulGoldenRevision; // PPGen use only |
USHORT usVddcDependencyOnSCLKOffset; |
USHORT usVddciDependencyOnMCLKOffset; |
USHORT usVddcDependencyOnMCLKOffset; |
USHORT usMaxClockVoltageOnDCOffset; |
USHORT usVddcPhaseShedLimitsTableOffset; // Points to ATOM_PPLIB_PhaseSheddingLimits_Table |
USHORT usReserved; |
} ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4; |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE5 |
{ |
ATOM_PPLIB_POWERPLAYTABLE4 basicTable4; |
ULONG ulTDPLimit; |
ULONG ulNearTDPLimit; |
ULONG ulSQRampingThreshold; |
USHORT usCACLeakageTableOffset; // Points to ATOM_PPLIB_CAC_Leakage_Table |
ULONG ulCACLeakage; // The iLeakage for driver calculated CAC leakage table |
USHORT usTDPODLimit; |
USHORT usLoadLineSlope; // in milliOhms * 100 |
} ATOM_PPLIB_POWERPLAYTABLE5, *LPATOM_PPLIB_POWERPLAYTABLE5; |
//// ATOM_PPLIB_NONCLOCK_INFO::usClassification |
#define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007 |
#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0 |
#define ATOM_PPLIB_CLASSIFICATION_UI_NONE 0 |
#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY 1 |
#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED 3 |
#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE 5 |
// 2, 4, 6, 7 are reserved |
#define ATOM_PPLIB_CLASSIFICATION_BOOT 0x0008 |
#define ATOM_PPLIB_CLASSIFICATION_THERMAL 0x0010 |
#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE 0x0020 |
#define ATOM_PPLIB_CLASSIFICATION_REST 0x0040 |
#define ATOM_PPLIB_CLASSIFICATION_FORCED 0x0080 |
#define ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE 0x0100 |
#define ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE 0x0200 |
#define ATOM_PPLIB_CLASSIFICATION_UVDSTATE 0x0400 |
#define ATOM_PPLIB_CLASSIFICATION_3DLOW 0x0800 |
#define ATOM_PPLIB_CLASSIFICATION_ACPI 0x1000 |
#define ATOM_PPLIB_CLASSIFICATION_HD2STATE 0x2000 |
#define ATOM_PPLIB_CLASSIFICATION_HDSTATE 0x4000 |
#define ATOM_PPLIB_CLASSIFICATION_SDSTATE 0x8000 |
//// ATOM_PPLIB_NONCLOCK_INFO::usClassification2 |
#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001 |
#define ATOM_PPLIB_CLASSIFICATION2_ULV 0x0002 |
#define ATOM_PPLIB_CLASSIFICATION2_MVC 0x0004 //Multi-View Codec (BD-3D) |
//// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings |
#define ATOM_PPLIB_SINGLE_DISPLAY_ONLY 0x00000001 |
#define ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK 0x00000002 |
// 0 is 2.5Gb/s, 1 is 5Gb/s |
#define ATOM_PPLIB_PCIE_LINK_SPEED_MASK 0x00000004 |
#define ATOM_PPLIB_PCIE_LINK_SPEED_SHIFT 2 |
// lanes - 1: 1, 2, 4, 8, 12, 16 permitted by PCIE spec |
#define ATOM_PPLIB_PCIE_LINK_WIDTH_MASK 0x000000F8 |
#define ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT 3 |
// lookup into reduced refresh-rate table |
#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK 0x00000F00 |
#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT 8 |
#define ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED 0 |
#define ATOM_PPLIB_LIMITED_REFRESHRATE_50HZ 1 |
// 2-15 TBD as needed. |
#define ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING 0x00001000 |
#define ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS 0x00002000 |
#define ATOM_PPLIB_DISALLOW_ON_DC 0x00004000 |
#define ATOM_PPLIB_ENABLE_VARIBRIGHT 0x00008000 |
//memory related flags |
#define ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF 0x000010000 |
//M3 Arb //2bits, current 3 sets of parameters in total |
#define ATOM_PPLIB_M3ARB_MASK 0x00060000 |
#define ATOM_PPLIB_M3ARB_SHIFT 17 |
#define ATOM_PPLIB_ENABLE_DRR 0x00080000 |
// remaining 16 bits are reserved |
typedef struct _ATOM_PPLIB_THERMAL_STATE |
{ |
UCHAR ucMinTemperature; |
UCHAR ucMaxTemperature; |
UCHAR ucThermalAction; |
}ATOM_PPLIB_THERMAL_STATE, *LPATOM_PPLIB_THERMAL_STATE; |
// Contained in an array starting at the offset |
// in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset. |
// referenced from ATOM_PPLIB_STATE_INFO::ucNonClockStateIndex |
#define ATOM_PPLIB_NONCLOCKINFO_VER1 12 |
#define ATOM_PPLIB_NONCLOCKINFO_VER2 24 |
typedef struct _ATOM_PPLIB_NONCLOCK_INFO |
{ |
USHORT usClassification; |
UCHAR ucMinTemperature; |
UCHAR ucMaxTemperature; |
ULONG ulCapsAndSettings; |
UCHAR ucRequiredPower; |
USHORT usClassification2; |
ULONG ulVCLK; |
ULONG ulDCLK; |
UCHAR ucUnused[5]; |
} ATOM_PPLIB_NONCLOCK_INFO; |
// Contained in an array starting at the offset |
// in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset. |
// referenced from ATOM_PPLIB_STATE::ucClockStateIndices |
typedef struct _ATOM_PPLIB_R600_CLOCK_INFO |
{ |
USHORT usEngineClockLow; |
UCHAR ucEngineClockHigh; |
USHORT usMemoryClockLow; |
UCHAR ucMemoryClockHigh; |
USHORT usVDDC; |
USHORT usUnused1; |
USHORT usUnused2; |
ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_* |
} ATOM_PPLIB_R600_CLOCK_INFO; |
// ulFlags in ATOM_PPLIB_R600_CLOCK_INFO |
#define ATOM_PPLIB_R600_FLAGS_PCIEGEN2 1 |
#define ATOM_PPLIB_R600_FLAGS_UVDSAFE 2 |
#define ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE 4 |
#define ATOM_PPLIB_R600_FLAGS_MEMORY_ODT_OFF 8 |
#define ATOM_PPLIB_R600_FLAGS_MEMORY_DLL_OFF 16 |
#define ATOM_PPLIB_R600_FLAGS_LOWPOWER 32 // On the RV770 use 'low power' setting (sequencer S0). |
typedef struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO |
{ |
USHORT usEngineClockLow; |
UCHAR ucEngineClockHigh; |
USHORT usMemoryClockLow; |
UCHAR ucMemoryClockHigh; |
USHORT usVDDC; |
USHORT usVDDCI; |
USHORT usUnused; |
ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_* |
} ATOM_PPLIB_EVERGREEN_CLOCK_INFO; |
typedef struct _ATOM_PPLIB_SI_CLOCK_INFO |
{ |
USHORT usEngineClockLow; |
UCHAR ucEngineClockHigh; |
USHORT usMemoryClockLow; |
UCHAR ucMemoryClockHigh; |
USHORT usVDDC; |
USHORT usVDDCI; |
UCHAR ucPCIEGen; |
UCHAR ucUnused1; |
ULONG ulFlags; // ATOM_PPLIB_SI_FLAGS_*, no flag is necessary for now |
} ATOM_PPLIB_SI_CLOCK_INFO; |
typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO |
{ |
USHORT usLowEngineClockLow; // Low Engine clock in MHz (the same way as on the R600). |
UCHAR ucLowEngineClockHigh; |
USHORT usHighEngineClockLow; // High Engine clock in MHz. |
UCHAR ucHighEngineClockHigh; |
USHORT usMemoryClockLow; // For now one of the ATOM_PPLIB_RS780_SPMCLK_XXXX constants. |
UCHAR ucMemoryClockHigh; // Currentyl unused. |
UCHAR ucPadding; // For proper alignment and size. |
USHORT usVDDC; // For the 780, use: None, Low, High, Variable |
UCHAR ucMaxHTLinkWidth; // From SBIOS - {2, 4, 8, 16} |
UCHAR ucMinHTLinkWidth; // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requriement. |
USHORT usHTLinkFreq; // See definition ATOM_PPLIB_RS780_HTLINKFREQ_xxx or in MHz(>=200). |
ULONG ulFlags; |
} ATOM_PPLIB_RS780_CLOCK_INFO; |
#define ATOM_PPLIB_RS780_VOLTAGE_NONE 0 |
#define ATOM_PPLIB_RS780_VOLTAGE_LOW 1 |
#define ATOM_PPLIB_RS780_VOLTAGE_HIGH 2 |
#define ATOM_PPLIB_RS780_VOLTAGE_VARIABLE 3 |
#define ATOM_PPLIB_RS780_SPMCLK_NONE 0 // We cannot change the side port memory clock, leave it as it is. |
#define ATOM_PPLIB_RS780_SPMCLK_LOW 1 |
#define ATOM_PPLIB_RS780_SPMCLK_HIGH 2 |
#define ATOM_PPLIB_RS780_HTLINKFREQ_NONE 0 |
#define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1 |
#define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2 |
typedef struct _ATOM_PPLIB_SUMO_CLOCK_INFO{ |
USHORT usEngineClockLow; //clockfrequency & 0xFFFF. The unit is in 10khz |
UCHAR ucEngineClockHigh; //clockfrequency >> 16. |
UCHAR vddcIndex; //2-bit vddc index; |
USHORT tdpLimit; |
//please initalize to 0 |
USHORT rsv1; |
//please initialize to 0s |
ULONG rsv2[2]; |
}ATOM_PPLIB_SUMO_CLOCK_INFO; |
typedef struct _ATOM_PPLIB_STATE_V2 |
{ |
//number of valid dpm levels in this state; Driver uses it to calculate the whole |
//size of the state: sizeof(ATOM_PPLIB_STATE_V2) + (ucNumDPMLevels - 1) * sizeof(UCHAR) |
UCHAR ucNumDPMLevels; |
//a index to the array of nonClockInfos |
UCHAR nonClockInfoIndex; |
/** |
* Driver will read the first ucNumDPMLevels in this array |
*/ |
UCHAR clockInfoIndex[1]; |
} ATOM_PPLIB_STATE_V2; |
typedef struct _StateArray{ |
//how many states we have |
UCHAR ucNumEntries; |
ATOM_PPLIB_STATE_V2 states[1]; |
}StateArray; |
typedef struct _ClockInfoArray{ |
//how many clock levels we have |
UCHAR ucNumEntries; |
//sizeof(ATOM_PPLIB_CLOCK_INFO) |
UCHAR ucEntrySize; |
UCHAR clockInfo[1]; |
}ClockInfoArray; |
typedef struct _NonClockInfoArray{ |
//how many non-clock levels we have. normally should be same as number of states |
UCHAR ucNumEntries; |
//sizeof(ATOM_PPLIB_NONCLOCK_INFO) |
UCHAR ucEntrySize; |
ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[1]; |
}NonClockInfoArray; |
typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Record |
{ |
USHORT usClockLow; |
UCHAR ucClockHigh; |
USHORT usVoltage; |
}ATOM_PPLIB_Clock_Voltage_Dependency_Record; |
typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Table |
{ |
UCHAR ucNumEntries; // Number of entries. |
ATOM_PPLIB_Clock_Voltage_Dependency_Record entries[1]; // Dynamically allocate entries. |
}ATOM_PPLIB_Clock_Voltage_Dependency_Table; |
typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Record |
{ |
USHORT usSclkLow; |
UCHAR ucSclkHigh; |
USHORT usMclkLow; |
UCHAR ucMclkHigh; |
USHORT usVddc; |
USHORT usVddci; |
}ATOM_PPLIB_Clock_Voltage_Limit_Record; |
typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table |
{ |
UCHAR ucNumEntries; // Number of entries. |
ATOM_PPLIB_Clock_Voltage_Limit_Record entries[1]; // Dynamically allocate entries. |
}ATOM_PPLIB_Clock_Voltage_Limit_Table; |
typedef struct _ATOM_PPLIB_CAC_Leakage_Record |
{ |
USHORT usVddc; // We use this field for the "fake" standardized VDDC for power calculations |
ULONG ulLeakageValue; |
}ATOM_PPLIB_CAC_Leakage_Record; |
typedef struct _ATOM_PPLIB_CAC_Leakage_Table |
{ |
UCHAR ucNumEntries; // Number of entries. |
ATOM_PPLIB_CAC_Leakage_Record entries[1]; // Dynamically allocate entries. |
}ATOM_PPLIB_CAC_Leakage_Table; |
typedef struct _ATOM_PPLIB_PhaseSheddingLimits_Record |
{ |
USHORT usVoltage; |
USHORT usSclkLow; |
UCHAR ucSclkHigh; |
USHORT usMclkLow; |
UCHAR ucMclkHigh; |
}ATOM_PPLIB_PhaseSheddingLimits_Record; |
typedef struct _ATOM_PPLIB_PhaseSheddingLimits_Table |
{ |
UCHAR ucNumEntries; // Number of entries. |
ATOM_PPLIB_PhaseSheddingLimits_Record entries[1]; // Dynamically allocate entries. |
}ATOM_PPLIB_PhaseSheddingLimits_Table; |
typedef struct _VCEClockInfo{ |
USHORT usEVClkLow; |
UCHAR ucEVClkHigh; |
USHORT usECClkLow; |
UCHAR ucECClkHigh; |
}VCEClockInfo; |
typedef struct _VCEClockInfoArray{ |
UCHAR ucNumEntries; |
VCEClockInfo entries[1]; |
}VCEClockInfoArray; |
typedef struct _ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record |
{ |
USHORT usVoltage; |
UCHAR ucVCEClockInfoIndex; |
}ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record; |
typedef struct _ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table |
{ |
UCHAR numEntries; |
ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record entries[1]; |
}ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table; |
typedef struct _ATOM_PPLIB_VCE_State_Record |
{ |
UCHAR ucVCEClockInfoIndex; |
UCHAR ucClockInfoIndex; //highest 2 bits indicates memory p-states, lower 6bits indicates index to ClockInfoArrary |
}ATOM_PPLIB_VCE_State_Record; |
typedef struct _ATOM_PPLIB_VCE_State_Table |
{ |
UCHAR numEntries; |
ATOM_PPLIB_VCE_State_Record entries[1]; |
}ATOM_PPLIB_VCE_State_Table; |
typedef struct _ATOM_PPLIB_VCE_Table |
{ |
UCHAR revid; |
// VCEClockInfoArray array; |
// ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table limits; |
// ATOM_PPLIB_VCE_State_Table states; |
}ATOM_PPLIB_VCE_Table; |
typedef struct _UVDClockInfo{ |
USHORT usVClkLow; |
UCHAR ucVClkHigh; |
USHORT usDClkLow; |
UCHAR ucDClkHigh; |
}UVDClockInfo; |
typedef struct _UVDClockInfoArray{ |
UCHAR ucNumEntries; |
UVDClockInfo entries[1]; |
}UVDClockInfoArray; |
typedef struct _ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record |
{ |
USHORT usVoltage; |
UCHAR ucUVDClockInfoIndex; |
}ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record; |
typedef struct _ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table |
{ |
UCHAR numEntries; |
ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record entries[1]; |
}ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table; |
typedef struct _ATOM_PPLIB_UVD_State_Record |
{ |
UCHAR ucUVDClockInfoIndex; |
UCHAR ucClockInfoIndex; //highest 2 bits indicates memory p-states, lower 6bits indicates index to ClockInfoArrary |
}ATOM_PPLIB_UVD_State_Record; |
typedef struct _ATOM_PPLIB_UVD_State_Table |
{ |
UCHAR numEntries; |
ATOM_PPLIB_UVD_State_Record entries[1]; |
}ATOM_PPLIB_UVD_State_Table; |
typedef struct _ATOM_PPLIB_UVD_Table |
{ |
UCHAR revid; |
// UVDClockInfoArray array; |
// ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table limits; |
// ATOM_PPLIB_UVD_State_Table states; |
}ATOM_PPLIB_UVD_Table; |
/**************************************************************************/ |
// Following definitions are for compatibility issue in different SW components. |
#define ATOM_MASTER_DATA_TABLE_REVISION 0x01 |
#define Object_Info Object_Header |
8010,3 → 7976,6 |
#endif /* _ATOMBIOS_H */ |
#include "pptable.h" |
/drivers/video/drm/radeon/atombios_crtc.c |
---|
209,6 → 209,16 |
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,14 → 226,24 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 */ |
555,7 → 579,7 |
if (rdev->family < CHIP_RV770) |
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; |
/* use frac fb div on APUs */ |
if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) |
if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev)) |
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; |
/* use frac fb div on RS780/RS880 */ |
if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) |
609,6 → 633,24 |
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 |
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 |
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 |
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; |
743,7 → 781,7 |
* SetPixelClock provides the dividers |
*/ |
args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); |
if (ASIC_IS_DCE61(rdev)) |
if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev)) |
args.v6.ucPpll = ATOM_EXT_PLL1; |
else if (ASIC_IS_DCE6(rdev)) |
args.v6.ucPpll = ATOM_PPLL0; |
839,6 → 877,7 |
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; |
if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { |
switch (bpc) { |
case 8: |
default: |
845,9 → 884,15 |
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; |
args.v5.ucPpll = pll_id; |
861,6 → 906,7 |
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; |
if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { |
switch (bpc) { |
case 8: |
default: |
867,15 → 913,16 |
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; |
break; |
case 10: |
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP; |
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6; |
break; |
case 12: |
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP; |
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; |
args.v6.ucPpll = pll_id; |
915,6 → 962,9 |
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,12 → 988,15 |
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: |
if (ASIC_IS_DCE4(rdev)) |
993,10 → 1046,17 |
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 |
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 |
/* 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 |
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 |
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,24 → 1175,44 |
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 |
1136,16 → 1219,78 |
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_TAHITI) |
tmp = rdev->config.si.tile_config; |
else if (rdev->family >= CHIP_CAYMAN) |
evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); |
/* 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; |
1162,21 → 1307,33 |
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); |
fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect); |
if (rdev->family >= CHIP_BONAIRE) { |
/* XXX need to know more about the surface tiling mode */ |
fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING); |
} |
} else if (tiling_flags & RADEON_TILING_MICRO) |
fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); |
if ((rdev->family == CHIP_TAHITI) || |
if (rdev->family >= CHIP_BONAIRE) { |
/* 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) { |
1213,6 → 1370,18 |
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); |
1224,6 → 1393,10 |
WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); |
WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); |
if (rdev->family >= CHIP_BONAIRE) |
WREG32(CIK_LB_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, |
target_fb->height); |
else |
WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, |
target_fb->height); |
x &= ~3; |
1241,10 → 1414,10 |
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); |
1276,9 → 1449,10 |
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; |
} |
1288,8 → 1462,8 |
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; |
1313,18 → 1487,30 |
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; |
1332,8 → 1518,8 |
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; |
1341,9 → 1527,20 |
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; |
} |
1382,6 → 1579,13 |
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); |
1410,10 → 1614,10 |
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); |
1597,6 → 1801,12 |
* |
* Asic specific PLL information |
* |
* DCE 8.x |
* KB/KV |
* - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) |
* CI |
* - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC |
* |
* DCE 6.1 |
* - PPLL2 is only available to UNIPHYA (both DP and non-DP) |
* - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) |
1623,7 → 1833,48 |
u32 pll_in_use; |
int pll; |
if (ASIC_IS_DCE61(rdev)) { |
if (ASIC_IS_DCE8(rdev)) { |
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; |
else { |
/* use the same PPLL for all DP monitors */ |
pll = radeon_get_shared_dp_ppll(crtc); |
if (pll != ATOM_PPLL_INVALID) |
return pll; |
} |
} else { |
/* use the same PPLL for all monitors with the same clock */ |
pll = radeon_get_shared_nondp_ppll(crtc); |
if (pll != ATOM_PPLL_INVALID) |
return pll; |
} |
/* otherwise, pick one of the plls */ |
if ((rdev->family == CHIP_KAVERI) || |
(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; |
if (!(pll_in_use & (1 << ATOM_PPLL1))) |
return ATOM_PPLL1; |
DRM_ERROR("unable to allocate a PPLL\n"); |
return ATOM_PPLL_INVALID; |
} else { |
/* CI has PPLL0, PPLL1, and PPLL2 */ |
pll_in_use = radeon_get_pll_use_mask(crtc); |
if (!(pll_in_use & (1 << ATOM_PPLL2))) |
return ATOM_PPLL2; |
if (!(pll_in_use & (1 << ATOM_PPLL1))) |
return ATOM_PPLL1; |
if (!(pll_in_use & (1 << ATOM_PPLL0))) |
return ATOM_PPLL0; |
DRM_ERROR("unable to allocate a PPLL\n"); |
return ATOM_PPLL_INVALID; |
} |
} else if (ASIC_IS_DCE61(rdev)) { |
struct radeon_encoder_atom_dig *dig = |
radeon_encoder->enc_priv; |
1656,6 → 1907,20 |
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: |
1753,6 → 2018,9 |
(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)) |
1771,6 → 2039,9 |
atombios_crtc_set_base(crtc, x, y, old_fb); |
atombios_overscan_setup(crtc, mode, adjusted_mode); |
atombios_scaler_setup(crtc); |
/* update the hw version fpr dpm */ |
radeon_crtc->hw_mode = *adjusted_mode; |
return 0; |
} |
1837,6 → 2108,27 |
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); |
else if (ASIC_IS_AVIVO(rdev)) |
WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 0); |
if (ASIC_IS_DCE6(rdev)) |
atombios_powergate_crtc(crtc, ATOM_ENABLE); |
1861,7 → 2153,9 |
break; |
case ATOM_PPLL0: |
/* disable the ppll */ |
if (ASIC_IS_DCE61(rdev)) |
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; |
/drivers/video/drm/radeon/atombios_dp.c |
---|
44,6 → 44,41 |
}; |
/***** radeon AUX functions *****/ |
/* Atom needs data in little endian format |
* so swap as appropriate when copying data to |
* or from atom. Note that atom operates on |
* dw units. |
*/ |
void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le) |
{ |
#ifdef __BIG_ENDIAN |
u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */ |
u32 *dst32, *src32; |
int i; |
memcpy(src_tmp, src, num_bytes); |
src32 = (u32 *)src_tmp; |
dst32 = (u32 *)dst_tmp; |
if (to_le) { |
for (i = 0; i < ((num_bytes + 3) / 4); i++) |
dst32[i] = cpu_to_le32(src32[i]); |
memcpy(dst, dst_tmp, num_bytes); |
} else { |
u8 dws = num_bytes & ~3; |
for (i = 0; i < ((num_bytes + 3) / 4); i++) |
dst32[i] = le32_to_cpu(src32[i]); |
memcpy(dst, dst_tmp, dws); |
if (num_bytes % 4) { |
for (i = 0; i < (num_bytes % 4); i++) |
dst[dws+i] = dst_tmp[dws+i]; |
} |
} |
#else |
memcpy(dst, src, num_bytes); |
#endif |
} |
union aux_channel_transaction { |
PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1; |
PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2; |
60,15 → 95,18 |
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); |
memcpy(base, send, send_bytes); |
radeon_atom_copy_swap(base, send, send_bytes, true); |
args.v1.lpAuxRequest = 0 + 4; |
args.v1.lpDataOut = 16 + 4; |
args.v1.lpAuxRequest = cpu_to_le16((u16)(0 + 4)); |
args.v1.lpDataOut = cpu_to_le16((u16)(16 + 4)); |
args.v1.ucDataOutLen = 0; |
args.v1.ucChannelID = chan->rec.i2c_id; |
args.v1.ucDelay = delay / 10; |
82,19 → 120,22 |
/* 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; |
102,189 → 143,91 |
recv_bytes = recv_size; |
if (recv && recv_size) |
memcpy(recv, base + 16, recv_bytes); |
radeon_atom_copy_swap(recv, base + 16, recv_bytes, false); |
return recv_bytes; |
} |
r = recv_bytes; |
done: |
mutex_unlock(&chan->mutex); |
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; |
return r; |
} |
return -EIO; |
} |
#define BARE_ADDRESS_SIZE 3 |
#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1) |
static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, |
u16 address, u8 *recv, int recv_bytes, u8 delay) |
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; |
u8 tx_buf[20]; |
size_t tx_size; |
u8 ack, delay = 0; |
msg[0] = address; |
msg[1] = address >> 8; |
msg[2] = AUX_NATIVE_READ << 4; |
msg[3] = (msg_bytes << 4) | (recv_bytes - 1); |
if (WARN_ON(msg->size > 16)) |
return -E2BIG; |
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; |
else |
return -EIO; |
} |
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; |
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); |
return val; |
} |
int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, |
u8 write_byte, u8 *read_byte) |
{ |
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; |
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 |
msg[2] = AUX_I2C_WRITE << 4; |
if (!(mode & MODE_I2C_STOP)) |
msg[2] |= AUX_I2C_MOT << 4; |
msg[0] = address; |
msg[1] = address >> 8; |
switch (mode) { |
case MODE_I2C_WRITE: |
msg_bytes = 5; |
msg[3] = msg_bytes << 4; |
msg[4] = write_byte; |
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 MODE_I2C_READ: |
msg_bytes = 4; |
msg[3] = msg_bytes << 4; |
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: |
msg_bytes = 4; |
msg[3] = 3 << 4; |
ret = -EINVAL; |
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); |
if (ret >= 0) |
msg->reply = ack >> 4; |
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; |
} |
void radeon_dp_aux_init(struct radeon_connector *radeon_connector) |
{ |
int ret; |
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; |
} |
} |
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; |
DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); |
return -EREMOTEIO; |
ret = drm_dp_aux_register(&radeon_connector->ddc_bus->aux); |
if (!ret) |
radeon_connector->ddc_bus->has_aux = true; |
WARN(ret, "drm_dp_aux_register() failed with error %d\n", ret); |
} |
/***** general DP utility functions *****/ |
349,6 → 292,19 |
/***** 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. |
358,7 → 314,7 |
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; |
396,7 → 352,7 |
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, |
419,12 → 375,11 |
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) |
435,11 → 390,11 |
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]); |
} |
448,17 → 403,19 |
{ |
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; |
u8 msg[DP_DPCD_SIZE]; |
int ret, i; |
int ret; |
ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, |
DP_DPCD_SIZE, 0); |
char dpcd_hex_dump[DP_DPCD_SIZE * 3]; |
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); |
return true; |
473,6 → 430,7 |
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; |
480,9 → 438,15 |
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 (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) || |
490,12 → 454,15 |
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 (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; |
} |
540,26 → 507,13 |
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 %*ph\n", 6, 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; |
566,11 → 520,30 |
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; |
580,6 → 553,7 |
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) |
590,8 → 564,8 |
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) |
626,7 → 600,7 |
} |
/* 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) |
636,33 → 610,30 |
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, |
drm_dp_dpcd_writeb(dp_info->aux, |
DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); |
else |
radeon_write_dpcd_reg(dp_info->radeon_connector, |
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) |
673,7 → 644,7 |
dp_info->dp_clock, dp_info->enc_id, 0); |
/* disable the training pattern on the sink */ |
radeon_write_dpcd_reg(dp_info->radeon_connector, |
drm_dp_dpcd_writeb(dp_info->aux, |
DP_TRAINING_PATTERN_SET, |
DP_TRAINING_PATTERN_DISABLE); |
685,7 → 656,7 |
udelay(400); |
/* disable the training pattern on the sink */ |
radeon_write_dpcd_reg(dp_info->radeon_connector, |
drm_dp_dpcd_writeb(dp_info->aux, |
DP_TRAINING_PATTERN_SET, |
DP_TRAINING_PATTERN_DISABLE); |
719,7 → 690,8 |
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; |
} |
781,7 → 753,8 |
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; |
} |
864,19 → 837,23 |
else |
dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A; |
tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT); |
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; |
/drivers/video/drm/radeon/atombios_encoders.c |
---|
183,9 → 183,15 |
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 |
* so don't register a backlight device |
*/ |
if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) && |
(rdev->pdev->device == 0x6741)) |
return; |
if (!radeon_encoder->enc_priv) |
return; |
206,7 → 212,7 |
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"); |
215,12 → 221,17 |
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); |
296,6 → 307,7 |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
return true; |
default: |
return false; |
319,12 → 331,10 |
&& (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) |
adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; |
/* get the native mode for LVDS */ |
if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT|ATOM_DEVICE_DFP_SUPPORT)) |
/* get the native mode for scaling */ |
if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT|ATOM_DEVICE_DFP_SUPPORT)) { |
radeon_panel_mode_fixup(encoder, adjusted_mode); |
/* get the native mode for TV */ |
if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { |
} else if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { |
struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; |
if (tv_dac) { |
if (tv_dac->tv_std == TV_STD_NTSC || |
334,6 → 344,8 |
else |
radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); |
} |
} else if (radeon_encoder->rmx_type != RMX_OFF) { |
radeon_panel_mode_fixup(encoder, adjusted_mode); |
} |
if (ASIC_IS_DCE3(rdev) && |
456,11 → 468,12 |
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: |
479,11 → 492,11 |
} |
} |
union dvo_encoder_control { |
ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; |
DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; |
DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; |
DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4; |
}; |
void |
533,6 → 546,13 |
args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); |
args.dvo_v3.ucDVOConfig = 0; /* XXX */ |
break; |
case 4: |
/* DCE8 */ |
args.dvo_v4.ucAction = action; |
args.dvo_v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); |
args.dvo_v4.ucDVOConfig = 0; /* XXX */ |
args.dvo_v4.ucBitPerColor = radeon_atom_get_bpc(encoder); |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
break; |
667,8 → 687,6 |
int |
atombios_get_encoder_mode(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector; |
694,24 → 712,37 |
switch (connector->connector_type) { |
case DRM_MODE_CONNECTOR_DVII: |
case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ |
if (drm_detect_hdmi_monitor(radeon_connector->edid) && |
radeon_audio && |
!ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */ |
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(connector)) && |
(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 { |
return ATOM_ENCODER_MODE_CRT; |
} |
break; |
case DRM_MODE_CONNECTOR_DVID: |
case DRM_MODE_CONNECTOR_HDMIA: |
default: |
if (drm_detect_hdmi_monitor(radeon_connector->edid) && |
radeon_audio && |
!ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */ |
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(connector)) && |
(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; |
719,14 → 750,19 |
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 (drm_detect_hdmi_monitor(radeon_connector->edid) && |
radeon_audio && |
!ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */ |
} 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(connector)) && |
(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; |
915,10 → 951,14 |
args.v4.ucLaneNum = 4; |
if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) { |
if (dp_clock == 270000) |
if (dp_clock == 540000) |
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; |
else if (dp_clock == 324000) |
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ; |
else if (dp_clock == 270000) |
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; |
else if (dp_clock == 540000) |
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; |
else |
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ; |
} |
args.v4.acConfig.ucDigSel = dig->dig_encoder; |
args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder); |
1012,6 → 1052,7 |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); |
break; |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
1271,10 → 1312,13 |
else |
args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG; |
break; |
} |
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; |
1593,10 → 1637,16 |
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) { |
1617,21 → 1667,13 |
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 early dce3.2 boards have a bug in their transmitter control table */ |
if ((rdev->family != CHIP_RV710) && (rdev->family != CHIP_RV730)) |
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) { |
1639,32 → 1681,50 |
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)) { |
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, 0, 0); |
} else 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); |
1671,52 → 1731,16 |
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; |
} |
} |
static void |
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, |
1735,6 → 1759,7 |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
radeon_atom_encoder_dpms_dig(encoder, mode); |
break; |
1775,9 → 1800,6 |
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); |
} |
1866,12 → 1888,16 |
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: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
dig = radeon_encoder->enc_priv; |
switch (dig->dig_encoder) { |
1893,6 → 1919,9 |
case 5: |
args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; |
break; |
case 6: |
args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID; |
break; |
} |
break; |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: |
1955,8 → 1984,14 |
/* set scaler clears this on some chips */ |
if (ASIC_IS_AVIVO(rdev) && |
(!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { |
if (ASIC_IS_DCE4(rdev)) { |
if (ASIC_IS_DCE8(rdev)) { |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, |
CIK_INTERLEAVE_EN); |
else |
WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 0); |
} else if (ASIC_IS_DCE4(rdev)) { |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, |
EVERGREEN_INTERLEAVE_EN); |
else |
2002,6 → 2037,9 |
else |
return 4; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
return 6; |
break; |
} |
} else if (ASIC_IS_DCE4(rdev)) { |
/* DCE4/5 */ |
2086,6 → 2124,7 |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); |
break; |
2130,6 → 2169,7 |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
/* handled in dpms */ |
break; |
2351,6 → 2391,15 |
/* 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) |
2395,6 → 2444,7 |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
/* handled in dpms */ |
break; |
2626,6 → 2676,7 |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
radeon_encoder->rmx_type = RMX_FULL; |
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); |
/drivers/video/drm/radeon/atombios_i2c.c |
---|
30,7 → 30,7 |
#define TARGET_HW_I2C_CLOCK 50 |
/* these are a limitation of ProcessI2cChannelTransaction not the hw */ |
#define ATOM_MAX_HW_I2C_WRITE 2 |
#define ATOM_MAX_HW_I2C_WRITE 3 |
#define ATOM_MAX_HW_I2C_READ 255 |
static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, |
42,28 → 42,42 |
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 2)\n", num); |
return -EINVAL; |
DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 3)\n", num); |
r = -EINVAL; |
goto done; |
} |
memcpy(&out, buf, num); |
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; |
} |
args.ucFlag = flags; |
args.ucI2CSpeed = TARGET_HW_I2C_CLOCK; |
args.ucRegIndex = 0; |
args.ucTransBytes = num; |
args.ucSlaveAddr = slave_addr << 1; |
args.ucLineNumber = chan->rec.i2c_id; |
73,13 → 87,17 |
/* 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)) |
memcpy(buf, base, num); |
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, |
88,7 → 106,7 |
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]; |
95,7 → 113,7 |
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 |
/drivers/video/drm/radeon/btc_dpm.c |
---|
0,0 → 1,2815 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "btcd.h" |
#include "r600_dpm.h" |
#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 |
#define MC_CG_ARB_FREQ_F2 0x0c |
#define MC_CG_ARB_FREQ_F3 0x0d |
#define MC_CG_SEQ_DRAMCONF_S0 0x05 |
#define MC_CG_SEQ_DRAMCONF_S1 0x06 |
#define MC_CG_SEQ_YCLK_SUSPEND 0x04 |
#define MC_CG_SEQ_YCLK_RESUME 0x0a |
#define SMC_RAM_END 0x8000 |
#ifndef BTC_MGCG_SEQUENCE |
#define BTC_MGCG_SEQUENCE 300 |
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[] = |
{ |
/* Register, Value, Mask bits */ |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff |
}; |
#define BARTS_CGCG_CGLS_DEFAULT_LENGTH sizeof(barts_cgcg_cgls_default) / (3 * sizeof(u32)) |
static const u32 barts_cgcg_cgls_disable[] = |
{ |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x00000644, 0x000f7912, 0x001f4180, |
0x00000644, 0x000f3812, 0x001f4180 |
}; |
#define BARTS_CGCG_CGLS_DISABLE_LENGTH sizeof(barts_cgcg_cgls_disable) / (3 * sizeof(u32)) |
static const u32 barts_cgcg_cgls_enable[] = |
{ |
/* 0x0000c124, 0x84180000, 0x00180000, */ |
0x00000644, 0x000f7892, 0x001f4080, |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff |
}; |
#define BARTS_CGCG_CGLS_ENABLE_LENGTH sizeof(barts_cgcg_cgls_enable) / (3 * sizeof(u32)) |
static const u32 barts_mgcg_default[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x00005448, 0x00000100, 0xffffffff, |
0x000055e4, 0x00600100, 0xffffffff, |
0x0000160c, 0x00000100, 0xffffffff, |
0x0000c164, 0x00000100, 0xffffffff, |
0x00008a18, 0x00000100, 0xffffffff, |
0x0000897c, 0x06000100, 0xffffffff, |
0x00008b28, 0x00000100, 0xffffffff, |
0x00009144, 0x00000100, 0xffffffff, |
0x00009a60, 0x00000100, 0xffffffff, |
0x00009868, 0x00000100, 0xffffffff, |
0x00008d58, 0x00000100, 0xffffffff, |
0x00009510, 0x00000100, 0xffffffff, |
0x0000949c, 0x00000100, 0xffffffff, |
0x00009654, 0x00000100, 0xffffffff, |
0x00009030, 0x00000100, 0xffffffff, |
0x00009034, 0x00000100, 0xffffffff, |
0x00009038, 0x00000100, 0xffffffff, |
0x0000903c, 0x00000100, 0xffffffff, |
0x00009040, 0x00000100, 0xffffffff, |
0x0000a200, 0x00000100, 0xffffffff, |
0x0000a204, 0x00000100, 0xffffffff, |
0x0000a208, 0x00000100, 0xffffffff, |
0x0000a20c, 0x00000100, 0xffffffff, |
0x0000977c, 0x00000100, 0xffffffff, |
0x00003f80, 0x00000100, 0xffffffff, |
0x0000a210, 0x00000100, 0xffffffff, |
0x0000a214, 0x00000100, 0xffffffff, |
0x000004d8, 0x00000100, 0xffffffff, |
0x00009784, 0x00000100, 0xffffffff, |
0x00009698, 0x00000100, 0xffffffff, |
0x000004d4, 0x00000200, 0xffffffff, |
0x000004d0, 0x00000000, 0xffffffff, |
0x000030cc, 0x00000100, 0xffffffff, |
0x0000d0c0, 0xff000100, 0xffffffff, |
0x0000802c, 0x40000000, 0xffffffff, |
0x0000915c, 0x00010000, 0xffffffff, |
0x00009160, 0x00030002, 0xffffffff, |
0x00009164, 0x00050004, 0xffffffff, |
0x00009168, 0x00070006, 0xffffffff, |
0x00009178, 0x00070000, 0xffffffff, |
0x0000917c, 0x00030002, 0xffffffff, |
0x00009180, 0x00050004, 0xffffffff, |
0x0000918c, 0x00010006, 0xffffffff, |
0x00009190, 0x00090008, 0xffffffff, |
0x00009194, 0x00070000, 0xffffffff, |
0x00009198, 0x00030002, 0xffffffff, |
0x0000919c, 0x00050004, 0xffffffff, |
0x000091a8, 0x00010006, 0xffffffff, |
0x000091ac, 0x00090008, 0xffffffff, |
0x000091b0, 0x00070000, 0xffffffff, |
0x000091b4, 0x00030002, 0xffffffff, |
0x000091b8, 0x00050004, 0xffffffff, |
0x000091c4, 0x00010006, 0xffffffff, |
0x000091c8, 0x00090008, 0xffffffff, |
0x000091cc, 0x00070000, 0xffffffff, |
0x000091d0, 0x00030002, 0xffffffff, |
0x000091d4, 0x00050004, 0xffffffff, |
0x000091e0, 0x00010006, 0xffffffff, |
0x000091e4, 0x00090008, 0xffffffff, |
0x000091e8, 0x00000000, 0xffffffff, |
0x000091ec, 0x00070000, 0xffffffff, |
0x000091f0, 0x00030002, 0xffffffff, |
0x000091f4, 0x00050004, 0xffffffff, |
0x00009200, 0x00010006, 0xffffffff, |
0x00009204, 0x00090008, 0xffffffff, |
0x00009208, 0x00070000, 0xffffffff, |
0x0000920c, 0x00030002, 0xffffffff, |
0x00009210, 0x00050004, 0xffffffff, |
0x0000921c, 0x00010006, 0xffffffff, |
0x00009220, 0x00090008, 0xffffffff, |
0x00009224, 0x00070000, 0xffffffff, |
0x00009228, 0x00030002, 0xffffffff, |
0x0000922c, 0x00050004, 0xffffffff, |
0x00009238, 0x00010006, 0xffffffff, |
0x0000923c, 0x00090008, 0xffffffff, |
0x00009294, 0x00000000, 0xffffffff, |
0x0000802c, 0x40010000, 0xffffffff, |
0x0000915c, 0x00010000, 0xffffffff, |
0x00009160, 0x00030002, 0xffffffff, |
0x00009164, 0x00050004, 0xffffffff, |
0x00009168, 0x00070006, 0xffffffff, |
0x00009178, 0x00070000, 0xffffffff, |
0x0000917c, 0x00030002, 0xffffffff, |
0x00009180, 0x00050004, 0xffffffff, |
0x0000918c, 0x00010006, 0xffffffff, |
0x00009190, 0x00090008, 0xffffffff, |
0x00009194, 0x00070000, 0xffffffff, |
0x00009198, 0x00030002, 0xffffffff, |
0x0000919c, 0x00050004, 0xffffffff, |
0x000091a8, 0x00010006, 0xffffffff, |
0x000091ac, 0x00090008, 0xffffffff, |
0x000091b0, 0x00070000, 0xffffffff, |
0x000091b4, 0x00030002, 0xffffffff, |
0x000091b8, 0x00050004, 0xffffffff, |
0x000091c4, 0x00010006, 0xffffffff, |
0x000091c8, 0x00090008, 0xffffffff, |
0x000091cc, 0x00070000, 0xffffffff, |
0x000091d0, 0x00030002, 0xffffffff, |
0x000091d4, 0x00050004, 0xffffffff, |
0x000091e0, 0x00010006, 0xffffffff, |
0x000091e4, 0x00090008, 0xffffffff, |
0x000091e8, 0x00000000, 0xffffffff, |
0x000091ec, 0x00070000, 0xffffffff, |
0x000091f0, 0x00030002, 0xffffffff, |
0x000091f4, 0x00050004, 0xffffffff, |
0x00009200, 0x00010006, 0xffffffff, |
0x00009204, 0x00090008, 0xffffffff, |
0x00009208, 0x00070000, 0xffffffff, |
0x0000920c, 0x00030002, 0xffffffff, |
0x00009210, 0x00050004, 0xffffffff, |
0x0000921c, 0x00010006, 0xffffffff, |
0x00009220, 0x00090008, 0xffffffff, |
0x00009224, 0x00070000, 0xffffffff, |
0x00009228, 0x00030002, 0xffffffff, |
0x0000922c, 0x00050004, 0xffffffff, |
0x00009238, 0x00010006, 0xffffffff, |
0x0000923c, 0x00090008, 0xffffffff, |
0x00009294, 0x00000000, 0xffffffff, |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff |
}; |
#define BARTS_MGCG_DEFAULT_LENGTH sizeof(barts_mgcg_default) / (3 * sizeof(u32)) |
static const u32 barts_mgcg_disable[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000002, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000003, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x00009150, 0x00600000, 0xffffffff |
}; |
#define BARTS_MGCG_DISABLE_LENGTH sizeof(barts_mgcg_disable) / (3 * sizeof(u32)) |
static const u32 barts_mgcg_enable[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000002, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000003, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x00009150, 0x81944000, 0xffffffff |
}; |
#define BARTS_MGCG_ENABLE_LENGTH sizeof(barts_mgcg_enable) / (3 * sizeof(u32)) |
//********* CAICOS **************// |
static const u32 caicos_cgcg_cgls_default[] = |
{ |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff |
}; |
#define CAICOS_CGCG_CGLS_DEFAULT_LENGTH sizeof(caicos_cgcg_cgls_default) / (3 * sizeof(u32)) |
static const u32 caicos_cgcg_cgls_disable[] = |
{ |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x00000644, 0x000f7912, 0x001f4180, |
0x00000644, 0x000f3812, 0x001f4180 |
}; |
#define CAICOS_CGCG_CGLS_DISABLE_LENGTH sizeof(caicos_cgcg_cgls_disable) / (3 * sizeof(u32)) |
static const u32 caicos_cgcg_cgls_enable[] = |
{ |
/* 0x0000c124, 0x84180000, 0x00180000, */ |
0x00000644, 0x000f7892, 0x001f4080, |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff |
}; |
#define CAICOS_CGCG_CGLS_ENABLE_LENGTH sizeof(caicos_cgcg_cgls_enable) / (3 * sizeof(u32)) |
static const u32 caicos_mgcg_default[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x00005448, 0x00000100, 0xffffffff, |
0x000055e4, 0x00600100, 0xffffffff, |
0x0000160c, 0x00000100, 0xffffffff, |
0x0000c164, 0x00000100, 0xffffffff, |
0x00008a18, 0x00000100, 0xffffffff, |
0x0000897c, 0x06000100, 0xffffffff, |
0x00008b28, 0x00000100, 0xffffffff, |
0x00009144, 0x00000100, 0xffffffff, |
0x00009a60, 0x00000100, 0xffffffff, |
0x00009868, 0x00000100, 0xffffffff, |
0x00008d58, 0x00000100, 0xffffffff, |
0x00009510, 0x00000100, 0xffffffff, |
0x0000949c, 0x00000100, 0xffffffff, |
0x00009654, 0x00000100, 0xffffffff, |
0x00009030, 0x00000100, 0xffffffff, |
0x00009034, 0x00000100, 0xffffffff, |
0x00009038, 0x00000100, 0xffffffff, |
0x0000903c, 0x00000100, 0xffffffff, |
0x00009040, 0x00000100, 0xffffffff, |
0x0000a200, 0x00000100, 0xffffffff, |
0x0000a204, 0x00000100, 0xffffffff, |
0x0000a208, 0x00000100, 0xffffffff, |
0x0000a20c, 0x00000100, 0xffffffff, |
0x0000977c, 0x00000100, 0xffffffff, |
0x00003f80, 0x00000100, 0xffffffff, |
0x0000a210, 0x00000100, 0xffffffff, |
0x0000a214, 0x00000100, 0xffffffff, |
0x000004d8, 0x00000100, 0xffffffff, |
0x00009784, 0x00000100, 0xffffffff, |
0x00009698, 0x00000100, 0xffffffff, |
0x000004d4, 0x00000200, 0xffffffff, |
0x000004d0, 0x00000000, 0xffffffff, |
0x000030cc, 0x00000100, 0xffffffff, |
0x0000d0c0, 0xff000100, 0xffffffff, |
0x0000915c, 0x00010000, 0xffffffff, |
0x00009160, 0x00030002, 0xffffffff, |
0x00009164, 0x00050004, 0xffffffff, |
0x00009168, 0x00070006, 0xffffffff, |
0x00009178, 0x00070000, 0xffffffff, |
0x0000917c, 0x00030002, 0xffffffff, |
0x00009180, 0x00050004, 0xffffffff, |
0x0000918c, 0x00010006, 0xffffffff, |
0x00009190, 0x00090008, 0xffffffff, |
0x00009194, 0x00070000, 0xffffffff, |
0x00009198, 0x00030002, 0xffffffff, |
0x0000919c, 0x00050004, 0xffffffff, |
0x000091a8, 0x00010006, 0xffffffff, |
0x000091ac, 0x00090008, 0xffffffff, |
0x000091e8, 0x00000000, 0xffffffff, |
0x00009294, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff |
}; |
#define CAICOS_MGCG_DEFAULT_LENGTH sizeof(caicos_mgcg_default) / (3 * sizeof(u32)) |
static const u32 caicos_mgcg_disable[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000002, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000003, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x00009150, 0x00600000, 0xffffffff |
}; |
#define CAICOS_MGCG_DISABLE_LENGTH sizeof(caicos_mgcg_disable) / (3 * sizeof(u32)) |
static const u32 caicos_mgcg_enable[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000002, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000003, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x00009150, 0x46944040, 0xffffffff |
}; |
#define CAICOS_MGCG_ENABLE_LENGTH sizeof(caicos_mgcg_enable) / (3 * sizeof(u32)) |
//********* TURKS **************// |
static const u32 turks_cgcg_cgls_default[] = |
{ |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff |
}; |
#define TURKS_CGCG_CGLS_DEFAULT_LENGTH sizeof(turks_cgcg_cgls_default) / (3 * sizeof(u32)) |
static const u32 turks_cgcg_cgls_disable[] = |
{ |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x00000644, 0x000f7912, 0x001f4180, |
0x00000644, 0x000f3812, 0x001f4180 |
}; |
#define TURKS_CGCG_CGLS_DISABLE_LENGTH sizeof(turks_cgcg_cgls_disable) / (3 * sizeof(u32)) |
static const u32 turks_cgcg_cgls_enable[] = |
{ |
/* 0x0000c124, 0x84180000, 0x00180000, */ |
0x00000644, 0x000f7892, 0x001f4080, |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff |
}; |
#define TURKS_CGCG_CGLS_ENABLE_LENGTH sizeof(turks_cgcg_cgls_enable) / (3 * sizeof(u32)) |
// These are the sequences for turks_mgcg_shls |
static const u32 turks_mgcg_default[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x00005448, 0x00000100, 0xffffffff, |
0x000055e4, 0x00600100, 0xffffffff, |
0x0000160c, 0x00000100, 0xffffffff, |
0x0000c164, 0x00000100, 0xffffffff, |
0x00008a18, 0x00000100, 0xffffffff, |
0x0000897c, 0x06000100, 0xffffffff, |
0x00008b28, 0x00000100, 0xffffffff, |
0x00009144, 0x00000100, 0xffffffff, |
0x00009a60, 0x00000100, 0xffffffff, |
0x00009868, 0x00000100, 0xffffffff, |
0x00008d58, 0x00000100, 0xffffffff, |
0x00009510, 0x00000100, 0xffffffff, |
0x0000949c, 0x00000100, 0xffffffff, |
0x00009654, 0x00000100, 0xffffffff, |
0x00009030, 0x00000100, 0xffffffff, |
0x00009034, 0x00000100, 0xffffffff, |
0x00009038, 0x00000100, 0xffffffff, |
0x0000903c, 0x00000100, 0xffffffff, |
0x00009040, 0x00000100, 0xffffffff, |
0x0000a200, 0x00000100, 0xffffffff, |
0x0000a204, 0x00000100, 0xffffffff, |
0x0000a208, 0x00000100, 0xffffffff, |
0x0000a20c, 0x00000100, 0xffffffff, |
0x0000977c, 0x00000100, 0xffffffff, |
0x00003f80, 0x00000100, 0xffffffff, |
0x0000a210, 0x00000100, 0xffffffff, |
0x0000a214, 0x00000100, 0xffffffff, |
0x000004d8, 0x00000100, 0xffffffff, |
0x00009784, 0x00000100, 0xffffffff, |
0x00009698, 0x00000100, 0xffffffff, |
0x000004d4, 0x00000200, 0xffffffff, |
0x000004d0, 0x00000000, 0xffffffff, |
0x000030cc, 0x00000100, 0xffffffff, |
0x0000d0c0, 0x00000100, 0xffffffff, |
0x0000915c, 0x00010000, 0xffffffff, |
0x00009160, 0x00030002, 0xffffffff, |
0x00009164, 0x00050004, 0xffffffff, |
0x00009168, 0x00070006, 0xffffffff, |
0x00009178, 0x00070000, 0xffffffff, |
0x0000917c, 0x00030002, 0xffffffff, |
0x00009180, 0x00050004, 0xffffffff, |
0x0000918c, 0x00010006, 0xffffffff, |
0x00009190, 0x00090008, 0xffffffff, |
0x00009194, 0x00070000, 0xffffffff, |
0x00009198, 0x00030002, 0xffffffff, |
0x0000919c, 0x00050004, 0xffffffff, |
0x000091a8, 0x00010006, 0xffffffff, |
0x000091ac, 0x00090008, 0xffffffff, |
0x000091b0, 0x00070000, 0xffffffff, |
0x000091b4, 0x00030002, 0xffffffff, |
0x000091b8, 0x00050004, 0xffffffff, |
0x000091c4, 0x00010006, 0xffffffff, |
0x000091c8, 0x00090008, 0xffffffff, |
0x000091cc, 0x00070000, 0xffffffff, |
0x000091d0, 0x00030002, 0xffffffff, |
0x000091d4, 0x00050004, 0xffffffff, |
0x000091e0, 0x00010006, 0xffffffff, |
0x000091e4, 0x00090008, 0xffffffff, |
0x000091e8, 0x00000000, 0xffffffff, |
0x000091ec, 0x00070000, 0xffffffff, |
0x000091f0, 0x00030002, 0xffffffff, |
0x000091f4, 0x00050004, 0xffffffff, |
0x00009200, 0x00010006, 0xffffffff, |
0x00009204, 0x00090008, 0xffffffff, |
0x00009208, 0x00070000, 0xffffffff, |
0x0000920c, 0x00030002, 0xffffffff, |
0x00009210, 0x00050004, 0xffffffff, |
0x0000921c, 0x00010006, 0xffffffff, |
0x00009220, 0x00090008, 0xffffffff, |
0x00009294, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff |
}; |
#define TURKS_MGCG_DEFAULT_LENGTH sizeof(turks_mgcg_default) / (3 * sizeof(u32)) |
static const u32 turks_mgcg_disable[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000002, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000003, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x00009150, 0x00600000, 0xffffffff |
}; |
#define TURKS_MGCG_DISABLE_LENGTH sizeof(turks_mgcg_disable) / (3 * sizeof(u32)) |
static const u32 turks_mgcg_enable[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000002, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000003, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x00009150, 0x6e944000, 0xffffffff |
}; |
#define TURKS_MGCG_ENABLE_LENGTH sizeof(turks_mgcg_enable) / (3 * sizeof(u32)) |
#endif |
#ifndef BTC_SYSLS_SEQUENCE |
#define BTC_SYSLS_SEQUENCE 100 |
//********* BARTS **************// |
static const u32 barts_sysls_default[] = |
{ |
/* Register, Value, Mask bits */ |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x000020c0, 0x000c0c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x000064ec, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00006dfc, 0x00000000, 0xffffffff |
}; |
#define BARTS_SYSLS_DEFAULT_LENGTH sizeof(barts_sysls_default) / (3 * sizeof(u32)) |
static const u32 barts_sysls_disable[] = |
{ |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x00041401, 0xffffffff, |
0x0000264c, 0x00040400, 0xffffffff, |
0x00002648, 0x00040400, 0xffffffff, |
0x00002650, 0x00040400, 0xffffffff, |
0x000020b8, 0x00040400, 0xffffffff, |
0x000020bc, 0x00040400, 0xffffffff, |
0x000020c0, 0x00040c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680000, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x000064ec, 0x00007ffd, 0xffffffff, |
0x00000c7c, 0x0000ff00, 0xffffffff, |
0x00006dfc, 0x0000007f, 0xffffffff |
}; |
#define BARTS_SYSLS_DISABLE_LENGTH sizeof(barts_sysls_disable) / (3 * sizeof(u32)) |
static const u32 barts_sysls_enable[] = |
{ |
0x000055e8, 0x00000001, 0xffffffff, |
0x0000d0bc, 0x00000100, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x000020c0, 0x000c0c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x000004c8, 0x00000000, 0xffffffff, |
0x000064ec, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00006dfc, 0x00000000, 0xffffffff |
}; |
#define BARTS_SYSLS_ENABLE_LENGTH sizeof(barts_sysls_enable) / (3 * sizeof(u32)) |
//********* CAICOS **************// |
static const u32 caicos_sysls_default[] = |
{ |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x000064ec, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00006dfc, 0x00000000, 0xffffffff |
}; |
#define CAICOS_SYSLS_DEFAULT_LENGTH sizeof(caicos_sysls_default) / (3 * sizeof(u32)) |
static const u32 caicos_sysls_disable[] = |
{ |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x00041401, 0xffffffff, |
0x0000264c, 0x00040400, 0xffffffff, |
0x00002648, 0x00040400, 0xffffffff, |
0x00002650, 0x00040400, 0xffffffff, |
0x000020b8, 0x00040400, 0xffffffff, |
0x000020bc, 0x00040400, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680000, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x000064ec, 0x00007ffd, 0xffffffff, |
0x00000c7c, 0x0000ff00, 0xffffffff, |
0x00006dfc, 0x0000007f, 0xffffffff |
}; |
#define CAICOS_SYSLS_DISABLE_LENGTH sizeof(caicos_sysls_disable) / (3 * sizeof(u32)) |
static const u32 caicos_sysls_enable[] = |
{ |
0x000055e8, 0x00000001, 0xffffffff, |
0x0000d0bc, 0x00000100, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x000064ec, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00006dfc, 0x00000000, 0xffffffff, |
0x000004c8, 0x00000000, 0xffffffff |
}; |
#define CAICOS_SYSLS_ENABLE_LENGTH sizeof(caicos_sysls_enable) / (3 * sizeof(u32)) |
//********* TURKS **************// |
static const u32 turks_sysls_default[] = |
{ |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x000020c0, 0x000c0c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x000064ec, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00006dfc, 0x00000000, 0xffffffff |
}; |
#define TURKS_SYSLS_DEFAULT_LENGTH sizeof(turks_sysls_default) / (3 * sizeof(u32)) |
static const u32 turks_sysls_disable[] = |
{ |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x00041401, 0xffffffff, |
0x0000264c, 0x00040400, 0xffffffff, |
0x00002648, 0x00040400, 0xffffffff, |
0x00002650, 0x00040400, 0xffffffff, |
0x000020b8, 0x00040400, 0xffffffff, |
0x000020bc, 0x00040400, 0xffffffff, |
0x000020c0, 0x00040c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680000, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x000064ec, 0x00007ffd, 0xffffffff, |
0x00000c7c, 0x0000ff00, 0xffffffff, |
0x00006dfc, 0x0000007f, 0xffffffff |
}; |
#define TURKS_SYSLS_DISABLE_LENGTH sizeof(turks_sysls_disable) / (3 * sizeof(u32)) |
static const u32 turks_sysls_enable[] = |
{ |
0x000055e8, 0x00000001, 0xffffffff, |
0x0000d0bc, 0x00000100, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x000020c0, 0x000c0c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x000004c8, 0x00000000, 0xffffffff, |
0x000064ec, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00006dfc, 0x00000000, 0xffffffff |
}; |
#define TURKS_SYSLS_ENABLE_LENGTH sizeof(turks_sysls_enable) / (3 * sizeof(u32)) |
#endif |
u32 btc_valid_sclk[40] = |
{ |
5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, |
55000, 60000, 65000, 70000, 75000, 80000, 85000, 90000, 95000, 100000, |
105000, 110000, 11500, 120000, 125000, 130000, 135000, 140000, 145000, 150000, |
155000, 160000, 165000, 170000, 175000, 180000, 185000, 190000, 195000, 200000 |
}; |
static const struct radeon_blacklist_clocks btc_blacklist_clocks[] = |
{ |
{ 10000, 30000, RADEON_SCLK_UP }, |
{ 15000, 30000, RADEON_SCLK_UP }, |
{ 20000, 30000, RADEON_SCLK_UP }, |
{ 25000, 30000, RADEON_SCLK_UP } |
}; |
void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table, |
u32 *max_clock) |
{ |
u32 i, clock = 0; |
if ((table == NULL) || (table->count == 0)) { |
*max_clock = clock; |
return; |
} |
for (i = 0; i < table->count; i++) { |
if (clock < table->entries[i].clk) |
clock = table->entries[i].clk; |
} |
*max_clock = clock; |
} |
void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table, |
u32 clock, u16 max_voltage, u16 *voltage) |
{ |
u32 i; |
if ((table == NULL) || (table->count == 0)) |
return; |
for (i= 0; i < table->count; i++) { |
if (clock <= table->entries[i].clk) { |
if (*voltage < table->entries[i].v) |
*voltage = (u16)((table->entries[i].v < max_voltage) ? |
table->entries[i].v : max_voltage); |
return; |
} |
} |
*voltage = (*voltage > max_voltage) ? *voltage : max_voltage; |
} |
static u32 btc_find_valid_clock(struct radeon_clock_array *clocks, |
u32 max_clock, u32 requested_clock) |
{ |
unsigned int i; |
if ((clocks == NULL) || (clocks->count == 0)) |
return (requested_clock < max_clock) ? requested_clock : max_clock; |
for (i = 0; i < clocks->count; i++) { |
if (clocks->values[i] >= requested_clock) |
return (clocks->values[i] < max_clock) ? clocks->values[i] : max_clock; |
} |
return (clocks->values[clocks->count - 1] < max_clock) ? |
clocks->values[clocks->count - 1] : max_clock; |
} |
static u32 btc_get_valid_mclk(struct radeon_device *rdev, |
u32 max_mclk, u32 requested_mclk) |
{ |
return btc_find_valid_clock(&rdev->pm.dpm.dyn_state.valid_mclk_values, |
max_mclk, requested_mclk); |
} |
static u32 btc_get_valid_sclk(struct radeon_device *rdev, |
u32 max_sclk, u32 requested_sclk) |
{ |
return btc_find_valid_clock(&rdev->pm.dpm.dyn_state.valid_sclk_values, |
max_sclk, requested_sclk); |
} |
void btc_skip_blacklist_clocks(struct radeon_device *rdev, |
const u32 max_sclk, const u32 max_mclk, |
u32 *sclk, u32 *mclk) |
{ |
int i, num_blacklist_clocks; |
if ((sclk == NULL) || (mclk == NULL)) |
return; |
num_blacklist_clocks = ARRAY_SIZE(btc_blacklist_clocks); |
for (i = 0; i < num_blacklist_clocks; i++) { |
if ((btc_blacklist_clocks[i].sclk == *sclk) && |
(btc_blacklist_clocks[i].mclk == *mclk)) |
break; |
} |
if (i < num_blacklist_clocks) { |
if (btc_blacklist_clocks[i].action == RADEON_SCLK_UP) { |
*sclk = btc_get_valid_sclk(rdev, max_sclk, *sclk + 1); |
if (*sclk < max_sclk) |
btc_skip_blacklist_clocks(rdev, max_sclk, max_mclk, sclk, mclk); |
} |
} |
} |
void btc_adjust_clock_combinations(struct radeon_device *rdev, |
const struct radeon_clock_and_voltage_limits *max_limits, |
struct rv7xx_pl *pl) |
{ |
if ((pl->mclk == 0) || (pl->sclk == 0)) |
return; |
if (pl->mclk == pl->sclk) |
return; |
if (pl->mclk > pl->sclk) { |
if (((pl->mclk + (pl->sclk - 1)) / pl->sclk) > rdev->pm.dpm.dyn_state.mclk_sclk_ratio) |
pl->sclk = btc_get_valid_sclk(rdev, |
max_limits->sclk, |
(pl->mclk + |
(rdev->pm.dpm.dyn_state.mclk_sclk_ratio - 1)) / |
rdev->pm.dpm.dyn_state.mclk_sclk_ratio); |
} else { |
if ((pl->sclk - pl->mclk) > rdev->pm.dpm.dyn_state.sclk_mclk_delta) |
pl->mclk = btc_get_valid_mclk(rdev, |
max_limits->mclk, |
pl->sclk - |
rdev->pm.dpm.dyn_state.sclk_mclk_delta); |
} |
} |
static u16 btc_find_voltage(struct atom_voltage_table *table, u16 voltage) |
{ |
unsigned int i; |
for (i = 0; i < table->count; i++) { |
if (voltage <= table->entries[i].value) |
return table->entries[i].value; |
} |
return table->entries[table->count - 1].value; |
} |
void btc_apply_voltage_delta_rules(struct radeon_device *rdev, |
u16 max_vddc, u16 max_vddci, |
u16 *vddc, u16 *vddci) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u16 new_voltage; |
if ((0 == *vddc) || (0 == *vddci)) |
return; |
if (*vddc > *vddci) { |
if ((*vddc - *vddci) > rdev->pm.dpm.dyn_state.vddc_vddci_delta) { |
new_voltage = btc_find_voltage(&eg_pi->vddci_voltage_table, |
(*vddc - rdev->pm.dpm.dyn_state.vddc_vddci_delta)); |
*vddci = (new_voltage < max_vddci) ? new_voltage : max_vddci; |
} |
} else { |
if ((*vddci - *vddc) > rdev->pm.dpm.dyn_state.vddc_vddci_delta) { |
new_voltage = btc_find_voltage(&eg_pi->vddc_voltage_table, |
(*vddci - rdev->pm.dpm.dyn_state.vddc_vddci_delta)); |
*vddc = (new_voltage < max_vddc) ? new_voltage : max_vddc; |
} |
} |
} |
static void btc_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp, bif; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if (enable) { |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) { |
if (!pi->boot_in_gen2) { |
bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK; |
bif |= CG_CLIENT_REQ(0xd); |
WREG32(CG_BIF_REQ_AND_RSP, bif); |
tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); |
tmp |= LC_GEN2_EN_STRAP; |
tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
udelay(10); |
tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
} |
} else { |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) || |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) { |
if (!pi->boot_in_gen2) { |
bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK; |
bif |= CG_CLIENT_REQ(0xd); |
WREG32(CG_BIF_REQ_AND_RSP, bif); |
tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
tmp &= ~LC_GEN2_EN_STRAP; |
} |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
} |
} |
static void btc_enable_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
btc_enable_bif_dynamic_pcie_gen2(rdev, enable); |
if (enable) |
WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE); |
} |
static int btc_disable_ulv(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (eg_pi->ulv.supported) { |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_DisableULV) != PPSMC_Result_OK) |
return -EINVAL; |
} |
return 0; |
} |
static int btc_populate_ulv_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
int ret = -EINVAL; |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl; |
if (ulv_pl->vddc) { |
ret = cypress_convert_power_level_to_smc(rdev, |
ulv_pl, |
&table->ULVState.levels[0], |
PPSMC_DISPLAY_WATERMARK_LOW); |
if (ret == 0) { |
table->ULVState.levels[0].arbValue = MC_CG_ARB_FREQ_F0; |
table->ULVState.levels[0].ACIndex = 1; |
table->ULVState.levels[1] = table->ULVState.levels[0]; |
table->ULVState.levels[2] = table->ULVState.levels[0]; |
table->ULVState.flags |= PPSMC_SWSTATE_FLAG_DC; |
WREG32(CG_ULV_CONTROL, BTC_CGULVCONTROL_DFLT); |
WREG32(CG_ULV_PARAMETER, BTC_CGULVPARAMETER_DFLT); |
} |
} |
return ret; |
} |
static int btc_populate_smc_acpi_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
int ret = cypress_populate_smc_acpi_state(rdev, table); |
if (ret == 0) { |
table->ACPIState.levels[0].ACIndex = 0; |
table->ACPIState.levels[1].ACIndex = 0; |
table->ACPIState.levels[2].ACIndex = 0; |
} |
return ret; |
} |
void btc_program_mgcg_hw_sequence(struct radeon_device *rdev, |
const u32 *sequence, u32 count) |
{ |
u32 i, length = count * 3; |
u32 tmp; |
for (i = 0; i < length; i+=3) { |
tmp = RREG32(sequence[i]); |
tmp &= ~sequence[i+2]; |
tmp |= sequence[i+1] & sequence[i+2]; |
WREG32(sequence[i], tmp); |
} |
} |
static void btc_cg_clock_gating_default(struct radeon_device *rdev) |
{ |
u32 count; |
const u32 *p = NULL; |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_cgcg_cgls_default; |
count = BARTS_CGCG_CGLS_DEFAULT_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_cgcg_cgls_default; |
count = TURKS_CGCG_CGLS_DEFAULT_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_cgcg_cgls_default; |
count = CAICOS_CGCG_CGLS_DEFAULT_LENGTH; |
} else |
return; |
btc_program_mgcg_hw_sequence(rdev, p, count); |
} |
static void btc_cg_clock_gating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 count; |
const u32 *p = NULL; |
if (enable) { |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_cgcg_cgls_enable; |
count = BARTS_CGCG_CGLS_ENABLE_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_cgcg_cgls_enable; |
count = TURKS_CGCG_CGLS_ENABLE_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_cgcg_cgls_enable; |
count = CAICOS_CGCG_CGLS_ENABLE_LENGTH; |
} else |
return; |
} else { |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_cgcg_cgls_disable; |
count = BARTS_CGCG_CGLS_DISABLE_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_cgcg_cgls_disable; |
count = TURKS_CGCG_CGLS_DISABLE_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_cgcg_cgls_disable; |
count = CAICOS_CGCG_CGLS_DISABLE_LENGTH; |
} else |
return; |
} |
btc_program_mgcg_hw_sequence(rdev, p, count); |
} |
static void btc_mg_clock_gating_default(struct radeon_device *rdev) |
{ |
u32 count; |
const u32 *p = NULL; |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_mgcg_default; |
count = BARTS_MGCG_DEFAULT_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_mgcg_default; |
count = TURKS_MGCG_DEFAULT_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_mgcg_default; |
count = CAICOS_MGCG_DEFAULT_LENGTH; |
} else |
return; |
btc_program_mgcg_hw_sequence(rdev, p, count); |
} |
static void btc_mg_clock_gating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 count; |
const u32 *p = NULL; |
if (enable) { |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_mgcg_enable; |
count = BARTS_MGCG_ENABLE_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_mgcg_enable; |
count = TURKS_MGCG_ENABLE_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_mgcg_enable; |
count = CAICOS_MGCG_ENABLE_LENGTH; |
} else |
return; |
} else { |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_mgcg_disable[0]; |
count = BARTS_MGCG_DISABLE_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_mgcg_disable[0]; |
count = TURKS_MGCG_DISABLE_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_mgcg_disable[0]; |
count = CAICOS_MGCG_DISABLE_LENGTH; |
} else |
return; |
} |
btc_program_mgcg_hw_sequence(rdev, p, count); |
} |
static void btc_ls_clock_gating_default(struct radeon_device *rdev) |
{ |
u32 count; |
const u32 *p = NULL; |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_sysls_default; |
count = BARTS_SYSLS_DEFAULT_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_sysls_default; |
count = TURKS_SYSLS_DEFAULT_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_sysls_default; |
count = CAICOS_SYSLS_DEFAULT_LENGTH; |
} else |
return; |
btc_program_mgcg_hw_sequence(rdev, p, count); |
} |
static void btc_ls_clock_gating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 count; |
const u32 *p = NULL; |
if (enable) { |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_sysls_enable; |
count = BARTS_SYSLS_ENABLE_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_sysls_enable; |
count = TURKS_SYSLS_ENABLE_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_sysls_enable; |
count = CAICOS_SYSLS_ENABLE_LENGTH; |
} else |
return; |
} else { |
if (rdev->family == CHIP_BARTS) { |
p = (const u32 *)&barts_sysls_disable; |
count = BARTS_SYSLS_DISABLE_LENGTH; |
} else if (rdev->family == CHIP_TURKS) { |
p = (const u32 *)&turks_sysls_disable; |
count = TURKS_SYSLS_DISABLE_LENGTH; |
} else if (rdev->family == CHIP_CAICOS) { |
p = (const u32 *)&caicos_sysls_disable; |
count = CAICOS_SYSLS_DISABLE_LENGTH; |
} else |
return; |
} |
btc_program_mgcg_hw_sequence(rdev, p, count); |
} |
bool btc_dpm_enabled(struct radeon_device *rdev) |
{ |
if (rv770_is_smc_running(rdev)) |
return true; |
else |
return false; |
} |
static int btc_init_smc_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
RV770_SMC_STATETABLE *table = &pi->smc_statetable; |
int ret; |
memset(table, 0, sizeof(RV770_SMC_STATETABLE)); |
cypress_populate_smc_voltage_tables(rdev, table); |
switch (rdev->pm.int_thermal_type) { |
case THERMAL_TYPE_EVERGREEN: |
case THERMAL_TYPE_EMC2103_WITH_INTERNAL: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL; |
break; |
case THERMAL_TYPE_NONE: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE; |
break; |
default: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL; |
break; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT) |
table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; |
if (pi->mem_gddr5) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5; |
ret = cypress_populate_smc_initial_state(rdev, radeon_boot_state, table); |
if (ret) |
return ret; |
if (eg_pi->sclk_deep_sleep) |
WREG32_P(SCLK_PSKIP_CNTL, PSKIP_ON_ALLOW_STOP_HI(32), |
~PSKIP_ON_ALLOW_STOP_HI_MASK); |
ret = btc_populate_smc_acpi_state(rdev, table); |
if (ret) |
return ret; |
if (eg_pi->ulv.supported) { |
ret = btc_populate_ulv_state(rdev, table); |
if (ret) |
eg_pi->ulv.supported = false; |
} |
table->driverState = table->initialState; |
return rv770_copy_bytes_to_smc(rdev, |
pi->state_table_start, |
(u8 *)table, |
sizeof(RV770_SMC_STATETABLE), |
pi->sram_end); |
} |
static void btc_set_at_for_uvd(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
int idx = 0; |
if (r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) |
idx = 1; |
if ((idx == 1) && !eg_pi->smu_uvd_hs) { |
pi->rlp = 10; |
pi->rmp = 100; |
pi->lhp = 100; |
pi->lmp = 10; |
} else { |
pi->rlp = eg_pi->ats[idx].rlp; |
pi->rmp = eg_pi->ats[idx].rmp; |
pi->lhp = eg_pi->ats[idx].lhp; |
pi->lmp = eg_pi->ats[idx].lmp; |
} |
} |
void btc_notify_uvd_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) { |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_uvd_enabled, 1); |
eg_pi->uvd_enabled = true; |
} else { |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_uvd_enabled, 0); |
eg_pi->uvd_enabled = false; |
} |
} |
int btc_reset_to_default(struct radeon_device *rdev) |
{ |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
static void btc_stop_smc(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (((RREG32(LB_SYNC_RESET_SEL) & LB_SYNC_RESET_SEL_MASK) >> LB_SYNC_RESET_SEL_SHIFT) != 1) |
break; |
udelay(1); |
} |
udelay(100); |
r7xx_stop_smc(rdev); |
} |
void btc_read_arb_registers(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct evergreen_arb_registers *arb_registers = |
&eg_pi->bootup_arb_registers; |
arb_registers->mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
arb_registers->mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
arb_registers->mc_arb_rfsh_rate = RREG32(MC_ARB_RFSH_RATE); |
arb_registers->mc_arb_burst_time = RREG32(MC_ARB_BURST_TIME); |
} |
static void btc_set_arb0_registers(struct radeon_device *rdev, |
struct evergreen_arb_registers *arb_registers) |
{ |
u32 val; |
WREG32(MC_ARB_DRAM_TIMING, arb_registers->mc_arb_dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2, arb_registers->mc_arb_dram_timing2); |
val = (arb_registers->mc_arb_rfsh_rate & POWERMODE0_MASK) >> |
POWERMODE0_SHIFT; |
WREG32_P(MC_ARB_RFSH_RATE, POWERMODE0(val), ~POWERMODE0_MASK); |
val = (arb_registers->mc_arb_burst_time & STATE0_MASK) >> |
STATE0_SHIFT; |
WREG32_P(MC_ARB_BURST_TIME, STATE0(val), ~STATE0_MASK); |
} |
static void btc_set_boot_state_timing(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (eg_pi->ulv.supported) |
btc_set_arb0_registers(rdev, &eg_pi->bootup_arb_registers); |
} |
static bool btc_is_state_ulv_compatible(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct rv7xx_ps *state = rv770_get_ps(radeon_state); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl; |
if (state->low.mclk != ulv_pl->mclk) |
return false; |
if (state->low.vddci != ulv_pl->vddci) |
return false; |
/* XXX check minclocks, etc. */ |
return true; |
} |
static int btc_set_ulv_dram_timing(struct radeon_device *rdev) |
{ |
u32 val; |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl; |
radeon_atom_set_engine_dram_timings(rdev, |
ulv_pl->sclk, |
ulv_pl->mclk); |
val = rv770_calculate_memory_refresh_rate(rdev, ulv_pl->sclk); |
WREG32_P(MC_ARB_RFSH_RATE, POWERMODE0(val), ~POWERMODE0_MASK); |
val = cypress_calculate_burst_time(rdev, ulv_pl->sclk, ulv_pl->mclk); |
WREG32_P(MC_ARB_BURST_TIME, STATE0(val), ~STATE0_MASK); |
return 0; |
} |
static int btc_enable_ulv(struct radeon_device *rdev) |
{ |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableULV) != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
static int btc_set_power_state_conditionally_enable_ulv(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
int ret = 0; |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (eg_pi->ulv.supported) { |
if (btc_is_state_ulv_compatible(rdev, radeon_new_state)) { |
// Set ARB[0] to reflect the DRAM timing needed for ULV. |
ret = btc_set_ulv_dram_timing(rdev); |
if (ret == 0) |
ret = btc_enable_ulv(rdev); |
} |
} |
return ret; |
} |
static bool btc_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg) |
{ |
bool result = true; |
switch (in_reg) { |
case MC_SEQ_RAS_TIMING >> 2: |
*out_reg = MC_SEQ_RAS_TIMING_LP >> 2; |
break; |
case MC_SEQ_CAS_TIMING >> 2: |
*out_reg = MC_SEQ_CAS_TIMING_LP >> 2; |
break; |
case MC_SEQ_MISC_TIMING >> 2: |
*out_reg = MC_SEQ_MISC_TIMING_LP >> 2; |
break; |
case MC_SEQ_MISC_TIMING2 >> 2: |
*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2; |
break; |
case MC_SEQ_RD_CTL_D0 >> 2: |
*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2; |
break; |
case MC_SEQ_RD_CTL_D1 >> 2: |
*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_D0 >> 2: |
*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_D1 >> 2: |
*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2; |
break; |
case MC_PMG_CMD_EMRS >> 2: |
*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
break; |
case MC_PMG_CMD_MRS >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
break; |
case MC_PMG_CMD_MRS1 >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
break; |
default: |
result = false; |
break; |
} |
return result; |
} |
static void btc_set_valid_flag(struct evergreen_mc_reg_table *table) |
{ |
u8 i, j; |
for (i = 0; i < table->last; i++) { |
for (j = 1; j < table->num_entries; j++) { |
if (table->mc_reg_table_entry[j-1].mc_data[i] != |
table->mc_reg_table_entry[j].mc_data[i]) { |
table->valid_flag |= (1 << i); |
break; |
} |
} |
} |
} |
static int btc_set_mc_special_registers(struct radeon_device *rdev, |
struct evergreen_mc_reg_table *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u8 i, j, k; |
u32 tmp; |
for (i = 0, j = table->last; i < table->last; i++) { |
switch (table->mc_reg_address[i].s1) { |
case MC_SEQ_MISC1 >> 2: |
tmp = RREG32(MC_PMG_CMD_EMRS); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
for (k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
((tmp & 0xffff0000)) | |
((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16); |
} |
j++; |
if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
tmp = RREG32(MC_PMG_CMD_MRS); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
for (k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
(tmp & 0xffff0000) | |
(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); |
if (!pi->mem_gddr5) |
table->mc_reg_table_entry[k].mc_data[j] |= 0x100; |
} |
j++; |
if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
break; |
case MC_SEQ_RESERVE_M >> 2: |
tmp = RREG32(MC_PMG_CMD_MRS1); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
for (k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
(tmp & 0xffff0000) | |
(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); |
} |
j++; |
if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
break; |
default: |
break; |
} |
} |
table->last = j; |
return 0; |
} |
static void btc_set_s0_mc_reg_index(struct evergreen_mc_reg_table *table) |
{ |
u32 i; |
u16 address; |
for (i = 0; i < table->last; i++) { |
table->mc_reg_address[i].s0 = |
btc_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ? |
address : table->mc_reg_address[i].s1; |
} |
} |
static int btc_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table, |
struct evergreen_mc_reg_table *eg_table) |
{ |
u8 i, j; |
if (table->last > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
if (table->num_entries > MAX_AC_TIMING_ENTRIES) |
return -EINVAL; |
for (i = 0; i < table->last; i++) |
eg_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1; |
eg_table->last = table->last; |
for (i = 0; i < table->num_entries; i++) { |
eg_table->mc_reg_table_entry[i].mclk_max = |
table->mc_reg_table_entry[i].mclk_max; |
for(j = 0; j < table->last; j++) |
eg_table->mc_reg_table_entry[i].mc_data[j] = |
table->mc_reg_table_entry[i].mc_data[j]; |
} |
eg_table->num_entries = table->num_entries; |
return 0; |
} |
static int btc_initialize_mc_reg_table(struct radeon_device *rdev) |
{ |
int ret; |
struct atom_mc_reg_table *table; |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct evergreen_mc_reg_table *eg_table = &eg_pi->mc_reg_table; |
u8 module_index = rv770_get_memory_module_index(rdev); |
table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL); |
if (!table) |
return -ENOMEM; |
/* Program additional LP registers that are no longer programmed by VBIOS */ |
WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING)); |
WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING)); |
WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING)); |
WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2)); |
WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0)); |
WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1)); |
WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0)); |
WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1)); |
WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS)); |
WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS)); |
WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1)); |
ret = radeon_atom_init_mc_reg_table(rdev, module_index, table); |
if (ret) |
goto init_mc_done; |
ret = btc_copy_vbios_mc_reg_table(table, eg_table); |
if (ret) |
goto init_mc_done; |
btc_set_s0_mc_reg_index(eg_table); |
ret = btc_set_mc_special_registers(rdev, eg_table); |
if (ret) |
goto init_mc_done; |
btc_set_valid_flag(eg_table); |
init_mc_done: |
kfree(table); |
return ret; |
} |
static void btc_init_stutter_mode(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp; |
if (pi->mclk_stutter_mode_threshold) { |
if (pi->mem_gddr5) { |
tmp = RREG32(MC_PMG_AUTO_CFG); |
if ((0x200 & tmp) == 0) { |
tmp = (tmp & 0xfffffc0b) | 0x204; |
WREG32(MC_PMG_AUTO_CFG, tmp); |
} |
} |
} |
} |
bool btc_dpm_vblank_too_short(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 vblank_time = r600_dpm_get_vblank_time(rdev); |
u32 switch_limit = pi->mem_gddr5 ? 450 : 100; |
if (vblank_time < switch_limit) |
return true; |
else |
return false; |
} |
static void btc_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct rv7xx_ps *ps = rv770_get_ps(rps); |
struct radeon_clock_and_voltage_limits *max_limits; |
bool disable_mclk_switching; |
u32 mclk, sclk; |
u16 vddc, vddci; |
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; |
if ((rdev->pm.dpm.new_active_crtc_count > 1) || |
btc_dpm_vblank_too_short(rdev)) |
disable_mclk_switching = true; |
else |
disable_mclk_switching = false; |
if (rdev->pm.dpm.ac_power) |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
else |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc; |
if (rdev->pm.dpm.ac_power == false) { |
if (ps->high.mclk > max_limits->mclk) |
ps->high.mclk = max_limits->mclk; |
if (ps->high.sclk > max_limits->sclk) |
ps->high.sclk = max_limits->sclk; |
if (ps->high.vddc > max_limits->vddc) |
ps->high.vddc = max_limits->vddc; |
if (ps->high.vddci > max_limits->vddci) |
ps->high.vddci = max_limits->vddci; |
if (ps->medium.mclk > max_limits->mclk) |
ps->medium.mclk = max_limits->mclk; |
if (ps->medium.sclk > max_limits->sclk) |
ps->medium.sclk = max_limits->sclk; |
if (ps->medium.vddc > max_limits->vddc) |
ps->medium.vddc = max_limits->vddc; |
if (ps->medium.vddci > max_limits->vddci) |
ps->medium.vddci = max_limits->vddci; |
if (ps->low.mclk > max_limits->mclk) |
ps->low.mclk = max_limits->mclk; |
if (ps->low.sclk > max_limits->sclk) |
ps->low.sclk = max_limits->sclk; |
if (ps->low.vddc > max_limits->vddc) |
ps->low.vddc = max_limits->vddc; |
if (ps->low.vddci > max_limits->vddci) |
ps->low.vddci = max_limits->vddci; |
} |
/* limit clocks to max supported clocks based on voltage dependency tables */ |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
&max_sclk_vddc); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
&max_mclk_vddci); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
&max_mclk_vddc); |
if (max_sclk_vddc) { |
if (ps->low.sclk > max_sclk_vddc) |
ps->low.sclk = max_sclk_vddc; |
if (ps->medium.sclk > max_sclk_vddc) |
ps->medium.sclk = max_sclk_vddc; |
if (ps->high.sclk > max_sclk_vddc) |
ps->high.sclk = max_sclk_vddc; |
} |
if (max_mclk_vddci) { |
if (ps->low.mclk > max_mclk_vddci) |
ps->low.mclk = max_mclk_vddci; |
if (ps->medium.mclk > max_mclk_vddci) |
ps->medium.mclk = max_mclk_vddci; |
if (ps->high.mclk > max_mclk_vddci) |
ps->high.mclk = max_mclk_vddci; |
} |
if (max_mclk_vddc) { |
if (ps->low.mclk > max_mclk_vddc) |
ps->low.mclk = max_mclk_vddc; |
if (ps->medium.mclk > max_mclk_vddc) |
ps->medium.mclk = max_mclk_vddc; |
if (ps->high.mclk > max_mclk_vddc) |
ps->high.mclk = max_mclk_vddc; |
} |
/* XXX validate the min clocks required for display */ |
if (disable_mclk_switching) { |
sclk = ps->low.sclk; |
mclk = ps->high.mclk; |
vddc = ps->low.vddc; |
vddci = ps->high.vddci; |
} else { |
sclk = ps->low.sclk; |
mclk = ps->low.mclk; |
vddc = ps->low.vddc; |
vddci = ps->low.vddci; |
} |
/* adjusted low state */ |
ps->low.sclk = sclk; |
ps->low.mclk = mclk; |
ps->low.vddc = vddc; |
ps->low.vddci = vddci; |
btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk, |
&ps->low.sclk, &ps->low.mclk); |
/* adjusted medium, high states */ |
if (ps->medium.sclk < ps->low.sclk) |
ps->medium.sclk = ps->low.sclk; |
if (ps->medium.vddc < ps->low.vddc) |
ps->medium.vddc = ps->low.vddc; |
if (ps->high.sclk < ps->medium.sclk) |
ps->high.sclk = ps->medium.sclk; |
if (ps->high.vddc < ps->medium.vddc) |
ps->high.vddc = ps->medium.vddc; |
if (disable_mclk_switching) { |
mclk = ps->low.mclk; |
if (mclk < ps->medium.mclk) |
mclk = ps->medium.mclk; |
if (mclk < ps->high.mclk) |
mclk = ps->high.mclk; |
ps->low.mclk = mclk; |
ps->low.vddci = vddci; |
ps->medium.mclk = mclk; |
ps->medium.vddci = vddci; |
ps->high.mclk = mclk; |
ps->high.vddci = vddci; |
} else { |
if (ps->medium.mclk < ps->low.mclk) |
ps->medium.mclk = ps->low.mclk; |
if (ps->medium.vddci < ps->low.vddci) |
ps->medium.vddci = ps->low.vddci; |
if (ps->high.mclk < ps->medium.mclk) |
ps->high.mclk = ps->medium.mclk; |
if (ps->high.vddci < ps->medium.vddci) |
ps->high.vddci = ps->medium.vddci; |
} |
btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk, |
&ps->medium.sclk, &ps->medium.mclk); |
btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk, |
&ps->high.sclk, &ps->high.mclk); |
btc_adjust_clock_combinations(rdev, max_limits, &ps->low); |
btc_adjust_clock_combinations(rdev, max_limits, &ps->medium); |
btc_adjust_clock_combinations(rdev, max_limits, &ps->high); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
ps->low.sclk, max_limits->vddc, &ps->low.vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
ps->low.mclk, max_limits->vddci, &ps->low.vddci); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
ps->low.mclk, max_limits->vddc, &ps->low.vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk, |
rdev->clock.current_dispclk, max_limits->vddc, &ps->low.vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
ps->medium.sclk, max_limits->vddc, &ps->medium.vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
ps->medium.mclk, max_limits->vddci, &ps->medium.vddci); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
ps->medium.mclk, max_limits->vddc, &ps->medium.vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk, |
rdev->clock.current_dispclk, max_limits->vddc, &ps->medium.vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
ps->high.sclk, max_limits->vddc, &ps->high.vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
ps->high.mclk, max_limits->vddci, &ps->high.vddci); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
ps->high.mclk, max_limits->vddc, &ps->high.vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk, |
rdev->clock.current_dispclk, max_limits->vddc, &ps->high.vddc); |
btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci, |
&ps->low.vddc, &ps->low.vddci); |
btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci, |
&ps->medium.vddc, &ps->medium.vddci); |
btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci, |
&ps->high.vddc, &ps->high.vddci); |
if ((ps->high.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) && |
(ps->medium.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) && |
(ps->low.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc)) |
ps->dc_compatible = true; |
else |
ps->dc_compatible = false; |
if (ps->low.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2) |
ps->low.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2; |
if (ps->medium.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2) |
ps->medium.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2; |
if (ps->high.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2) |
ps->high.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2; |
} |
static void btc_update_current_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct rv7xx_ps *new_ps = rv770_get_ps(rps); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
eg_pi->current_rps = *rps; |
eg_pi->current_ps = *new_ps; |
eg_pi->current_rps.ps_priv = &eg_pi->current_ps; |
} |
static void btc_update_requested_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct rv7xx_ps *new_ps = rv770_get_ps(rps); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
eg_pi->requested_rps = *rps; |
eg_pi->requested_ps = *new_ps; |
eg_pi->requested_rps.ps_priv = &eg_pi->requested_ps; |
} |
void btc_dpm_reset_asic(struct radeon_device *rdev) |
{ |
rv770_restrict_performance_levels_before_switch(rdev); |
btc_disable_ulv(rdev); |
btc_set_boot_state_timing(rdev); |
rv770_set_boot_state(rdev); |
} |
int btc_dpm_pre_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; |
struct radeon_ps *new_ps = &requested_ps; |
btc_update_requested_ps(rdev, new_ps); |
btc_apply_state_adjust_rules(rdev, &eg_pi->requested_rps); |
return 0; |
} |
int btc_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *new_ps = &eg_pi->requested_rps; |
struct radeon_ps *old_ps = &eg_pi->current_rps; |
int ret; |
ret = btc_disable_ulv(rdev); |
btc_set_boot_state_timing(rdev); |
ret = rv770_restrict_performance_levels_before_switch(rdev); |
if (ret) { |
DRM_ERROR("rv770_restrict_performance_levels_before_switch failed\n"); |
return ret; |
} |
if (eg_pi->pcie_performance_request) |
cypress_notify_link_speed_change_before_state_change(rdev, new_ps, old_ps); |
rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
ret = rv770_halt_smc(rdev); |
if (ret) { |
DRM_ERROR("rv770_halt_smc failed\n"); |
return ret; |
} |
btc_set_at_for_uvd(rdev, new_ps); |
if (eg_pi->smu_uvd_hs) |
btc_notify_uvd_to_smc(rdev, new_ps); |
ret = cypress_upload_sw_state(rdev, new_ps); |
if (ret) { |
DRM_ERROR("cypress_upload_sw_state failed\n"); |
return ret; |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = cypress_upload_mc_reg_table(rdev, new_ps); |
if (ret) { |
DRM_ERROR("cypress_upload_mc_reg_table failed\n"); |
return ret; |
} |
} |
cypress_program_memory_timing_parameters(rdev, new_ps); |
ret = rv770_resume_smc(rdev); |
if (ret) { |
DRM_ERROR("rv770_resume_smc failed\n"); |
return ret; |
} |
ret = rv770_set_sw_state(rdev); |
if (ret) { |
DRM_ERROR("rv770_set_sw_state failed\n"); |
return ret; |
} |
rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
if (eg_pi->pcie_performance_request) |
cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps); |
ret = btc_set_power_state_conditionally_enable_ulv(rdev, new_ps); |
if (ret) { |
DRM_ERROR("btc_set_power_state_conditionally_enable_ulv failed\n"); |
return ret; |
} |
return 0; |
} |
void btc_dpm_post_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *new_ps = &eg_pi->requested_rps; |
btc_update_current_ps(rdev, new_ps); |
} |
int btc_dpm_enable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
int ret; |
if (pi->gfx_clock_gating) |
btc_cg_clock_gating_default(rdev); |
if (btc_dpm_enabled(rdev)) |
return -EINVAL; |
if (pi->mg_clock_gating) |
btc_mg_clock_gating_default(rdev); |
if (eg_pi->ls_clock_gating) |
btc_ls_clock_gating_default(rdev); |
if (pi->voltage_control) { |
rv770_enable_voltage_control(rdev, true); |
ret = cypress_construct_voltage_tables(rdev); |
if (ret) { |
DRM_ERROR("cypress_construct_voltage_tables failed\n"); |
return ret; |
} |
} |
if (pi->mvdd_control) { |
ret = cypress_get_mvdd_configuration(rdev); |
if (ret) { |
DRM_ERROR("cypress_get_mvdd_configuration failed\n"); |
return ret; |
} |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = btc_initialize_mc_reg_table(rdev); |
if (ret) |
eg_pi->dynamic_ac_timing = false; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) |
rv770_enable_backbias(rdev, true); |
if (pi->dynamic_ss) |
cypress_enable_spread_spectrum(rdev, true); |
if (pi->thermal_protection) |
rv770_enable_thermal_protection(rdev, true); |
rv770_setup_bsp(rdev); |
rv770_program_git(rdev); |
rv770_program_tp(rdev); |
rv770_program_tpp(rdev); |
rv770_program_sstp(rdev); |
rv770_program_engine_speed_parameters(rdev); |
cypress_enable_display_gap(rdev); |
rv770_program_vc(rdev); |
if (pi->dynamic_pcie_gen2) |
btc_enable_dynamic_pcie_gen2(rdev, true); |
ret = rv770_upload_firmware(rdev); |
if (ret) { |
DRM_ERROR("rv770_upload_firmware failed\n"); |
return ret; |
} |
ret = cypress_get_table_locations(rdev); |
if (ret) { |
DRM_ERROR("cypress_get_table_locations failed\n"); |
return ret; |
} |
ret = btc_init_smc_table(rdev, boot_ps); |
if (ret) |
return ret; |
if (eg_pi->dynamic_ac_timing) { |
ret = cypress_populate_mc_reg_table(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("cypress_populate_mc_reg_table failed\n"); |
return ret; |
} |
} |
cypress_program_response_times(rdev); |
r7xx_start_smc(rdev); |
ret = cypress_notify_smc_display_change(rdev, false); |
if (ret) { |
DRM_ERROR("cypress_notify_smc_display_change failed\n"); |
return ret; |
} |
cypress_enable_sclk_control(rdev, true); |
if (eg_pi->memory_transition) |
cypress_enable_mclk_control(rdev, true); |
cypress_start_dpm(rdev); |
if (pi->gfx_clock_gating) |
btc_cg_clock_gating_enable(rdev, true); |
if (pi->mg_clock_gating) |
btc_mg_clock_gating_enable(rdev, true); |
if (eg_pi->ls_clock_gating) |
btc_ls_clock_gating_enable(rdev, true); |
rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); |
btc_init_stutter_mode(rdev); |
btc_update_current_ps(rdev, rdev->pm.dpm.boot_ps); |
return 0; |
}; |
void btc_dpm_disable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (!btc_dpm_enabled(rdev)) |
return; |
rv770_clear_vc(rdev); |
if (pi->thermal_protection) |
rv770_enable_thermal_protection(rdev, false); |
if (pi->dynamic_pcie_gen2) |
btc_enable_dynamic_pcie_gen2(rdev, false); |
if (rdev->irq.installed && |
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { |
rdev->irq.dpm_thermal = false; |
radeon_irq_set(rdev); |
} |
if (pi->gfx_clock_gating) |
btc_cg_clock_gating_enable(rdev, false); |
if (pi->mg_clock_gating) |
btc_mg_clock_gating_enable(rdev, false); |
if (eg_pi->ls_clock_gating) |
btc_ls_clock_gating_enable(rdev, false); |
rv770_stop_dpm(rdev); |
btc_reset_to_default(rdev); |
btc_stop_smc(rdev); |
cypress_enable_spread_spectrum(rdev, false); |
btc_update_current_ps(rdev, rdev->pm.dpm.boot_ps); |
} |
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); |
rv770_read_voltage_smio_registers(rdev); |
if (eg_pi->pcie_performance_request) |
cypress_advertise_gen2_capability(rdev); |
rv770_get_pcie_gen2_status(rdev); |
rv770_enable_acpi_pm(rdev); |
} |
int btc_dpm_init(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi; |
struct evergreen_power_info *eg_pi; |
struct atom_clock_dividers dividers; |
int ret; |
eg_pi = kzalloc(sizeof(struct evergreen_power_info), GFP_KERNEL); |
if (eg_pi == NULL) |
return -ENOMEM; |
rdev->pm.dpm.priv = eg_pi; |
pi = &eg_pi->rv7xx; |
rv770_get_max_vddc(rdev); |
eg_pi->ulv.supported = false; |
pi->acpi_vddc = 0; |
eg_pi->acpi_vddci = 0; |
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; |
ret = r600_parse_extended_power_table(rdev); |
if (ret) |
return ret; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = |
kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 800; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 800; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 800; |
if (rdev->pm.dpm.voltage_response_time == 0) |
rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; |
if (rdev->pm.dpm.backbias_response_time == 0) |
rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
0, false, ÷rs); |
if (ret) |
pi->ref_div = dividers.ref_div + 1; |
else |
pi->ref_div = R600_REFERENCEDIVIDER_DFLT; |
pi->mclk_strobe_mode_threshold = 40000; |
pi->mclk_edc_enable_threshold = 40000; |
eg_pi->mclk_edc_wr_enable_threshold = 40000; |
pi->rlp = RV770_RLP_DFLT; |
pi->rmp = RV770_RMP_DFLT; |
pi->lhp = RV770_LHP_DFLT; |
pi->lmp = RV770_LMP_DFLT; |
eg_pi->ats[0].rlp = RV770_RLP_DFLT; |
eg_pi->ats[0].rmp = RV770_RMP_DFLT; |
eg_pi->ats[0].lhp = RV770_LHP_DFLT; |
eg_pi->ats[0].lmp = RV770_LMP_DFLT; |
eg_pi->ats[1].rlp = BTC_RLP_UVD_DFLT; |
eg_pi->ats[1].rmp = BTC_RMP_UVD_DFLT; |
eg_pi->ats[1].lhp = BTC_LHP_UVD_DFLT; |
eg_pi->ats[1].lmp = BTC_LMP_UVD_DFLT; |
eg_pi->smu_uvd_hs = true; |
pi->voltage_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0); |
pi->mvdd_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0); |
eg_pi->vddci_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0); |
rv770_get_engine_memory_ss(rdev); |
pi->asi = RV770_ASI_DFLT; |
pi->pasi = CYPRESS_HASI_DFLT; |
pi->vrc = CYPRESS_VRC_DFLT; |
pi->power_gating = false; |
pi->gfx_clock_gating = true; |
pi->mg_clock_gating = true; |
pi->mgcgtssm = true; |
eg_pi->ls_clock_gating = false; |
eg_pi->sclk_deep_sleep = false; |
pi->dynamic_pcie_gen2 = true; |
if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) |
pi->thermal_protection = true; |
else |
pi->thermal_protection = false; |
pi->display_gap = true; |
if (rdev->flags & RADEON_IS_MOBILITY) |
pi->dcodt = true; |
else |
pi->dcodt = false; |
pi->ulps = true; |
eg_pi->dynamic_ac_timing = true; |
eg_pi->abm = true; |
eg_pi->mcls = true; |
eg_pi->light_sleep = true; |
eg_pi->memory_transition = true; |
#if defined(CONFIG_ACPI) |
eg_pi->pcie_performance_request = |
radeon_acpi_is_pcie_performance_request_supported(rdev); |
#else |
eg_pi->pcie_performance_request = false; |
#endif |
if (rdev->family == CHIP_BARTS) |
eg_pi->dll_default_on = true; |
else |
eg_pi->dll_default_on = false; |
eg_pi->sclk_deep_sleep = false; |
if (ASIC_IS_LOMBOK(rdev)) |
pi->mclk_stutter_mode_threshold = 30000; |
else |
pi->mclk_stutter_mode_threshold = 0; |
pi->sram_end = SMC_RAM_END; |
rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 4; |
rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200; |
rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2 = 900; |
rdev->pm.dpm.dyn_state.valid_sclk_values.count = ARRAY_SIZE(btc_valid_sclk); |
rdev->pm.dpm.dyn_state.valid_sclk_values.values = btc_valid_sclk; |
rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0; |
rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL; |
if (rdev->family == CHIP_TURKS) |
rdev->pm.dpm.dyn_state.sclk_mclk_delta = 15000; |
else |
rdev->pm.dpm.dyn_state.sclk_mclk_delta = 10000; |
/* make sure dc limits are valid */ |
if ((rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) || |
(rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0)) |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc = |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
return 0; |
} |
void btc_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries); |
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); |
struct rv7xx_ps *requested_state = rv770_get_ps(&eg_pi->requested_rps); |
if (low) |
return requested_state->low.sclk; |
else |
return requested_state->high.sclk; |
} |
u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct rv7xx_ps *requested_state = rv770_get_ps(&eg_pi->requested_rps); |
if (low) |
return requested_state->low.mclk; |
else |
return requested_state->high.mclk; |
} |
/drivers/video/drm/radeon/btc_dpm.h |
---|
0,0 → 1,59 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __BTC_DPM_H__ |
#define __BTC_DPM_H__ |
#define BTC_RLP_UVD_DFLT 20 |
#define BTC_RMP_UVD_DFLT 50 |
#define BTC_LHP_UVD_DFLT 50 |
#define BTC_LMP_UVD_DFLT 20 |
#define BARTS_MGCGCGTSSMCTRL_DFLT 0x81944000 |
#define TURKS_MGCGCGTSSMCTRL_DFLT 0x6e944000 |
#define CAICOS_MGCGCGTSSMCTRL_DFLT 0x46944040 |
#define BTC_CGULVPARAMETER_DFLT 0x00040035 |
#define BTC_CGULVCONTROL_DFLT 0x00001450 |
extern u32 btc_valid_sclk[40]; |
void btc_read_arb_registers(struct radeon_device *rdev); |
void btc_program_mgcg_hw_sequence(struct radeon_device *rdev, |
const u32 *sequence, u32 count); |
void btc_skip_blacklist_clocks(struct radeon_device *rdev, |
const u32 max_sclk, const u32 max_mclk, |
u32 *sclk, u32 *mclk); |
void btc_adjust_clock_combinations(struct radeon_device *rdev, |
const struct radeon_clock_and_voltage_limits *max_limits, |
struct rv7xx_pl *pl); |
void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table, |
u32 clock, u16 max_voltage, u16 *voltage); |
void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table, |
u32 *max_clock); |
void btc_apply_voltage_delta_rules(struct radeon_device *rdev, |
u16 max_vddc, u16 max_vddci, |
u16 *vddc, u16 *vddci); |
bool btc_dpm_enabled(struct radeon_device *rdev); |
int btc_reset_to_default(struct radeon_device *rdev); |
void btc_notify_uvd_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state); |
#endif |
/drivers/video/drm/radeon/btcd.h |
---|
0,0 → 1,185 |
/* |
* Copyright 2010 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#ifndef _BTCD_H_ |
#define _BTCD_H_ |
/* pm registers */ |
#define GENERAL_PWRMGT 0x63c |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define THERMAL_PROTECTION_DIS (1 << 2) |
# define THERMAL_PROTECTION_TYPE (1 << 3) |
# define ENABLE_GEN2PCIE (1 << 4) |
# define ENABLE_GEN2XSP (1 << 5) |
# define SW_SMIO_INDEX(x) ((x) << 6) |
# define SW_SMIO_INDEX_MASK (3 << 6) |
# define SW_SMIO_INDEX_SHIFT 6 |
# define LOW_VOLT_D2_ACPI (1 << 8) |
# define LOW_VOLT_D3_ACPI (1 << 9) |
# define VOLT_PWRMGT_EN (1 << 10) |
# define BACKBIAS_PAD_EN (1 << 18) |
# define BACKBIAS_VALUE (1 << 19) |
# 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) |
#define CG_CLIENT_REQ_SHIFT 0 |
#define CG_CLIENT_RESP(x) ((x) << 8) |
#define CG_CLIENT_RESP_MASK (0xff << 8) |
#define CG_CLIENT_RESP_SHIFT 8 |
#define CLIENT_CG_REQ(x) ((x) << 16) |
#define CLIENT_CG_REQ_MASK (0xff << 16) |
#define CLIENT_CG_REQ_SHIFT 16 |
#define CLIENT_CG_RESP(x) ((x) << 24) |
#define CLIENT_CG_RESP_MASK (0xff << 24) |
#define CLIENT_CG_RESP_SHIFT 24 |
#define SCLK_PSKIP_CNTL 0x8c0 |
#define PSKIP_ON_ALLOW_STOP_HI(x) ((x) << 16) |
#define PSKIP_ON_ALLOW_STOP_HI_MASK (0xff << 16) |
#define PSKIP_ON_ALLOW_STOP_HI_SHIFT 16 |
#define CG_ULV_CONTROL 0x8c8 |
#define CG_ULV_PARAMETER 0x8cc |
#define MC_ARB_DRAM_TIMING 0x2774 |
#define MC_ARB_DRAM_TIMING2 0x2778 |
#define MC_ARB_RFSH_RATE 0x27b0 |
#define POWERMODE0(x) ((x) << 0) |
#define POWERMODE0_MASK (0xff << 0) |
#define POWERMODE0_SHIFT 0 |
#define POWERMODE1(x) ((x) << 8) |
#define POWERMODE1_MASK (0xff << 8) |
#define POWERMODE1_SHIFT 8 |
#define POWERMODE2(x) ((x) << 16) |
#define POWERMODE2_MASK (0xff << 16) |
#define POWERMODE2_SHIFT 16 |
#define POWERMODE3(x) ((x) << 24) |
#define POWERMODE3_MASK (0xff << 24) |
#define POWERMODE3_SHIFT 24 |
#define MC_ARB_BURST_TIME 0x2808 |
#define STATE0(x) ((x) << 0) |
#define STATE0_MASK (0x1f << 0) |
#define STATE0_SHIFT 0 |
#define STATE1(x) ((x) << 5) |
#define STATE1_MASK (0x1f << 5) |
#define STATE1_SHIFT 5 |
#define STATE2(x) ((x) << 10) |
#define STATE2_MASK (0x1f << 10) |
#define STATE2_SHIFT 10 |
#define STATE3(x) ((x) << 15) |
#define STATE3_MASK (0x1f << 15) |
#define STATE3_SHIFT 15 |
#define MC_SEQ_RAS_TIMING 0x28a0 |
#define MC_SEQ_CAS_TIMING 0x28a4 |
#define MC_SEQ_MISC_TIMING 0x28a8 |
#define MC_SEQ_MISC_TIMING2 0x28ac |
#define MC_SEQ_RD_CTL_D0 0x28b4 |
#define MC_SEQ_RD_CTL_D1 0x28b8 |
#define MC_SEQ_WR_CTL_D0 0x28bc |
#define MC_SEQ_WR_CTL_D1 0x28c0 |
#define MC_PMG_AUTO_CFG 0x28d4 |
#define MC_SEQ_STATUS_M 0x29f4 |
# define PMG_PWRSTATE (1 << 16) |
#define MC_SEQ_MISC0 0x2a00 |
#define MC_SEQ_MISC0_GDDR5_SHIFT 28 |
#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000 |
#define MC_SEQ_MISC0_GDDR5_VALUE 5 |
#define MC_SEQ_MISC1 0x2a04 |
#define MC_SEQ_RESERVE_M 0x2a08 |
#define MC_PMG_CMD_EMRS 0x2a0c |
#define MC_SEQ_MISC3 0x2a2c |
#define MC_SEQ_MISC5 0x2a54 |
#define MC_SEQ_MISC6 0x2a58 |
#define MC_SEQ_MISC7 0x2a64 |
#define MC_SEQ_CG 0x2a68 |
#define CG_SEQ_REQ(x) ((x) << 0) |
#define CG_SEQ_REQ_MASK (0xff << 0) |
#define CG_SEQ_REQ_SHIFT 0 |
#define CG_SEQ_RESP(x) ((x) << 8) |
#define CG_SEQ_RESP_MASK (0xff << 8) |
#define CG_SEQ_RESP_SHIFT 8 |
#define SEQ_CG_REQ(x) ((x) << 16) |
#define SEQ_CG_REQ_MASK (0xff << 16) |
#define SEQ_CG_REQ_SHIFT 16 |
#define SEQ_CG_RESP(x) ((x) << 24) |
#define SEQ_CG_RESP_MASK (0xff << 24) |
#define SEQ_CG_RESP_SHIFT 24 |
#define MC_SEQ_RAS_TIMING_LP 0x2a6c |
#define MC_SEQ_CAS_TIMING_LP 0x2a70 |
#define MC_SEQ_MISC_TIMING_LP 0x2a74 |
#define MC_SEQ_MISC_TIMING2_LP 0x2a78 |
#define MC_SEQ_WR_CTL_D0_LP 0x2a7c |
#define MC_SEQ_WR_CTL_D1_LP 0x2a80 |
#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84 |
#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88 |
#define MC_PMG_CMD_MRS 0x2aac |
#define MC_SEQ_RD_CTL_D0_LP 0x2b1c |
#define MC_SEQ_RD_CTL_D1_LP 0x2b20 |
#define MC_PMG_CMD_MRS1 0x2b44 |
#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48 |
#define LB_SYNC_RESET_SEL 0x6b28 |
#define LB_SYNC_RESET_SEL_MASK (3 << 0) |
#define LB_SYNC_RESET_SEL_SHIFT 0 |
/* PCIE link stuff */ |
#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ |
# define LC_GEN2_EN_STRAP (1 << 0) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) |
# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5) |
# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 |
# define LC_CURRENT_DATA_RATE (1 << 11) |
# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12 |
# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) |
# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) |
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) |
# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) |
#endif |
/drivers/video/drm/radeon/cayman_blit_shaders.c |
---|
317,58 → 317,4 |
0x00000010, /* */ |
}; |
const u32 cayman_vs[] = |
{ |
0x00000004, |
0x80400400, |
0x0000a03c, |
0x95000688, |
0x00004000, |
0x15000688, |
0x00000000, |
0x88000000, |
0x04000000, |
0x67961001, |
#ifdef __BIG_ENDIAN |
0x00020000, |
#else |
0x00000000, |
#endif |
0x00000000, |
0x04000000, |
0x67961000, |
#ifdef __BIG_ENDIAN |
0x00020008, |
#else |
0x00000008, |
#endif |
0x00000000, |
}; |
const u32 cayman_ps[] = |
{ |
0x00000004, |
0xa00c0000, |
0x00000008, |
0x80400000, |
0x00000000, |
0x95000688, |
0x00000000, |
0x88000000, |
0x00380400, |
0x00146b10, |
0x00380000, |
0x20146b10, |
0x00380400, |
0x40146b00, |
0x80380000, |
0x60146b00, |
0x00000010, |
0x000d1000, |
0xb0800000, |
0x00000000, |
}; |
const u32 cayman_ps_size = ARRAY_SIZE(cayman_ps); |
const u32 cayman_vs_size = ARRAY_SIZE(cayman_vs); |
const u32 cayman_default_size = ARRAY_SIZE(cayman_default_state); |
/drivers/video/drm/radeon/cayman_reg_safe.h |
---|
0,0 → 1,514 |
static const unsigned cayman_reg_safe_bm[2047] = { |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFEF7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0xCFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFDDEFFF, 0xCF3FFFFF, 0xFFFFE00F, |
0xFEFFFFDF, 0xFFFFFFFF, 0xFFFFFFEF, 0xEFFFFFFF, |
0xFFFFFFCC, 0xFFFFFFFF, 0xFFFFFFFF, 0xBFFFFFD7, |
0xFFFBF8FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF7FFE, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFB, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFDF0FFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xC0000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFC3E4, 0xFFFFFFFF, 0x0000FFFF, 0x00000000, |
0x000CC000, 0x00000000, 0xFF500000, 0x00000000, |
0x00000E00, 0x00000000, 0x00000000, 0x00000000, |
0x00000000, 0x00000000, 0xFFFFFCF8, 0xFE07FF00, |
0x3CF1F003, 0xE39E7BCF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xE7020000, 0xDDD898DD, 0x079FA3FD, 0x011FFFE0, |
0xBFFF0000, 0xEFC3DF87, 0x7BF0F7E1, 0x1EFC3DF8, |
0xDFBF0F7E, 0xFFFFF7EF, 0xFFFFFFFF, 0x00000000, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xCFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF8, |
}; |
/drivers/video/drm/radeon/ci_dpm.c |
---|
0,0 → 1,5341 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#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" |
#include "atom.h" |
#include <linux/seq_file.h> |
#define MC_CG_ARB_FREQ_F0 0x0a |
#define MC_CG_ARB_FREQ_F1 0x0b |
#define MC_CG_ARB_FREQ_F2 0x0c |
#define MC_CG_ARB_FREQ_F3 0x0d |
#define SMC_RAM_END 0x40000 |
#define VOLTAGE_SCALE 4 |
#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, |
{ 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61 }, |
{ 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 } |
}; |
static const struct ci_pt_defaults defaults_bonaire_pro = |
{ |
1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x65062, |
{ 0x8C, 0x23F, 0x244, 0xA6, 0x83, 0x85, 0x86, 0x86, 0x83, 0xDB, 0xDB, 0xDA, 0x67, 0x60, 0x5F }, |
{ 0x187, 0x193, 0x193, 0x1C7, 0x1D1, 0x1D1, 0x210, 0x219, 0x219, 0x266, 0x26C, 0x26C, 0x2C9, 0x2CB, 0x2CB } |
}; |
static const struct ci_pt_defaults defaults_saturn_xt = |
{ |
1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x70000, |
{ 0x8C, 0x247, 0x249, 0xA6, 0x80, 0x81, 0x8B, 0x89, 0x86, 0xC9, 0xCA, 0xC9, 0x4D, 0x4D, 0x4D }, |
{ 0x187, 0x187, 0x187, 0x1C7, 0x1C7, 0x1C7, 0x210, 0x210, 0x210, 0x266, 0x266, 0x266, 0x2C9, 0x2C9, 0x2C9 } |
}; |
static const struct ci_pt_defaults defaults_saturn_pro = |
{ |
1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x30000, |
{ 0x96, 0x21D, 0x23B, 0xA1, 0x85, 0x87, 0x83, 0x84, 0x81, 0xE6, 0xE6, 0xE6, 0x71, 0x6A, 0x6A }, |
{ 0x193, 0x19E, 0x19E, 0x1D2, 0x1DC, 0x1DC, 0x21A, 0x223, 0x223, 0x26E, 0x27E, 0x274, 0x2CF, 0x2D2, 0x2D2 } |
}; |
static const struct ci_pt_config_reg didt_config_ci[] = |
{ |
{ 0x10, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x10, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x10, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x10, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x11, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x11, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x11, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x11, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x12, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x12, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x12, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x12, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x2, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x2, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x2, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x1, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x1, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x0, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x30, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x30, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x30, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x30, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x31, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x31, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x31, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x31, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x32, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x32, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x32, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x32, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x22, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x22, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x22, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x21, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x21, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x20, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x50, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x50, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x50, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x50, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x51, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x51, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x51, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x51, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x52, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x52, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x52, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x52, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x42, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x42, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x42, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x41, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x41, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x40, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x70, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x70, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x70, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x70, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x71, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x71, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x71, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x71, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x72, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x72, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x72, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x72, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x62, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x62, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x62, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x61, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x61, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0x60, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND }, |
{ 0xFFFFFFFF } |
}; |
extern u8 rv770_get_memory_module_index(struct radeon_device *rdev); |
extern void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table, |
u32 *max_clock); |
extern int ni_copy_and_switch_arb_sets(struct radeon_device *rdev, |
u32 arb_freq_src, u32 arb_freq_dest); |
extern u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock); |
extern u8 si_get_mclk_frequency_ratio(u32 memory_clock, bool strobe_mode); |
extern void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev, |
u32 max_voltage_steps, |
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); |
static int ci_get_std_voltage_value_sidd(struct radeon_device *rdev, |
struct atom_voltage_table_entry *voltage_table, |
u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd); |
static int ci_set_power_limit(struct radeon_device *rdev, u32 n); |
static int ci_set_overdrive_target_tdp(struct radeon_device *rdev, |
u32 target_tdp); |
static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate); |
static struct ci_power_info *ci_get_pi(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
static struct ci_ps *ci_get_ps(struct radeon_ps *rps) |
{ |
struct ci_ps *ps = rps->ps_priv; |
return ps; |
} |
static void ci_initialize_powertune_defaults(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
switch (rdev->pdev->device) { |
case 0x6649: |
case 0x6650: |
case 0x6651: |
case 0x6658: |
case 0x665C: |
case 0x665D: |
default: |
pi->powertune_defaults = &defaults_bonaire_xt; |
break; |
case 0x6640: |
case 0x6641: |
case 0x6646: |
case 0x6647: |
pi->powertune_defaults = &defaults_saturn_xt; |
break; |
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; |
} |
pi->dte_tj_offset = 0; |
pi->caps_power_containment = true; |
pi->caps_cac = false; |
pi->caps_sq_ramping = false; |
pi->caps_db_ramping = false; |
pi->caps_td_ramping = false; |
pi->caps_tcp_ramping = false; |
if (pi->caps_power_containment) { |
pi->caps_cac = true; |
pi->enable_bapm_feature = true; |
pi->enable_tdc_limit_feature = true; |
pi->enable_pkg_pwr_tracking_feature = true; |
} |
} |
static u8 ci_convert_to_vid(u16 vddc) |
{ |
return (6200 - (vddc * VOLTAGE_SCALE)) / 25; |
} |
static int ci_populate_bapm_vddc_vid_sidd(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd; |
u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd; |
u8 *hi2_vid = pi->smc_powertune_table.BapmVddCVidHiSidd2; |
u32 i; |
if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries == NULL) |
return -EINVAL; |
if (rdev->pm.dpm.dyn_state.cac_leakage_table.count > 8) |
return -EINVAL; |
if (rdev->pm.dpm.dyn_state.cac_leakage_table.count != |
rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count) |
return -EINVAL; |
for (i = 0; i < rdev->pm.dpm.dyn_state.cac_leakage_table.count; i++) { |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) { |
lo_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1); |
hi_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2); |
hi2_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3); |
} else { |
lo_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc); |
hi_vid[i] = ci_convert_to_vid((u16)rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage); |
} |
} |
return 0; |
} |
static int ci_populate_vddc_vid(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u8 *vid = pi->smc_powertune_table.VddCVid; |
u32 i; |
if (pi->vddc_voltage_table.count > 8) |
return -EINVAL; |
for (i = 0; i < pi->vddc_voltage_table.count; i++) |
vid[i] = ci_convert_to_vid(pi->vddc_voltage_table.entries[i].value); |
return 0; |
} |
static int ci_populate_svi_load_line(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults; |
pi->smc_powertune_table.SviLoadLineEn = pt_defaults->svi_load_line_en; |
pi->smc_powertune_table.SviLoadLineVddC = pt_defaults->svi_load_line_vddc; |
pi->smc_powertune_table.SviLoadLineTrimVddC = 3; |
pi->smc_powertune_table.SviLoadLineOffsetVddC = 0; |
return 0; |
} |
static int ci_populate_tdc_limit(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults; |
u16 tdc_limit; |
tdc_limit = rdev->pm.dpm.dyn_state.cac_tdp_table->tdc * 256; |
pi->smc_powertune_table.TDC_VDDC_PkgLimit = cpu_to_be16(tdc_limit); |
pi->smc_powertune_table.TDC_VDDC_ThrottleReleaseLimitPerc = |
pt_defaults->tdc_vddc_throttle_release_limit_perc; |
pi->smc_powertune_table.TDC_MAWt = pt_defaults->tdc_mawt; |
return 0; |
} |
static int ci_populate_dw8(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults; |
int ret; |
ret = ci_read_smc_sram_dword(rdev, |
SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, PmFuseTable) + |
offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), |
(u32 *)&pi->smc_powertune_table.TdcWaterfallCtl, |
pi->sram_end); |
if (ret) |
return -EINVAL; |
else |
pi->smc_powertune_table.TdcWaterfallCtl = pt_defaults->tdc_waterfall_ctl; |
return 0; |
} |
static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd; |
u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd; |
int i, min, max; |
min = max = hi_vid[0]; |
for (i = 0; i < 8; i++) { |
if (0 != hi_vid[i]) { |
if (min > hi_vid[i]) |
min = hi_vid[i]; |
if (max < hi_vid[i]) |
max = hi_vid[i]; |
} |
if (0 != lo_vid[i]) { |
if (min > lo_vid[i]) |
min = lo_vid[i]; |
if (max < lo_vid[i]) |
max = lo_vid[i]; |
} |
} |
if ((min == 0) || (max == 0)) |
return -EINVAL; |
pi->smc_powertune_table.GnbLPMLMaxVid = (u8)max; |
pi->smc_powertune_table.GnbLPMLMinVid = (u8)min; |
return 0; |
} |
static int ci_populate_bapm_vddc_base_leakage_sidd(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u16 hi_sidd = pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd; |
u16 lo_sidd = pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd; |
struct radeon_cac_tdp_table *cac_tdp_table = |
rdev->pm.dpm.dyn_state.cac_tdp_table; |
hi_sidd = cac_tdp_table->high_cac_leakage / 100 * 256; |
lo_sidd = cac_tdp_table->low_cac_leakage / 100 * 256; |
pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd = cpu_to_be16(hi_sidd); |
pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd = cpu_to_be16(lo_sidd); |
return 0; |
} |
static int ci_populate_bapm_parameters_in_dpm_table(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults; |
SMU7_Discrete_DpmTable *dpm_table = &pi->smc_state_table; |
struct radeon_cac_tdp_table *cac_tdp_table = |
rdev->pm.dpm.dyn_state.cac_tdp_table; |
struct radeon_ppm_table *ppm = rdev->pm.dpm.dyn_state.ppm_table; |
int i, j, k; |
const u16 *def1; |
const u16 *def2; |
dpm_table->DefaultTdp = cac_tdp_table->tdp * 256; |
dpm_table->TargetTdp = cac_tdp_table->configurable_tdp * 256; |
dpm_table->DTETjOffset = (u8)pi->dte_tj_offset; |
dpm_table->GpuTjMax = |
(u8)(pi->thermal_temp_setting.temperature_high / 1000); |
dpm_table->GpuTjHyst = 8; |
dpm_table->DTEAmbientTempBase = pt_defaults->dte_ambient_temp_base; |
if (ppm) { |
dpm_table->PPM_PkgPwrLimit = cpu_to_be16((u16)ppm->dgpu_tdp * 256 / 1000); |
dpm_table->PPM_TemperatureLimit = cpu_to_be16((u16)ppm->tj_max * 256); |
} else { |
dpm_table->PPM_PkgPwrLimit = cpu_to_be16(0); |
dpm_table->PPM_TemperatureLimit = cpu_to_be16(0); |
} |
dpm_table->BAPM_TEMP_GRADIENT = cpu_to_be32(pt_defaults->bapm_temp_gradient); |
def1 = pt_defaults->bapmti_r; |
def2 = pt_defaults->bapmti_rc; |
for (i = 0; i < SMU7_DTE_ITERATIONS; i++) { |
for (j = 0; j < SMU7_DTE_SOURCES; j++) { |
for (k = 0; k < SMU7_DTE_SINKS; k++) { |
dpm_table->BAPMTI_R[i][j][k] = cpu_to_be16(*def1); |
dpm_table->BAPMTI_RC[i][j][k] = cpu_to_be16(*def2); |
def1++; |
def2++; |
} |
} |
} |
return 0; |
} |
static int ci_populate_pm_base(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 pm_fuse_table_offset; |
int ret; |
if (pi->caps_power_containment) { |
ret = ci_read_smc_sram_dword(rdev, |
SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, PmFuseTable), |
&pm_fuse_table_offset, pi->sram_end); |
if (ret) |
return ret; |
ret = ci_populate_bapm_vddc_vid_sidd(rdev); |
if (ret) |
return ret; |
ret = ci_populate_vddc_vid(rdev); |
if (ret) |
return ret; |
ret = ci_populate_svi_load_line(rdev); |
if (ret) |
return ret; |
ret = ci_populate_tdc_limit(rdev); |
if (ret) |
return ret; |
ret = ci_populate_dw8(rdev); |
if (ret) |
return ret; |
ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(rdev); |
if (ret) |
return ret; |
ret = ci_populate_bapm_vddc_base_leakage_sidd(rdev); |
if (ret) |
return ret; |
ret = ci_copy_bytes_to_smc(rdev, pm_fuse_table_offset, |
(u8 *)&pi->smc_powertune_table, |
sizeof(SMU7_Discrete_PmFuses), pi->sram_end); |
if (ret) |
return ret; |
} |
return 0; |
} |
static void ci_do_enable_didt(struct radeon_device *rdev, const bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 data; |
if (pi->caps_sq_ramping) { |
data = RREG32_DIDT(DIDT_SQ_CTRL0); |
if (enable) |
data |= DIDT_CTRL_EN; |
else |
data &= ~DIDT_CTRL_EN; |
WREG32_DIDT(DIDT_SQ_CTRL0, data); |
} |
if (pi->caps_db_ramping) { |
data = RREG32_DIDT(DIDT_DB_CTRL0); |
if (enable) |
data |= DIDT_CTRL_EN; |
else |
data &= ~DIDT_CTRL_EN; |
WREG32_DIDT(DIDT_DB_CTRL0, data); |
} |
if (pi->caps_td_ramping) { |
data = RREG32_DIDT(DIDT_TD_CTRL0); |
if (enable) |
data |= DIDT_CTRL_EN; |
else |
data &= ~DIDT_CTRL_EN; |
WREG32_DIDT(DIDT_TD_CTRL0, data); |
} |
if (pi->caps_tcp_ramping) { |
data = RREG32_DIDT(DIDT_TCP_CTRL0); |
if (enable) |
data |= DIDT_CTRL_EN; |
else |
data &= ~DIDT_CTRL_EN; |
WREG32_DIDT(DIDT_TCP_CTRL0, data); |
} |
} |
static int ci_program_pt_config_registers(struct radeon_device *rdev, |
const struct ci_pt_config_reg *cac_config_regs) |
{ |
const struct ci_pt_config_reg *config_regs = cac_config_regs; |
u32 data; |
u32 cache = 0; |
if (config_regs == NULL) |
return -EINVAL; |
while (config_regs->offset != 0xFFFFFFFF) { |
if (config_regs->type == CISLANDS_CONFIGREG_CACHE) { |
cache |= ((config_regs->value << config_regs->shift) & config_regs->mask); |
} else { |
switch (config_regs->type) { |
case CISLANDS_CONFIGREG_SMC_IND: |
data = RREG32_SMC(config_regs->offset); |
break; |
case CISLANDS_CONFIGREG_DIDT_IND: |
data = RREG32_DIDT(config_regs->offset); |
break; |
default: |
data = RREG32(config_regs->offset << 2); |
break; |
} |
data &= ~config_regs->mask; |
data |= ((config_regs->value << config_regs->shift) & config_regs->mask); |
data |= cache; |
switch (config_regs->type) { |
case CISLANDS_CONFIGREG_SMC_IND: |
WREG32_SMC(config_regs->offset, data); |
break; |
case CISLANDS_CONFIGREG_DIDT_IND: |
WREG32_DIDT(config_regs->offset, data); |
break; |
default: |
WREG32(config_regs->offset << 2, data); |
break; |
} |
cache = 0; |
} |
config_regs++; |
} |
return 0; |
} |
static int ci_enable_didt(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int ret; |
if (pi->caps_sq_ramping || pi->caps_db_ramping || |
pi->caps_td_ramping || pi->caps_tcp_ramping) { |
cik_enter_rlc_safe_mode(rdev); |
if (enable) { |
ret = ci_program_pt_config_registers(rdev, didt_config_ci); |
if (ret) { |
cik_exit_rlc_safe_mode(rdev); |
return ret; |
} |
} |
ci_do_enable_didt(rdev, enable); |
cik_exit_rlc_safe_mode(rdev); |
} |
return 0; |
} |
static int ci_enable_power_containment(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
int ret = 0; |
if (enable) { |
pi->power_containment_features = 0; |
if (pi->caps_power_containment) { |
if (pi->enable_bapm_feature) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableDTE); |
if (smc_result != PPSMC_Result_OK) |
ret = -EINVAL; |
else |
pi->power_containment_features |= POWERCONTAINMENT_FEATURE_BAPM; |
} |
if (pi->enable_tdc_limit_feature) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_TDCLimitEnable); |
if (smc_result != PPSMC_Result_OK) |
ret = -EINVAL; |
else |
pi->power_containment_features |= POWERCONTAINMENT_FEATURE_TDCLimit; |
} |
if (pi->enable_pkg_pwr_tracking_feature) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PkgPwrLimitEnable); |
if (smc_result != PPSMC_Result_OK) { |
ret = -EINVAL; |
} else { |
struct radeon_cac_tdp_table *cac_tdp_table = |
rdev->pm.dpm.dyn_state.cac_tdp_table; |
u32 default_pwr_limit = |
(u32)(cac_tdp_table->maximum_power_delivery_limit * 256); |
pi->power_containment_features |= POWERCONTAINMENT_FEATURE_PkgPwrLimit; |
ci_set_power_limit(rdev, default_pwr_limit); |
} |
} |
} |
} else { |
if (pi->caps_power_containment && pi->power_containment_features) { |
if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_TDCLimit) |
ci_send_msg_to_smc(rdev, PPSMC_MSG_TDCLimitDisable); |
if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM) |
ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableDTE); |
if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit) |
ci_send_msg_to_smc(rdev, PPSMC_MSG_PkgPwrLimitDisable); |
pi->power_containment_features = 0; |
} |
} |
return ret; |
} |
static int ci_enable_smc_cac(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
int ret = 0; |
if (pi->caps_cac) { |
if (enable) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac); |
if (smc_result != PPSMC_Result_OK) { |
ret = -EINVAL; |
pi->cac_enabled = false; |
} else { |
pi->cac_enabled = true; |
} |
} else if (pi->cac_enabled) { |
ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac); |
pi->cac_enabled = false; |
} |
} |
return ret; |
} |
static int ci_power_control_set_level(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_cac_tdp_table *cac_tdp_table = |
rdev->pm.dpm.dyn_state.cac_tdp_table; |
s32 adjust_percent; |
s32 target_tdp; |
int ret = 0; |
bool adjust_polarity = false; /* ??? */ |
if (pi->caps_power_containment && |
(pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM)) { |
adjust_percent = adjust_polarity ? |
rdev->pm.dpm.tdp_adjustment : (-1 * rdev->pm.dpm.tdp_adjustment); |
target_tdp = ((100 + adjust_percent) * |
(s32)cac_tdp_table->configurable_tdp) / 100; |
target_tdp *= 256; |
ret = ci_set_overdrive_target_tdp(rdev, (u32)target_tdp); |
} |
return ret; |
} |
void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (pi->uvd_power_gated == gate) |
return; |
pi->uvd_power_gated = gate; |
ci_update_uvd_dpm(rdev, gate); |
} |
bool ci_dpm_vblank_too_short(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 vblank_time = r600_dpm_get_vblank_time(rdev); |
u32 switch_limit = pi->mem_gddr5 ? 450 : 300; |
if (vblank_time < switch_limit) |
return true; |
else |
return false; |
} |
static void ci_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct ci_ps *ps = ci_get_ps(rps); |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_clock_and_voltage_limits *max_limits; |
bool disable_mclk_switching; |
u32 sclk, mclk; |
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; |
else |
disable_mclk_switching = false; |
if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) |
pi->battery_state = true; |
else |
pi->battery_state = false; |
if (rdev->pm.dpm.ac_power) |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
else |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc; |
if (rdev->pm.dpm.ac_power == false) { |
for (i = 0; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].mclk > max_limits->mclk) |
ps->performance_levels[i].mclk = max_limits->mclk; |
if (ps->performance_levels[i].sclk > max_limits->sclk) |
ps->performance_levels[i].sclk = max_limits->sclk; |
} |
} |
/* limit clocks to max supported clocks based on voltage dependency tables */ |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
&max_sclk_vddc); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
&max_mclk_vddci); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
&max_mclk_vddc); |
for (i = 0; i < ps->performance_level_count; i++) { |
if (max_sclk_vddc) { |
if (ps->performance_levels[i].sclk > max_sclk_vddc) |
ps->performance_levels[i].sclk = max_sclk_vddc; |
} |
if (max_mclk_vddci) { |
if (ps->performance_levels[i].mclk > max_mclk_vddci) |
ps->performance_levels[i].mclk = max_mclk_vddci; |
} |
if (max_mclk_vddc) { |
if (ps->performance_levels[i].mclk > max_mclk_vddc) |
ps->performance_levels[i].mclk = max_mclk_vddc; |
} |
} |
/* XXX validate the min clocks required for display */ |
if (disable_mclk_switching) { |
mclk = ps->performance_levels[ps->performance_level_count - 1].mclk; |
sclk = ps->performance_levels[0].sclk; |
} else { |
mclk = ps->performance_levels[0].mclk; |
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; |
if (ps->performance_levels[1].sclk < ps->performance_levels[0].sclk) |
ps->performance_levels[1].sclk = ps->performance_levels[0].sclk; |
if (disable_mclk_switching) { |
if (ps->performance_levels[0].mclk < ps->performance_levels[1].mclk) |
ps->performance_levels[0].mclk = ps->performance_levels[1].mclk; |
} else { |
if (ps->performance_levels[1].mclk < ps->performance_levels[0].mclk) |
ps->performance_levels[1].mclk = ps->performance_levels[0].mclk; |
} |
} |
static int ci_set_thermal_temperature_range(struct radeon_device *rdev, |
int min_temp, int max_temp) |
{ |
int low_temp = 0 * 1000; |
int high_temp = 255 * 1000; |
u32 tmp; |
if (low_temp < min_temp) |
low_temp = min_temp; |
if (high_temp > max_temp) |
high_temp = max_temp; |
if (high_temp < low_temp) { |
DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); |
return -EINVAL; |
} |
tmp = RREG32_SMC(CG_THERMAL_INT); |
tmp &= ~(CI_DIG_THERM_INTH_MASK | CI_DIG_THERM_INTL_MASK); |
tmp |= CI_DIG_THERM_INTH(high_temp / 1000) | |
CI_DIG_THERM_INTL(low_temp / 1000); |
WREG32_SMC(CG_THERMAL_INT, tmp); |
#if 0 |
/* XXX: need to figure out how to handle this properly */ |
tmp = RREG32_SMC(CG_THERMAL_CTRL); |
tmp &= DIG_THERM_DPM_MASK; |
tmp |= DIG_THERM_DPM(high_temp / 1000); |
WREG32_SMC(CG_THERMAL_CTRL, tmp); |
#endif |
rdev->pm.dpm.thermal.min_temp = low_temp; |
rdev->pm.dpm.thermal.max_temp = high_temp; |
return 0; |
} |
#if 0 |
static int ci_read_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 *value) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
return ci_read_smc_sram_dword(rdev, |
pi->soft_regs_start + reg_offset, |
value, pi->sram_end); |
} |
#endif |
static int ci_write_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 value) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
return ci_write_smc_sram_dword(rdev, |
pi->soft_regs_start + reg_offset, |
value, pi->sram_end); |
} |
static void ci_init_fps_limits(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
SMU7_Discrete_DpmTable *table = &pi->smc_state_table; |
if (pi->caps_fps) { |
u16 tmp; |
tmp = 45; |
table->FpsHighT = cpu_to_be16(tmp); |
tmp = 30; |
table->FpsLowT = cpu_to_be16(tmp); |
} |
} |
static int ci_update_sclk_t(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int ret = 0; |
u32 low_sclk_interrupt_t = 0; |
if (pi->caps_sclk_throttle_low_notification) { |
low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t); |
ret = ci_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Discrete_DpmTable, LowSclkInterruptT), |
(u8 *)&low_sclk_interrupt_t, |
sizeof(u32), pi->sram_end); |
} |
return ret; |
} |
static void ci_get_leakage_voltages(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u16 leakage_id, virtual_voltage_id; |
u16 vddc, vddci; |
int i; |
pi->vddc_leakage.count = 0; |
pi->vddci_leakage.count = 0; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) { |
for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) { |
virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i; |
if (radeon_atom_get_voltage_evv(rdev, virtual_voltage_id, &vddc) != 0) |
continue; |
if (vddc != 0 && vddc != virtual_voltage_id) { |
pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc; |
pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id; |
pi->vddc_leakage.count++; |
} |
} |
} else if (radeon_atom_get_leakage_id_from_vbios(rdev, &leakage_id) == 0) { |
for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) { |
virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i; |
if (radeon_atom_get_leakage_vddc_based_on_leakage_params(rdev, &vddc, &vddci, |
virtual_voltage_id, |
leakage_id) == 0) { |
if (vddc != 0 && vddc != virtual_voltage_id) { |
pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc; |
pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id; |
pi->vddc_leakage.count++; |
} |
if (vddci != 0 && vddci != virtual_voltage_id) { |
pi->vddci_leakage.actual_voltage[pi->vddci_leakage.count] = vddci; |
pi->vddci_leakage.leakage_id[pi->vddci_leakage.count] = virtual_voltage_id; |
pi->vddci_leakage.count++; |
} |
} |
} |
} |
} |
static void ci_set_dpm_event_sources(struct radeon_device *rdev, u32 sources) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
bool want_thermal_protection; |
enum radeon_dpm_event_src dpm_event_src; |
u32 tmp; |
switch (sources) { |
case 0: |
default: |
want_thermal_protection = false; |
break; |
case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL; |
break; |
case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL; |
break; |
case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) | |
(1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL; |
break; |
} |
if (want_thermal_protection) { |
#if 0 |
/* XXX: need to figure out how to handle this properly */ |
tmp = RREG32_SMC(CG_THERMAL_CTRL); |
tmp &= DPM_EVENT_SRC_MASK; |
tmp |= DPM_EVENT_SRC(dpm_event_src); |
WREG32_SMC(CG_THERMAL_CTRL, tmp); |
#endif |
tmp = RREG32_SMC(GENERAL_PWRMGT); |
if (pi->thermal_protection) |
tmp &= ~THERMAL_PROTECTION_DIS; |
else |
tmp |= THERMAL_PROTECTION_DIS; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
} else { |
tmp = RREG32_SMC(GENERAL_PWRMGT); |
tmp |= THERMAL_PROTECTION_DIS; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
} |
} |
static void ci_enable_auto_throttle_source(struct radeon_device *rdev, |
enum radeon_dpm_auto_throttle_src source, |
bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (enable) { |
if (!(pi->active_auto_throttle_sources & (1 << source))) { |
pi->active_auto_throttle_sources |= 1 << source; |
ci_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); |
} |
} else { |
if (pi->active_auto_throttle_sources & (1 << source)) { |
pi->active_auto_throttle_sources &= ~(1 << source); |
ci_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); |
} |
} |
} |
static void ci_enable_vr_hot_gpio_interrupt(struct radeon_device *rdev) |
{ |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT) |
ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableVRHotGPIOInterrupt); |
} |
static int ci_unfreeze_sclk_mclk_dpm(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
if (!pi->need_update_smu7_dpm_table) |
return 0; |
if ((!pi->sclk_dpm_key_disabled) && |
(pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_SCLKDPM_UnfreezeLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
if ((!pi->mclk_dpm_key_disabled) && |
(pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_UnfreezeLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
pi->need_update_smu7_dpm_table = 0; |
return 0; |
} |
static int ci_enable_sclk_mclk_dpm(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
if (enable) { |
if (!pi->sclk_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DPM_Enable); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
if (!pi->mclk_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_Enable); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
WREG32_P(MC_SEQ_CNTL_3, CAC_EN, ~CAC_EN); |
WREG32_SMC(LCAC_MC0_CNTL, 0x05); |
WREG32_SMC(LCAC_MC1_CNTL, 0x05); |
WREG32_SMC(LCAC_CPL_CNTL, 0x100005); |
udelay(10); |
WREG32_SMC(LCAC_MC0_CNTL, 0x400005); |
WREG32_SMC(LCAC_MC1_CNTL, 0x400005); |
WREG32_SMC(LCAC_CPL_CNTL, 0x500005); |
} |
} else { |
if (!pi->sclk_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DPM_Disable); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
if (!pi->mclk_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_Disable); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
} |
return 0; |
} |
static int ci_start_dpm(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
int ret; |
u32 tmp; |
tmp = RREG32_SMC(GENERAL_PWRMGT); |
tmp |= GLOBAL_PWRMGT_EN; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
tmp = RREG32_SMC(SCLK_PWRMGT_CNTL); |
tmp |= DYNAMIC_PM_EN; |
WREG32_SMC(SCLK_PWRMGT_CNTL, tmp); |
ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, VoltageChangeTimeout), 0x1000); |
WREG32_P(BIF_LNCNT_RESET, 0, ~RESET_LNCNT_EN); |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Voltage_Cntl_Enable); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
ret = ci_enable_sclk_mclk_dpm(rdev, true); |
if (ret) |
return ret; |
if (!pi->pcie_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_Enable); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
return 0; |
} |
static int ci_freeze_sclk_mclk_dpm(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
if (!pi->need_update_smu7_dpm_table) |
return 0; |
if ((!pi->sclk_dpm_key_disabled) && |
(pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_SCLKDPM_FreezeLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
if ((!pi->mclk_dpm_key_disabled) && |
(pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_FreezeLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
return 0; |
} |
static int ci_stop_dpm(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
int ret; |
u32 tmp; |
tmp = RREG32_SMC(GENERAL_PWRMGT); |
tmp &= ~GLOBAL_PWRMGT_EN; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
tmp = RREG32_SMC(SCLK_PWRMGT_CNTL); |
tmp &= ~DYNAMIC_PM_EN; |
WREG32_SMC(SCLK_PWRMGT_CNTL, tmp); |
if (!pi->pcie_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_Disable); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
ret = ci_enable_sclk_mclk_dpm(rdev, false); |
if (ret) |
return ret; |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Voltage_Cntl_Disable); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
static void ci_enable_sclk_control(struct radeon_device *rdev, bool enable) |
{ |
u32 tmp = RREG32_SMC(SCLK_PWRMGT_CNTL); |
if (enable) |
tmp &= ~SCLK_PWRMGT_OFF; |
else |
tmp |= SCLK_PWRMGT_OFF; |
WREG32_SMC(SCLK_PWRMGT_CNTL, tmp); |
} |
#if 0 |
static int ci_notify_hw_of_power_source(struct radeon_device *rdev, |
bool ac_power) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_cac_tdp_table *cac_tdp_table = |
rdev->pm.dpm.dyn_state.cac_tdp_table; |
u32 power_limit; |
if (ac_power) |
power_limit = (u32)(cac_tdp_table->maximum_power_delivery_limit * 256); |
else |
power_limit = (u32)(cac_tdp_table->battery_power_limit * 256); |
ci_set_power_limit(rdev, power_limit); |
if (pi->caps_automatic_dc_transition) { |
if (ac_power) |
ci_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC); |
else |
ci_send_msg_to_smc(rdev, PPSMC_MSG_Remove_DC_Clamp); |
} |
return 0; |
} |
#endif |
static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev, |
PPSMC_Msg msg, u32 parameter) |
{ |
WREG32(SMC_MSG_ARG_0, parameter); |
return ci_send_msg_to_smc(rdev, msg); |
} |
static PPSMC_Result ci_send_msg_to_smc_return_parameter(struct radeon_device *rdev, |
PPSMC_Msg msg, u32 *parameter) |
{ |
PPSMC_Result smc_result; |
smc_result = ci_send_msg_to_smc(rdev, msg); |
if ((smc_result == PPSMC_Result_OK) && parameter) |
*parameter = RREG32(SMC_MSG_ARG_0); |
return smc_result; |
} |
static int ci_dpm_force_state_sclk(struct radeon_device *rdev, u32 n) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (!pi->sclk_dpm_key_disabled) { |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, n); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
return 0; |
} |
static int ci_dpm_force_state_mclk(struct radeon_device *rdev, u32 n) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (!pi->mclk_dpm_key_disabled) { |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_ForceState, n); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
return 0; |
} |
static int ci_dpm_force_state_pcie(struct radeon_device *rdev, u32 n) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (!pi->pcie_dpm_key_disabled) { |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_PCIeDPM_ForceLevel, n); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
return 0; |
} |
static int ci_set_power_limit(struct radeon_device *rdev, u32 n) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit) { |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_PkgPwrSetLimit, n); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
return 0; |
} |
static int ci_set_overdrive_target_tdp(struct radeon_device *rdev, |
u32 target_tdp) |
{ |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_OverDriveSetTargetTdp, target_tdp); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
static int ci_set_boot_state(struct radeon_device *rdev) |
{ |
return ci_enable_sclk_mclk_dpm(rdev, false); |
} |
static u32 ci_get_average_sclk_freq(struct radeon_device *rdev) |
{ |
u32 sclk_freq; |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_return_parameter(rdev, |
PPSMC_MSG_API_GetSclkFrequency, |
&sclk_freq); |
if (smc_result != PPSMC_Result_OK) |
sclk_freq = 0; |
return sclk_freq; |
} |
static u32 ci_get_average_mclk_freq(struct radeon_device *rdev) |
{ |
u32 mclk_freq; |
PPSMC_Result smc_result = |
ci_send_msg_to_smc_return_parameter(rdev, |
PPSMC_MSG_API_GetMclkFrequency, |
&mclk_freq); |
if (smc_result != PPSMC_Result_OK) |
mclk_freq = 0; |
return mclk_freq; |
} |
static void ci_dpm_start_smc(struct radeon_device *rdev) |
{ |
int i; |
ci_program_jump_on_start(rdev); |
ci_start_smc_clock(rdev); |
ci_start_smc(rdev); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32_SMC(FIRMWARE_FLAGS) & INTERRUPTS_ENABLED) |
break; |
} |
} |
static void ci_dpm_stop_smc(struct radeon_device *rdev) |
{ |
ci_reset_smc(rdev); |
ci_stop_smc_clock(rdev); |
} |
static int ci_process_firmware_header(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = ci_read_smc_sram_dword(rdev, |
SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, DpmTable), |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->dpm_table_start = tmp; |
ret = ci_read_smc_sram_dword(rdev, |
SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, SoftRegisters), |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->soft_regs_start = tmp; |
ret = ci_read_smc_sram_dword(rdev, |
SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, mcRegisterTable), |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->mc_reg_table_start = tmp; |
ret = ci_read_smc_sram_dword(rdev, |
SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, FanTable), |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->fan_table_start = tmp; |
ret = ci_read_smc_sram_dword(rdev, |
SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, mcArbDramTimingTable), |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->arb_table_start = tmp; |
return 0; |
} |
static void ci_read_clock_registers(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
pi->clock_registers.cg_spll_func_cntl = |
RREG32_SMC(CG_SPLL_FUNC_CNTL); |
pi->clock_registers.cg_spll_func_cntl_2 = |
RREG32_SMC(CG_SPLL_FUNC_CNTL_2); |
pi->clock_registers.cg_spll_func_cntl_3 = |
RREG32_SMC(CG_SPLL_FUNC_CNTL_3); |
pi->clock_registers.cg_spll_func_cntl_4 = |
RREG32_SMC(CG_SPLL_FUNC_CNTL_4); |
pi->clock_registers.cg_spll_spread_spectrum = |
RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM); |
pi->clock_registers.cg_spll_spread_spectrum_2 = |
RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM_2); |
pi->clock_registers.dll_cntl = RREG32(DLL_CNTL); |
pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL); |
pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL); |
pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL); |
pi->clock_registers.mpll_func_cntl = RREG32(MPLL_FUNC_CNTL); |
pi->clock_registers.mpll_func_cntl_1 = RREG32(MPLL_FUNC_CNTL_1); |
pi->clock_registers.mpll_func_cntl_2 = RREG32(MPLL_FUNC_CNTL_2); |
pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1); |
pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2); |
} |
static void ci_init_sclk_t(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
pi->low_sclk_interrupt_t = 0; |
} |
static void ci_enable_thermal_protection(struct radeon_device *rdev, |
bool enable) |
{ |
u32 tmp = RREG32_SMC(GENERAL_PWRMGT); |
if (enable) |
tmp &= ~THERMAL_PROTECTION_DIS; |
else |
tmp |= THERMAL_PROTECTION_DIS; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
} |
static void ci_enable_acpi_power_management(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(GENERAL_PWRMGT); |
tmp |= STATIC_PM_EN; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
} |
#if 0 |
static int ci_enter_ulp_state(struct radeon_device *rdev) |
{ |
WREG32(SMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower); |
udelay(25000); |
return 0; |
} |
static int ci_exit_ulp_state(struct radeon_device *rdev) |
{ |
int i; |
WREG32(SMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower); |
udelay(7000); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(SMC_RESP_0) == 1) |
break; |
udelay(1000); |
} |
return 0; |
} |
#endif |
static int ci_notify_smc_display_change(struct radeon_device *rdev, |
bool has_display) |
{ |
PPSMC_Msg msg = has_display ? PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay; |
return (ci_send_msg_to_smc(rdev, msg) == PPSMC_Result_OK) ? 0 : -EINVAL; |
} |
static int ci_enable_ds_master_switch(struct radeon_device *rdev, |
bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (enable) { |
if (pi->caps_sclk_ds) { |
if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_ON) != PPSMC_Result_OK) |
return -EINVAL; |
} else { |
if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK) |
return -EINVAL; |
} |
} else { |
if (pi->caps_sclk_ds) { |
if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK) |
return -EINVAL; |
} |
} |
return 0; |
} |
static void ci_program_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(CG_DISPLAY_GAP_CNTL); |
u32 pre_vbi_time_in_us; |
u32 frame_time_in_us; |
u32 ref_clock = rdev->clock.spll.reference_freq; |
u32 refresh_rate = r600_dpm_get_vrefresh(rdev); |
u32 vblank_time = r600_dpm_get_vblank_time(rdev); |
tmp &= ~DISP_GAP_MASK; |
if (rdev->pm.dpm.new_active_crtc_count > 0) |
tmp |= DISP_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); |
else |
tmp |= DISP_GAP(R600_PM_DISPLAY_GAP_IGNORE); |
WREG32_SMC(CG_DISPLAY_GAP_CNTL, tmp); |
if (refresh_rate == 0) |
refresh_rate = 60; |
if (vblank_time == 0xffffffff) |
vblank_time = 500; |
frame_time_in_us = 1000000 / refresh_rate; |
pre_vbi_time_in_us = |
frame_time_in_us - 200 - vblank_time; |
tmp = pre_vbi_time_in_us * (ref_clock / 100); |
WREG32_SMC(CG_DISPLAY_GAP_CNTL2, tmp); |
ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, PreVBlankGap), 0x64); |
ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us)); |
ci_notify_smc_display_change(rdev, (rdev->pm.dpm.new_active_crtc_count == 1)); |
} |
static void ci_enable_spread_spectrum(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 tmp; |
if (enable) { |
if (pi->caps_sclk_ss_support) { |
tmp = RREG32_SMC(GENERAL_PWRMGT); |
tmp |= DYN_SPREAD_SPECTRUM_EN; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
} |
} else { |
tmp = RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM); |
tmp &= ~SSEN; |
WREG32_SMC(CG_SPLL_SPREAD_SPECTRUM, tmp); |
tmp = RREG32_SMC(GENERAL_PWRMGT); |
tmp &= ~DYN_SPREAD_SPECTRUM_EN; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
} |
} |
static void ci_program_sstp(struct radeon_device *rdev) |
{ |
WREG32_SMC(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT))); |
} |
static void ci_enable_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(CG_DISPLAY_GAP_CNTL); |
tmp &= ~(DISP_GAP_MASK | DISP_GAP_MCHG_MASK); |
tmp |= (DISP_GAP(R600_PM_DISPLAY_GAP_IGNORE) | |
DISP_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK)); |
WREG32_SMC(CG_DISPLAY_GAP_CNTL, tmp); |
} |
static void ci_program_vc(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_SMC(SCLK_PWRMGT_CNTL); |
tmp &= ~(RESET_SCLK_CNT | RESET_BUSY_CNT); |
WREG32_SMC(SCLK_PWRMGT_CNTL, tmp); |
WREG32_SMC(CG_FTV_0, CISLANDS_VRC_DFLT0); |
WREG32_SMC(CG_FTV_1, CISLANDS_VRC_DFLT1); |
WREG32_SMC(CG_FTV_2, CISLANDS_VRC_DFLT2); |
WREG32_SMC(CG_FTV_3, CISLANDS_VRC_DFLT3); |
WREG32_SMC(CG_FTV_4, CISLANDS_VRC_DFLT4); |
WREG32_SMC(CG_FTV_5, CISLANDS_VRC_DFLT5); |
WREG32_SMC(CG_FTV_6, CISLANDS_VRC_DFLT6); |
WREG32_SMC(CG_FTV_7, CISLANDS_VRC_DFLT7); |
} |
static void ci_clear_vc(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_SMC(SCLK_PWRMGT_CNTL); |
tmp |= (RESET_SCLK_CNT | RESET_BUSY_CNT); |
WREG32_SMC(SCLK_PWRMGT_CNTL, tmp); |
WREG32_SMC(CG_FTV_0, 0); |
WREG32_SMC(CG_FTV_1, 0); |
WREG32_SMC(CG_FTV_2, 0); |
WREG32_SMC(CG_FTV_3, 0); |
WREG32_SMC(CG_FTV_4, 0); |
WREG32_SMC(CG_FTV_5, 0); |
WREG32_SMC(CG_FTV_6, 0); |
WREG32_SMC(CG_FTV_7, 0); |
} |
static int ci_upload_firmware(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int i, ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32_SMC(RCU_UC_EVENTS) & BOOT_SEQ_DONE) |
break; |
} |
WREG32_SMC(SMC_SYSCON_MISC_CNTL, 1); |
ci_stop_smc_clock(rdev); |
ci_reset_smc(rdev); |
ret = ci_load_smc_ucode(rdev, pi->sram_end); |
return ret; |
} |
static int ci_get_svi2_voltage_table(struct radeon_device *rdev, |
struct radeon_clock_voltage_dependency_table *voltage_dependency_table, |
struct atom_voltage_table *voltage_table) |
{ |
u32 i; |
if (voltage_dependency_table == NULL) |
return -EINVAL; |
voltage_table->mask_low = 0; |
voltage_table->phase_delay = 0; |
voltage_table->count = voltage_dependency_table->count; |
for (i = 0; i < voltage_table->count; i++) { |
voltage_table->entries[i].value = voltage_dependency_table->entries[i].v; |
voltage_table->entries[i].smio_low = 0; |
} |
return 0; |
} |
static int ci_construct_voltage_tables(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int ret; |
if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) { |
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC, |
VOLTAGE_OBJ_GPIO_LUT, |
&pi->vddc_voltage_table); |
if (ret) |
return ret; |
} else if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) { |
ret = ci_get_svi2_voltage_table(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
&pi->vddc_voltage_table); |
if (ret) |
return ret; |
} |
if (pi->vddc_voltage_table.count > SMU7_MAX_LEVELS_VDDC) |
si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_VDDC, |
&pi->vddc_voltage_table); |
if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) { |
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDCI, |
VOLTAGE_OBJ_GPIO_LUT, |
&pi->vddci_voltage_table); |
if (ret) |
return ret; |
} else if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) { |
ret = ci_get_svi2_voltage_table(rdev, |
&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
&pi->vddci_voltage_table); |
if (ret) |
return ret; |
} |
if (pi->vddci_voltage_table.count > SMU7_MAX_LEVELS_VDDCI) |
si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_VDDCI, |
&pi->vddci_voltage_table); |
if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) { |
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_MVDDC, |
VOLTAGE_OBJ_GPIO_LUT, |
&pi->mvdd_voltage_table); |
if (ret) |
return ret; |
} else if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) { |
ret = ci_get_svi2_voltage_table(rdev, |
&rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk, |
&pi->mvdd_voltage_table); |
if (ret) |
return ret; |
} |
if (pi->mvdd_voltage_table.count > SMU7_MAX_LEVELS_MVDD) |
si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_MVDD, |
&pi->mvdd_voltage_table); |
return 0; |
} |
static void ci_populate_smc_voltage_table(struct radeon_device *rdev, |
struct atom_voltage_table_entry *voltage_table, |
SMU7_Discrete_VoltageLevel *smc_voltage_table) |
{ |
int ret; |
ret = ci_get_std_voltage_value_sidd(rdev, voltage_table, |
&smc_voltage_table->StdVoltageHiSidd, |
&smc_voltage_table->StdVoltageLoSidd); |
if (ret) { |
smc_voltage_table->StdVoltageHiSidd = voltage_table->value * VOLTAGE_SCALE; |
smc_voltage_table->StdVoltageLoSidd = voltage_table->value * VOLTAGE_SCALE; |
} |
smc_voltage_table->Voltage = cpu_to_be16(voltage_table->value * VOLTAGE_SCALE); |
smc_voltage_table->StdVoltageHiSidd = |
cpu_to_be16(smc_voltage_table->StdVoltageHiSidd); |
smc_voltage_table->StdVoltageLoSidd = |
cpu_to_be16(smc_voltage_table->StdVoltageLoSidd); |
} |
static int ci_populate_smc_vddc_table(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
unsigned int count; |
table->VddcLevelCount = pi->vddc_voltage_table.count; |
for (count = 0; count < table->VddcLevelCount; count++) { |
ci_populate_smc_voltage_table(rdev, |
&pi->vddc_voltage_table.entries[count], |
&table->VddcLevel[count]); |
if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) |
table->VddcLevel[count].Smio |= |
pi->vddc_voltage_table.entries[count].smio_low; |
else |
table->VddcLevel[count].Smio = 0; |
} |
table->VddcLevelCount = cpu_to_be32(table->VddcLevelCount); |
return 0; |
} |
static int ci_populate_smc_vddci_table(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
unsigned int count; |
struct ci_power_info *pi = ci_get_pi(rdev); |
table->VddciLevelCount = pi->vddci_voltage_table.count; |
for (count = 0; count < table->VddciLevelCount; count++) { |
ci_populate_smc_voltage_table(rdev, |
&pi->vddci_voltage_table.entries[count], |
&table->VddciLevel[count]); |
if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) |
table->VddciLevel[count].Smio |= |
pi->vddci_voltage_table.entries[count].smio_low; |
else |
table->VddciLevel[count].Smio = 0; |
} |
table->VddciLevelCount = cpu_to_be32(table->VddciLevelCount); |
return 0; |
} |
static int ci_populate_smc_mvdd_table(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
unsigned int count; |
table->MvddLevelCount = pi->mvdd_voltage_table.count; |
for (count = 0; count < table->MvddLevelCount; count++) { |
ci_populate_smc_voltage_table(rdev, |
&pi->mvdd_voltage_table.entries[count], |
&table->MvddLevel[count]); |
if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) |
table->MvddLevel[count].Smio |= |
pi->mvdd_voltage_table.entries[count].smio_low; |
else |
table->MvddLevel[count].Smio = 0; |
} |
table->MvddLevelCount = cpu_to_be32(table->MvddLevelCount); |
return 0; |
} |
static int ci_populate_smc_voltage_tables(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
int ret; |
ret = ci_populate_smc_vddc_table(rdev, table); |
if (ret) |
return ret; |
ret = ci_populate_smc_vddci_table(rdev, table); |
if (ret) |
return ret; |
ret = ci_populate_smc_mvdd_table(rdev, table); |
if (ret) |
return ret; |
return 0; |
} |
static int ci_populate_mvdd_value(struct radeon_device *rdev, u32 mclk, |
SMU7_Discrete_VoltageLevel *voltage) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 i = 0; |
if (pi->mvdd_control != CISLANDS_VOLTAGE_CONTROL_NONE) { |
for (i = 0; i < rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count; i++) { |
if (mclk <= rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries[i].clk) { |
voltage->Voltage = pi->mvdd_voltage_table.entries[i].value; |
break; |
} |
} |
if (i >= rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count) |
return -EINVAL; |
} |
return -EINVAL; |
} |
static int ci_get_std_voltage_value_sidd(struct radeon_device *rdev, |
struct atom_voltage_table_entry *voltage_table, |
u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd) |
{ |
u16 v_index, idx; |
bool voltage_found = false; |
*std_voltage_hi_sidd = voltage_table->value * VOLTAGE_SCALE; |
*std_voltage_lo_sidd = voltage_table->value * VOLTAGE_SCALE; |
if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL) |
return -EINVAL; |
if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries) { |
for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) { |
if (voltage_table->value == |
rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) { |
voltage_found = true; |
if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count) |
idx = v_index; |
else |
idx = rdev->pm.dpm.dyn_state.cac_leakage_table.count - 1; |
*std_voltage_lo_sidd = |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE; |
*std_voltage_hi_sidd = |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE; |
break; |
} |
} |
if (!voltage_found) { |
for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) { |
if (voltage_table->value <= |
rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) { |
voltage_found = true; |
if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count) |
idx = v_index; |
else |
idx = rdev->pm.dpm.dyn_state.cac_leakage_table.count - 1; |
*std_voltage_lo_sidd = |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE; |
*std_voltage_hi_sidd = |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE; |
break; |
} |
} |
} |
} |
return 0; |
} |
static void ci_populate_phase_value_based_on_sclk(struct radeon_device *rdev, |
const struct radeon_phase_shedding_limits_table *limits, |
u32 sclk, |
u32 *phase_shedding) |
{ |
unsigned int i; |
*phase_shedding = 1; |
for (i = 0; i < limits->count; i++) { |
if (sclk < limits->entries[i].sclk) { |
*phase_shedding = i; |
break; |
} |
} |
} |
static void ci_populate_phase_value_based_on_mclk(struct radeon_device *rdev, |
const struct radeon_phase_shedding_limits_table *limits, |
u32 mclk, |
u32 *phase_shedding) |
{ |
unsigned int i; |
*phase_shedding = 1; |
for (i = 0; i < limits->count; i++) { |
if (mclk < limits->entries[i].mclk) { |
*phase_shedding = i; |
break; |
} |
} |
} |
static int ci_init_arb_table_index(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = ci_read_smc_sram_dword(rdev, pi->arb_table_start, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
tmp &= 0x00FFFFFF; |
tmp |= MC_CG_ARB_FREQ_F1 << 24; |
return ci_write_smc_sram_dword(rdev, pi->arb_table_start, |
tmp, pi->sram_end); |
} |
static int ci_get_dependency_volt_by_clk(struct radeon_device *rdev, |
struct radeon_clock_voltage_dependency_table *allowed_clock_voltage_table, |
u32 clock, u32 *voltage) |
{ |
u32 i = 0; |
if (allowed_clock_voltage_table->count == 0) |
return -EINVAL; |
for (i = 0; i < allowed_clock_voltage_table->count; i++) { |
if (allowed_clock_voltage_table->entries[i].clk >= clock) { |
*voltage = allowed_clock_voltage_table->entries[i].v; |
return 0; |
} |
} |
*voltage = allowed_clock_voltage_table->entries[i-1].v; |
return 0; |
} |
static u8 ci_get_sleep_divider_id_from_clock(struct radeon_device *rdev, |
u32 sclk, u32 min_sclk_in_sr) |
{ |
u32 i; |
u32 tmp; |
u32 min = (min_sclk_in_sr > CISLAND_MINIMUM_ENGINE_CLOCK) ? |
min_sclk_in_sr : CISLAND_MINIMUM_ENGINE_CLOCK; |
if (sclk < min) |
return 0; |
for (i = CISLAND_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) { |
tmp = sclk / (1 << i); |
if (tmp >= min || i == 0) |
break; |
} |
return (u8)i; |
} |
static int ci_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev) |
{ |
return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1); |
} |
static int ci_reset_to_default(struct radeon_device *rdev) |
{ |
return (ci_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static int ci_force_switch_to_arb_f0(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = (RREG32_SMC(SMC_SCRATCH9) & 0x0000ff00) >> 8; |
if (tmp == MC_CG_ARB_FREQ_F0) |
return 0; |
return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0); |
} |
static int ci_populate_memory_timing_parameters(struct radeon_device *rdev, |
u32 sclk, |
u32 mclk, |
SMU7_Discrete_MCArbDramTimingTableEntry *arb_regs) |
{ |
u32 dram_timing; |
u32 dram_timing2; |
u32 burst_time; |
radeon_atom_set_engine_dram_timings(rdev, sclk, mclk); |
dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK; |
arb_regs->McArbDramTiming = cpu_to_be32(dram_timing); |
arb_regs->McArbDramTiming2 = cpu_to_be32(dram_timing2); |
arb_regs->McArbBurstTime = (u8)burst_time; |
return 0; |
} |
static int ci_do_program_memory_timing_parameters(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
SMU7_Discrete_MCArbDramTimingTable arb_regs; |
u32 i, j; |
int ret = 0; |
memset(&arb_regs, 0, sizeof(SMU7_Discrete_MCArbDramTimingTable)); |
for (i = 0; i < pi->dpm_table.sclk_table.count; i++) { |
for (j = 0; j < pi->dpm_table.mclk_table.count; j++) { |
ret = ci_populate_memory_timing_parameters(rdev, |
pi->dpm_table.sclk_table.dpm_levels[i].value, |
pi->dpm_table.mclk_table.dpm_levels[j].value, |
&arb_regs.entries[i][j]); |
if (ret) |
break; |
} |
} |
if (ret == 0) |
ret = ci_copy_bytes_to_smc(rdev, |
pi->arb_table_start, |
(u8 *)&arb_regs, |
sizeof(SMU7_Discrete_MCArbDramTimingTable), |
pi->sram_end); |
return ret; |
} |
static int ci_program_memory_timing_parameters(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (pi->need_update_smu7_dpm_table == 0) |
return 0; |
return ci_do_program_memory_timing_parameters(rdev); |
} |
static void ci_populate_smc_initial_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct ci_ps *boot_state = ci_get_ps(radeon_boot_state); |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 level = 0; |
for (level = 0; level < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; level++) { |
if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[level].clk >= |
boot_state->performance_levels[0].sclk) { |
pi->smc_state_table.GraphicsBootLevel = level; |
break; |
} |
} |
for (level = 0; level < rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.count; level++) { |
if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries[level].clk >= |
boot_state->performance_levels[0].mclk) { |
pi->smc_state_table.MemoryBootLevel = level; |
break; |
} |
} |
} |
static u32 ci_get_dpm_level_enable_mask_value(struct ci_single_dpm_table *dpm_table) |
{ |
u32 i; |
u32 mask_value = 0; |
for (i = dpm_table->count; i > 0; i--) { |
mask_value = mask_value << 1; |
if (dpm_table->dpm_levels[i-1].enabled) |
mask_value |= 0x1; |
else |
mask_value &= 0xFFFFFFFE; |
} |
return mask_value; |
} |
static void ci_populate_smc_link_level(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_dpm_table *dpm_table = &pi->dpm_table; |
u32 i; |
for (i = 0; i < dpm_table->pcie_speed_table.count; i++) { |
table->LinkLevel[i].PcieGenSpeed = |
(u8)dpm_table->pcie_speed_table.dpm_levels[i].value; |
table->LinkLevel[i].PcieLaneCount = |
r600_encode_pci_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1); |
table->LinkLevel[i].EnabledForActivity = 1; |
table->LinkLevel[i].DownT = cpu_to_be32(5); |
table->LinkLevel[i].UpT = cpu_to_be32(30); |
} |
pi->smc_state_table.LinkLevelCount = (u8)dpm_table->pcie_speed_table.count; |
pi->dpm_level_enable_mask.pcie_dpm_enable_mask = |
ci_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table); |
} |
static int ci_populate_smc_uvd_level(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
u32 count; |
struct atom_clock_dividers dividers; |
int ret = -EINVAL; |
table->UvdLevelCount = |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count; |
for (count = 0; count < table->UvdLevelCount; count++) { |
table->UvdLevel[count].VclkFrequency = |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].vclk; |
table->UvdLevel[count].DclkFrequency = |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].dclk; |
table->UvdLevel[count].MinVddc = |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE; |
table->UvdLevel[count].MinVddcPhases = 1; |
ret = radeon_atom_get_clock_dividers(rdev, |
COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, |
table->UvdLevel[count].VclkFrequency, false, ÷rs); |
if (ret) |
return ret; |
table->UvdLevel[count].VclkDivider = (u8)dividers.post_divider; |
ret = radeon_atom_get_clock_dividers(rdev, |
COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, |
table->UvdLevel[count].DclkFrequency, false, ÷rs); |
if (ret) |
return ret; |
table->UvdLevel[count].DclkDivider = (u8)dividers.post_divider; |
table->UvdLevel[count].VclkFrequency = cpu_to_be32(table->UvdLevel[count].VclkFrequency); |
table->UvdLevel[count].DclkFrequency = cpu_to_be32(table->UvdLevel[count].DclkFrequency); |
table->UvdLevel[count].MinVddc = cpu_to_be16(table->UvdLevel[count].MinVddc); |
} |
return ret; |
} |
static int ci_populate_smc_vce_level(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
u32 count; |
struct atom_clock_dividers dividers; |
int ret = -EINVAL; |
table->VceLevelCount = |
rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count; |
for (count = 0; count < table->VceLevelCount; count++) { |
table->VceLevel[count].Frequency = |
rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].evclk; |
table->VceLevel[count].MinVoltage = |
(u16)rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE; |
table->VceLevel[count].MinPhases = 1; |
ret = radeon_atom_get_clock_dividers(rdev, |
COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, |
table->VceLevel[count].Frequency, false, ÷rs); |
if (ret) |
return ret; |
table->VceLevel[count].Divider = (u8)dividers.post_divider; |
table->VceLevel[count].Frequency = cpu_to_be32(table->VceLevel[count].Frequency); |
table->VceLevel[count].MinVoltage = cpu_to_be16(table->VceLevel[count].MinVoltage); |
} |
return ret; |
} |
static int ci_populate_smc_acp_level(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
u32 count; |
struct atom_clock_dividers dividers; |
int ret = -EINVAL; |
table->AcpLevelCount = (u8) |
(rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count); |
for (count = 0; count < table->AcpLevelCount; count++) { |
table->AcpLevel[count].Frequency = |
rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].clk; |
table->AcpLevel[count].MinVoltage = |
rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].v; |
table->AcpLevel[count].MinPhases = 1; |
ret = radeon_atom_get_clock_dividers(rdev, |
COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, |
table->AcpLevel[count].Frequency, false, ÷rs); |
if (ret) |
return ret; |
table->AcpLevel[count].Divider = (u8)dividers.post_divider; |
table->AcpLevel[count].Frequency = cpu_to_be32(table->AcpLevel[count].Frequency); |
table->AcpLevel[count].MinVoltage = cpu_to_be16(table->AcpLevel[count].MinVoltage); |
} |
return ret; |
} |
static int ci_populate_smc_samu_level(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
u32 count; |
struct atom_clock_dividers dividers; |
int ret = -EINVAL; |
table->SamuLevelCount = |
rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count; |
for (count = 0; count < table->SamuLevelCount; count++) { |
table->SamuLevel[count].Frequency = |
rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].clk; |
table->SamuLevel[count].MinVoltage = |
rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE; |
table->SamuLevel[count].MinPhases = 1; |
ret = radeon_atom_get_clock_dividers(rdev, |
COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, |
table->SamuLevel[count].Frequency, false, ÷rs); |
if (ret) |
return ret; |
table->SamuLevel[count].Divider = (u8)dividers.post_divider; |
table->SamuLevel[count].Frequency = cpu_to_be32(table->SamuLevel[count].Frequency); |
table->SamuLevel[count].MinVoltage = cpu_to_be16(table->SamuLevel[count].MinVoltage); |
} |
return ret; |
} |
static int ci_calculate_mclk_params(struct radeon_device *rdev, |
u32 memory_clock, |
SMU7_Discrete_MemoryLevel *mclk, |
bool strobe_mode, |
bool dll_state_on) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 dll_cntl = pi->clock_registers.dll_cntl; |
u32 mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl; |
u32 mpll_ad_func_cntl = pi->clock_registers.mpll_ad_func_cntl; |
u32 mpll_dq_func_cntl = pi->clock_registers.mpll_dq_func_cntl; |
u32 mpll_func_cntl = pi->clock_registers.mpll_func_cntl; |
u32 mpll_func_cntl_1 = pi->clock_registers.mpll_func_cntl_1; |
u32 mpll_func_cntl_2 = pi->clock_registers.mpll_func_cntl_2; |
u32 mpll_ss1 = pi->clock_registers.mpll_ss1; |
u32 mpll_ss2 = pi->clock_registers.mpll_ss2; |
struct atom_mpll_param mpll_param; |
int ret; |
ret = radeon_atom_get_memory_pll_dividers(rdev, memory_clock, strobe_mode, &mpll_param); |
if (ret) |
return ret; |
mpll_func_cntl &= ~BWCTRL_MASK; |
mpll_func_cntl |= BWCTRL(mpll_param.bwcntl); |
mpll_func_cntl_1 &= ~(CLKF_MASK | CLKFRAC_MASK | VCO_MODE_MASK); |
mpll_func_cntl_1 |= CLKF(mpll_param.clkf) | |
CLKFRAC(mpll_param.clkfrac) | VCO_MODE(mpll_param.vco_mode); |
mpll_ad_func_cntl &= ~YCLK_POST_DIV_MASK; |
mpll_ad_func_cntl |= YCLK_POST_DIV(mpll_param.post_div); |
if (pi->mem_gddr5) { |
mpll_dq_func_cntl &= ~(YCLK_SEL_MASK | YCLK_POST_DIV_MASK); |
mpll_dq_func_cntl |= YCLK_SEL(mpll_param.yclk_sel) | |
YCLK_POST_DIV(mpll_param.post_div); |
} |
if (pi->caps_mclk_ss_support) { |
struct radeon_atom_ss ss; |
u32 freq_nom; |
u32 tmp; |
u32 reference_clock = rdev->clock.mpll.reference_freq; |
if (pi->mem_gddr5) |
freq_nom = memory_clock * 4; |
else |
freq_nom = memory_clock * 2; |
tmp = (freq_nom / reference_clock); |
tmp = tmp * tmp; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, freq_nom)) { |
u32 clks = reference_clock * 5 / ss.rate; |
u32 clkv = (u32)((((131 * ss.percentage * ss.rate) / 100) * tmp) / freq_nom); |
mpll_ss1 &= ~CLKV_MASK; |
mpll_ss1 |= CLKV(clkv); |
mpll_ss2 &= ~CLKS_MASK; |
mpll_ss2 |= CLKS(clks); |
} |
} |
mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK; |
mclk_pwrmgt_cntl |= DLL_SPEED(mpll_param.dll_speed); |
if (dll_state_on) |
mclk_pwrmgt_cntl |= MRDCK0_PDNB | MRDCK1_PDNB; |
else |
mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB); |
mclk->MclkFrequency = memory_clock; |
mclk->MpllFuncCntl = mpll_func_cntl; |
mclk->MpllFuncCntl_1 = mpll_func_cntl_1; |
mclk->MpllFuncCntl_2 = mpll_func_cntl_2; |
mclk->MpllAdFuncCntl = mpll_ad_func_cntl; |
mclk->MpllDqFuncCntl = mpll_dq_func_cntl; |
mclk->MclkPwrmgtCntl = mclk_pwrmgt_cntl; |
mclk->DllCntl = dll_cntl; |
mclk->MpllSs1 = mpll_ss1; |
mclk->MpllSs2 = mpll_ss2; |
return 0; |
} |
static int ci_populate_single_memory_level(struct radeon_device *rdev, |
u32 memory_clock, |
SMU7_Discrete_MemoryLevel *memory_level) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int ret; |
bool dll_state_on; |
if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries) { |
ret = ci_get_dependency_volt_by_clk(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
memory_clock, &memory_level->MinVddc); |
if (ret) |
return ret; |
} |
if (rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries) { |
ret = ci_get_dependency_volt_by_clk(rdev, |
&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
memory_clock, &memory_level->MinVddci); |
if (ret) |
return ret; |
} |
if (rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries) { |
ret = ci_get_dependency_volt_by_clk(rdev, |
&rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk, |
memory_clock, &memory_level->MinMvdd); |
if (ret) |
return ret; |
} |
memory_level->MinVddcPhases = 1; |
if (pi->vddc_phase_shed_control) |
ci_populate_phase_value_based_on_mclk(rdev, |
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table, |
memory_clock, |
&memory_level->MinVddcPhases); |
memory_level->EnabledForThrottle = 1; |
memory_level->EnabledForActivity = 1; |
memory_level->UpH = 0; |
memory_level->DownH = 100; |
memory_level->VoltageDownH = 0; |
memory_level->ActivityLevel = (u16)pi->mclk_activity_target; |
memory_level->StutterEnable = false; |
memory_level->StrobeEnable = false; |
memory_level->EdcReadEnable = false; |
memory_level->EdcWriteEnable = false; |
memory_level->RttEnable = false; |
memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; |
if (pi->mclk_stutter_mode_threshold && |
(memory_clock <= pi->mclk_stutter_mode_threshold) && |
(pi->uvd_enabled == false) && |
(RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) && |
(rdev->pm.dpm.new_active_crtc_count <= 2)) |
memory_level->StutterEnable = true; |
if (pi->mclk_strobe_mode_threshold && |
(memory_clock <= pi->mclk_strobe_mode_threshold)) |
memory_level->StrobeEnable = 1; |
if (pi->mem_gddr5) { |
memory_level->StrobeRatio = |
si_get_mclk_frequency_ratio(memory_clock, memory_level->StrobeEnable); |
if (pi->mclk_edc_enable_threshold && |
(memory_clock > pi->mclk_edc_enable_threshold)) |
memory_level->EdcReadEnable = true; |
if (pi->mclk_edc_wr_enable_threshold && |
(memory_clock > pi->mclk_edc_wr_enable_threshold)) |
memory_level->EdcWriteEnable = true; |
if (memory_level->StrobeEnable) { |
if (si_get_mclk_frequency_ratio(memory_clock, true) >= |
((RREG32(MC_SEQ_MISC7) >> 16) & 0xf)) |
dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false; |
else |
dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false; |
} else { |
dll_state_on = pi->dll_default_on; |
} |
} else { |
memory_level->StrobeRatio = si_get_ddr3_mclk_frequency_ratio(memory_clock); |
dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false; |
} |
ret = ci_calculate_mclk_params(rdev, memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on); |
if (ret) |
return ret; |
memory_level->MinVddc = cpu_to_be32(memory_level->MinVddc * VOLTAGE_SCALE); |
memory_level->MinVddcPhases = cpu_to_be32(memory_level->MinVddcPhases); |
memory_level->MinVddci = cpu_to_be32(memory_level->MinVddci * VOLTAGE_SCALE); |
memory_level->MinMvdd = cpu_to_be32(memory_level->MinMvdd * VOLTAGE_SCALE); |
memory_level->MclkFrequency = cpu_to_be32(memory_level->MclkFrequency); |
memory_level->ActivityLevel = cpu_to_be16(memory_level->ActivityLevel); |
memory_level->MpllFuncCntl = cpu_to_be32(memory_level->MpllFuncCntl); |
memory_level->MpllFuncCntl_1 = cpu_to_be32(memory_level->MpllFuncCntl_1); |
memory_level->MpllFuncCntl_2 = cpu_to_be32(memory_level->MpllFuncCntl_2); |
memory_level->MpllAdFuncCntl = cpu_to_be32(memory_level->MpllAdFuncCntl); |
memory_level->MpllDqFuncCntl = cpu_to_be32(memory_level->MpllDqFuncCntl); |
memory_level->MclkPwrmgtCntl = cpu_to_be32(memory_level->MclkPwrmgtCntl); |
memory_level->DllCntl = cpu_to_be32(memory_level->DllCntl); |
memory_level->MpllSs1 = cpu_to_be32(memory_level->MpllSs1); |
memory_level->MpllSs2 = cpu_to_be32(memory_level->MpllSs2); |
return 0; |
} |
static int ci_populate_smc_acpi_level(struct radeon_device *rdev, |
SMU7_Discrete_DpmTable *table) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct atom_clock_dividers dividers; |
SMU7_Discrete_VoltageLevel voltage_level; |
u32 spll_func_cntl = pi->clock_registers.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = pi->clock_registers.cg_spll_func_cntl_2; |
u32 dll_cntl = pi->clock_registers.dll_cntl; |
u32 mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl; |
int ret; |
table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC; |
if (pi->acpi_vddc) |
table->ACPILevel.MinVddc = cpu_to_be32(pi->acpi_vddc * VOLTAGE_SCALE); |
else |
table->ACPILevel.MinVddc = cpu_to_be32(pi->min_vddc_in_pp_table * VOLTAGE_SCALE); |
table->ACPILevel.MinVddcPhases = pi->vddc_phase_shed_control ? 0 : 1; |
table->ACPILevel.SclkFrequency = rdev->clock.spll.reference_freq; |
ret = radeon_atom_get_clock_dividers(rdev, |
COMPUTE_GPUCLK_INPUT_FLAG_SCLK, |
table->ACPILevel.SclkFrequency, false, ÷rs); |
if (ret) |
return ret; |
table->ACPILevel.SclkDid = (u8)dividers.post_divider; |
table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; |
table->ACPILevel.DeepSleepDivId = 0; |
spll_func_cntl &= ~SPLL_PWRON; |
spll_func_cntl |= SPLL_RESET; |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(4); |
table->ACPILevel.CgSpllFuncCntl = spll_func_cntl; |
table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2; |
table->ACPILevel.CgSpllFuncCntl3 = pi->clock_registers.cg_spll_func_cntl_3; |
table->ACPILevel.CgSpllFuncCntl4 = pi->clock_registers.cg_spll_func_cntl_4; |
table->ACPILevel.SpllSpreadSpectrum = pi->clock_registers.cg_spll_spread_spectrum; |
table->ACPILevel.SpllSpreadSpectrum2 = pi->clock_registers.cg_spll_spread_spectrum_2; |
table->ACPILevel.CcPwrDynRm = 0; |
table->ACPILevel.CcPwrDynRm1 = 0; |
table->ACPILevel.Flags = cpu_to_be32(table->ACPILevel.Flags); |
table->ACPILevel.MinVddcPhases = cpu_to_be32(table->ACPILevel.MinVddcPhases); |
table->ACPILevel.SclkFrequency = cpu_to_be32(table->ACPILevel.SclkFrequency); |
table->ACPILevel.CgSpllFuncCntl = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl); |
table->ACPILevel.CgSpllFuncCntl2 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl2); |
table->ACPILevel.CgSpllFuncCntl3 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl3); |
table->ACPILevel.CgSpllFuncCntl4 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl4); |
table->ACPILevel.SpllSpreadSpectrum = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum); |
table->ACPILevel.SpllSpreadSpectrum2 = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum2); |
table->ACPILevel.CcPwrDynRm = cpu_to_be32(table->ACPILevel.CcPwrDynRm); |
table->ACPILevel.CcPwrDynRm1 = cpu_to_be32(table->ACPILevel.CcPwrDynRm1); |
table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc; |
table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases; |
if (pi->vddci_control != CISLANDS_VOLTAGE_CONTROL_NONE) { |
if (pi->acpi_vddci) |
table->MemoryACPILevel.MinVddci = |
cpu_to_be32(pi->acpi_vddci * VOLTAGE_SCALE); |
else |
table->MemoryACPILevel.MinVddci = |
cpu_to_be32(pi->min_vddci_in_pp_table * VOLTAGE_SCALE); |
} |
if (ci_populate_mvdd_value(rdev, 0, &voltage_level)) |
table->MemoryACPILevel.MinMvdd = 0; |
else |
table->MemoryACPILevel.MinMvdd = |
cpu_to_be32(voltage_level.Voltage * VOLTAGE_SCALE); |
mclk_pwrmgt_cntl |= MRDCK0_RESET | MRDCK1_RESET; |
mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB); |
dll_cntl &= ~(MRDCK0_BYPASS | MRDCK1_BYPASS); |
table->MemoryACPILevel.DllCntl = cpu_to_be32(dll_cntl); |
table->MemoryACPILevel.MclkPwrmgtCntl = cpu_to_be32(mclk_pwrmgt_cntl); |
table->MemoryACPILevel.MpllAdFuncCntl = |
cpu_to_be32(pi->clock_registers.mpll_ad_func_cntl); |
table->MemoryACPILevel.MpllDqFuncCntl = |
cpu_to_be32(pi->clock_registers.mpll_dq_func_cntl); |
table->MemoryACPILevel.MpllFuncCntl = |
cpu_to_be32(pi->clock_registers.mpll_func_cntl); |
table->MemoryACPILevel.MpllFuncCntl_1 = |
cpu_to_be32(pi->clock_registers.mpll_func_cntl_1); |
table->MemoryACPILevel.MpllFuncCntl_2 = |
cpu_to_be32(pi->clock_registers.mpll_func_cntl_2); |
table->MemoryACPILevel.MpllSs1 = cpu_to_be32(pi->clock_registers.mpll_ss1); |
table->MemoryACPILevel.MpllSs2 = cpu_to_be32(pi->clock_registers.mpll_ss2); |
table->MemoryACPILevel.EnabledForThrottle = 0; |
table->MemoryACPILevel.EnabledForActivity = 0; |
table->MemoryACPILevel.UpH = 0; |
table->MemoryACPILevel.DownH = 100; |
table->MemoryACPILevel.VoltageDownH = 0; |
table->MemoryACPILevel.ActivityLevel = |
cpu_to_be16((u16)pi->mclk_activity_target); |
table->MemoryACPILevel.StutterEnable = false; |
table->MemoryACPILevel.StrobeEnable = false; |
table->MemoryACPILevel.EdcReadEnable = false; |
table->MemoryACPILevel.EdcWriteEnable = false; |
table->MemoryACPILevel.RttEnable = false; |
return 0; |
} |
static int ci_enable_ulv(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_ulv_parm *ulv = &pi->ulv; |
if (ulv->supported) { |
if (enable) |
return (ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableULV) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
else |
return (ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
return 0; |
} |
static int ci_populate_ulv_level(struct radeon_device *rdev, |
SMU7_Discrete_Ulv *state) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u16 ulv_voltage = rdev->pm.dpm.backbias_response_time; |
state->CcPwrDynRm = 0; |
state->CcPwrDynRm1 = 0; |
if (ulv_voltage == 0) { |
pi->ulv.supported = false; |
return 0; |
} |
if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_BY_SVID2) { |
if (ulv_voltage > rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v) |
state->VddcOffset = 0; |
else |
state->VddcOffset = |
rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage; |
} else { |
if (ulv_voltage > rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v) |
state->VddcOffsetVid = 0; |
else |
state->VddcOffsetVid = (u8) |
((rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage) * |
VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1); |
} |
state->VddcPhase = pi->vddc_phase_shed_control ? 0 : 1; |
state->CcPwrDynRm = cpu_to_be32(state->CcPwrDynRm); |
state->CcPwrDynRm1 = cpu_to_be32(state->CcPwrDynRm1); |
state->VddcOffset = cpu_to_be16(state->VddcOffset); |
return 0; |
} |
static int ci_calculate_sclk_params(struct radeon_device *rdev, |
u32 engine_clock, |
SMU7_Discrete_GraphicsLevel *sclk) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct atom_clock_dividers dividers; |
u32 spll_func_cntl_3 = pi->clock_registers.cg_spll_func_cntl_3; |
u32 spll_func_cntl_4 = pi->clock_registers.cg_spll_func_cntl_4; |
u32 cg_spll_spread_spectrum = pi->clock_registers.cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2 = pi->clock_registers.cg_spll_spread_spectrum_2; |
u32 reference_clock = rdev->clock.spll.reference_freq; |
u32 reference_divider; |
u32 fbdiv; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, |
COMPUTE_GPUCLK_INPUT_FLAG_SCLK, |
engine_clock, false, ÷rs); |
if (ret) |
return ret; |
reference_divider = 1 + dividers.ref_div; |
fbdiv = dividers.fb_div & 0x3FFFFFF; |
spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK; |
spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv); |
spll_func_cntl_3 |= SPLL_DITHEN; |
if (pi->caps_sclk_ss_support) { |
struct radeon_atom_ss ss; |
u32 vco_freq = engine_clock * dividers.post_div; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, vco_freq)) { |
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); |
u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000); |
cg_spll_spread_spectrum &= ~CLK_S_MASK; |
cg_spll_spread_spectrum |= CLK_S(clk_s); |
cg_spll_spread_spectrum |= SSEN; |
cg_spll_spread_spectrum_2 &= ~CLK_V_MASK; |
cg_spll_spread_spectrum_2 |= CLK_V(clk_v); |
} |
} |
sclk->SclkFrequency = engine_clock; |
sclk->CgSpllFuncCntl3 = spll_func_cntl_3; |
sclk->CgSpllFuncCntl4 = spll_func_cntl_4; |
sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum; |
sclk->SpllSpreadSpectrum2 = cg_spll_spread_spectrum_2; |
sclk->SclkDid = (u8)dividers.post_divider; |
return 0; |
} |
static int ci_populate_single_graphic_level(struct radeon_device *rdev, |
u32 engine_clock, |
u16 sclk_activity_level_t, |
SMU7_Discrete_GraphicsLevel *graphic_level) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int ret; |
ret = ci_calculate_sclk_params(rdev, engine_clock, graphic_level); |
if (ret) |
return ret; |
ret = ci_get_dependency_volt_by_clk(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
engine_clock, &graphic_level->MinVddc); |
if (ret) |
return ret; |
graphic_level->SclkFrequency = engine_clock; |
graphic_level->Flags = 0; |
graphic_level->MinVddcPhases = 1; |
if (pi->vddc_phase_shed_control) |
ci_populate_phase_value_based_on_sclk(rdev, |
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table, |
engine_clock, |
&graphic_level->MinVddcPhases); |
graphic_level->ActivityLevel = sclk_activity_level_t; |
graphic_level->CcPwrDynRm = 0; |
graphic_level->CcPwrDynRm1 = 0; |
graphic_level->EnabledForActivity = 1; |
graphic_level->EnabledForThrottle = 1; |
graphic_level->UpH = 0; |
graphic_level->DownH = 0; |
graphic_level->VoltageDownH = 0; |
graphic_level->PowerThrottle = 0; |
if (pi->caps_sclk_ds) |
graphic_level->DeepSleepDivId = ci_get_sleep_divider_id_from_clock(rdev, |
engine_clock, |
CISLAND_MINIMUM_ENGINE_CLOCK); |
graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; |
graphic_level->Flags = cpu_to_be32(graphic_level->Flags); |
graphic_level->MinVddc = cpu_to_be32(graphic_level->MinVddc * VOLTAGE_SCALE); |
graphic_level->MinVddcPhases = cpu_to_be32(graphic_level->MinVddcPhases); |
graphic_level->SclkFrequency = cpu_to_be32(graphic_level->SclkFrequency); |
graphic_level->ActivityLevel = cpu_to_be16(graphic_level->ActivityLevel); |
graphic_level->CgSpllFuncCntl3 = cpu_to_be32(graphic_level->CgSpllFuncCntl3); |
graphic_level->CgSpllFuncCntl4 = cpu_to_be32(graphic_level->CgSpllFuncCntl4); |
graphic_level->SpllSpreadSpectrum = cpu_to_be32(graphic_level->SpllSpreadSpectrum); |
graphic_level->SpllSpreadSpectrum2 = cpu_to_be32(graphic_level->SpllSpreadSpectrum2); |
graphic_level->CcPwrDynRm = cpu_to_be32(graphic_level->CcPwrDynRm); |
graphic_level->CcPwrDynRm1 = cpu_to_be32(graphic_level->CcPwrDynRm1); |
return 0; |
} |
static int ci_populate_all_graphic_levels(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_dpm_table *dpm_table = &pi->dpm_table; |
u32 level_array_address = pi->dpm_table_start + |
offsetof(SMU7_Discrete_DpmTable, GraphicsLevel); |
u32 level_array_size = sizeof(SMU7_Discrete_GraphicsLevel) * |
SMU7_MAX_LEVELS_GRAPHICS; |
SMU7_Discrete_GraphicsLevel *levels = pi->smc_state_table.GraphicsLevel; |
u32 i, ret; |
memset(levels, 0, level_array_size); |
for (i = 0; i < dpm_table->sclk_table.count; i++) { |
ret = ci_populate_single_graphic_level(rdev, |
dpm_table->sclk_table.dpm_levels[i].value, |
(u16)pi->activity_target[i], |
&pi->smc_state_table.GraphicsLevel[i]); |
if (ret) |
return ret; |
if (i == (dpm_table->sclk_table.count - 1)) |
pi->smc_state_table.GraphicsLevel[i].DisplayWatermark = |
PPSMC_DISPLAY_WATERMARK_HIGH; |
} |
pi->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count; |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask = |
ci_get_dpm_level_enable_mask_value(&dpm_table->sclk_table); |
ret = ci_copy_bytes_to_smc(rdev, level_array_address, |
(u8 *)levels, level_array_size, |
pi->sram_end); |
if (ret) |
return ret; |
return 0; |
} |
static int ci_populate_ulv_state(struct radeon_device *rdev, |
SMU7_Discrete_Ulv *ulv_level) |
{ |
return ci_populate_ulv_level(rdev, ulv_level); |
} |
static int ci_populate_all_memory_levels(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_dpm_table *dpm_table = &pi->dpm_table; |
u32 level_array_address = pi->dpm_table_start + |
offsetof(SMU7_Discrete_DpmTable, MemoryLevel); |
u32 level_array_size = sizeof(SMU7_Discrete_MemoryLevel) * |
SMU7_MAX_LEVELS_MEMORY; |
SMU7_Discrete_MemoryLevel *levels = pi->smc_state_table.MemoryLevel; |
u32 i, ret; |
memset(levels, 0, level_array_size); |
for (i = 0; i < dpm_table->mclk_table.count; i++) { |
if (dpm_table->mclk_table.dpm_levels[i].value == 0) |
return -EINVAL; |
ret = ci_populate_single_memory_level(rdev, |
dpm_table->mclk_table.dpm_levels[i].value, |
&pi->smc_state_table.MemoryLevel[i]); |
if (ret) |
return ret; |
} |
pi->smc_state_table.MemoryLevel[0].ActivityLevel = cpu_to_be16(0x1F); |
pi->smc_state_table.MemoryDpmLevelCount = (u8)dpm_table->mclk_table.count; |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask = |
ci_get_dpm_level_enable_mask_value(&dpm_table->mclk_table); |
pi->smc_state_table.MemoryLevel[dpm_table->mclk_table.count - 1].DisplayWatermark = |
PPSMC_DISPLAY_WATERMARK_HIGH; |
ret = ci_copy_bytes_to_smc(rdev, level_array_address, |
(u8 *)levels, level_array_size, |
pi->sram_end); |
if (ret) |
return ret; |
return 0; |
} |
static void ci_reset_single_dpm_table(struct radeon_device *rdev, |
struct ci_single_dpm_table* dpm_table, |
u32 count) |
{ |
u32 i; |
dpm_table->count = count; |
for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++) |
dpm_table->dpm_levels[i].enabled = false; |
} |
static void ci_setup_pcie_table_entry(struct ci_single_dpm_table* dpm_table, |
u32 index, u32 pcie_gen, u32 pcie_lanes) |
{ |
dpm_table->dpm_levels[index].value = pcie_gen; |
dpm_table->dpm_levels[index].param1 = pcie_lanes; |
dpm_table->dpm_levels[index].enabled = true; |
} |
static int ci_setup_default_pcie_tables(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (!pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels) |
return -EINVAL; |
if (pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels) { |
pi->pcie_gen_powersaving = pi->pcie_gen_performance; |
pi->pcie_lane_powersaving = pi->pcie_lane_performance; |
} else if (!pi->use_pcie_performance_levels && pi->use_pcie_powersaving_levels) { |
pi->pcie_gen_performance = pi->pcie_gen_powersaving; |
pi->pcie_lane_performance = pi->pcie_lane_powersaving; |
} |
ci_reset_single_dpm_table(rdev, |
&pi->dpm_table.pcie_speed_table, |
SMU7_MAX_LEVELS_LINK); |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0, |
pi->pcie_gen_powersaving.min, |
pi->pcie_lane_powersaving.min); |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 1, |
pi->pcie_gen_performance.min, |
pi->pcie_lane_performance.min); |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 2, |
pi->pcie_gen_powersaving.min, |
pi->pcie_lane_powersaving.max); |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 3, |
pi->pcie_gen_performance.min, |
pi->pcie_lane_performance.max); |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 4, |
pi->pcie_gen_powersaving.max, |
pi->pcie_lane_powersaving.max); |
ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 5, |
pi->pcie_gen_performance.max, |
pi->pcie_lane_performance.max); |
pi->dpm_table.pcie_speed_table.count = 6; |
return 0; |
} |
static int ci_setup_default_dpm_tables(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_clock_voltage_dependency_table *allowed_sclk_vddc_table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
struct radeon_clock_voltage_dependency_table *allowed_mclk_table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk; |
struct radeon_cac_leakage_table *std_voltage_table = |
&rdev->pm.dpm.dyn_state.cac_leakage_table; |
u32 i; |
if (allowed_sclk_vddc_table == NULL) |
return -EINVAL; |
if (allowed_sclk_vddc_table->count < 1) |
return -EINVAL; |
if (allowed_mclk_table == NULL) |
return -EINVAL; |
if (allowed_mclk_table->count < 1) |
return -EINVAL; |
memset(&pi->dpm_table, 0, sizeof(struct ci_dpm_table)); |
ci_reset_single_dpm_table(rdev, |
&pi->dpm_table.sclk_table, |
SMU7_MAX_LEVELS_GRAPHICS); |
ci_reset_single_dpm_table(rdev, |
&pi->dpm_table.mclk_table, |
SMU7_MAX_LEVELS_MEMORY); |
ci_reset_single_dpm_table(rdev, |
&pi->dpm_table.vddc_table, |
SMU7_MAX_LEVELS_VDDC); |
ci_reset_single_dpm_table(rdev, |
&pi->dpm_table.vddci_table, |
SMU7_MAX_LEVELS_VDDCI); |
ci_reset_single_dpm_table(rdev, |
&pi->dpm_table.mvdd_table, |
SMU7_MAX_LEVELS_MVDD); |
pi->dpm_table.sclk_table.count = 0; |
for (i = 0; i < allowed_sclk_vddc_table->count; i++) { |
if ((i == 0) || |
(pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count-1].value != |
allowed_sclk_vddc_table->entries[i].clk)) { |
pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].value = |
allowed_sclk_vddc_table->entries[i].clk; |
pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled = true; |
pi->dpm_table.sclk_table.count++; |
} |
} |
pi->dpm_table.mclk_table.count = 0; |
for (i = 0; i < allowed_mclk_table->count; i++) { |
if ((i==0) || |
(pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count-1].value != |
allowed_mclk_table->entries[i].clk)) { |
pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].value = |
allowed_mclk_table->entries[i].clk; |
pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled = true; |
pi->dpm_table.mclk_table.count++; |
} |
} |
for (i = 0; i < allowed_sclk_vddc_table->count; i++) { |
pi->dpm_table.vddc_table.dpm_levels[i].value = |
allowed_sclk_vddc_table->entries[i].v; |
pi->dpm_table.vddc_table.dpm_levels[i].param1 = |
std_voltage_table->entries[i].leakage; |
pi->dpm_table.vddc_table.dpm_levels[i].enabled = true; |
} |
pi->dpm_table.vddc_table.count = allowed_sclk_vddc_table->count; |
allowed_mclk_table = &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk; |
if (allowed_mclk_table) { |
for (i = 0; i < allowed_mclk_table->count; i++) { |
pi->dpm_table.vddci_table.dpm_levels[i].value = |
allowed_mclk_table->entries[i].v; |
pi->dpm_table.vddci_table.dpm_levels[i].enabled = true; |
} |
pi->dpm_table.vddci_table.count = allowed_mclk_table->count; |
} |
allowed_mclk_table = &rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk; |
if (allowed_mclk_table) { |
for (i = 0; i < allowed_mclk_table->count; i++) { |
pi->dpm_table.mvdd_table.dpm_levels[i].value = |
allowed_mclk_table->entries[i].v; |
pi->dpm_table.mvdd_table.dpm_levels[i].enabled = true; |
} |
pi->dpm_table.mvdd_table.count = allowed_mclk_table->count; |
} |
ci_setup_default_pcie_tables(rdev); |
return 0; |
} |
static int ci_find_boot_level(struct ci_single_dpm_table *table, |
u32 value, u32 *boot_level) |
{ |
u32 i; |
int ret = -EINVAL; |
for(i = 0; i < table->count; i++) { |
if (value == table->dpm_levels[i].value) { |
*boot_level = i; |
ret = 0; |
} |
} |
return ret; |
} |
static int ci_init_smc_table(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_ulv_parm *ulv = &pi->ulv; |
struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps; |
SMU7_Discrete_DpmTable *table = &pi->smc_state_table; |
int ret; |
ret = ci_setup_default_dpm_tables(rdev); |
if (ret) |
return ret; |
if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) |
ci_populate_smc_voltage_tables(rdev, table); |
ci_init_fps_limits(rdev); |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) |
table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) |
table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; |
if (pi->mem_gddr5) |
table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5; |
if (ulv->supported) { |
ret = ci_populate_ulv_state(rdev, &pi->smc_state_table.Ulv); |
if (ret) |
return ret; |
WREG32_SMC(CG_ULV_PARAMETER, ulv->cg_ulv_parameter); |
} |
ret = ci_populate_all_graphic_levels(rdev); |
if (ret) |
return ret; |
ret = ci_populate_all_memory_levels(rdev); |
if (ret) |
return ret; |
ci_populate_smc_link_level(rdev, table); |
ret = ci_populate_smc_acpi_level(rdev, table); |
if (ret) |
return ret; |
ret = ci_populate_smc_vce_level(rdev, table); |
if (ret) |
return ret; |
ret = ci_populate_smc_acp_level(rdev, table); |
if (ret) |
return ret; |
ret = ci_populate_smc_samu_level(rdev, table); |
if (ret) |
return ret; |
ret = ci_do_program_memory_timing_parameters(rdev); |
if (ret) |
return ret; |
ret = ci_populate_smc_uvd_level(rdev, table); |
if (ret) |
return ret; |
table->UvdBootLevel = 0; |
table->VceBootLevel = 0; |
table->AcpBootLevel = 0; |
table->SamuBootLevel = 0; |
table->GraphicsBootLevel = 0; |
table->MemoryBootLevel = 0; |
ret = ci_find_boot_level(&pi->dpm_table.sclk_table, |
pi->vbios_boot_state.sclk_bootup_value, |
(u32 *)&pi->smc_state_table.GraphicsBootLevel); |
ret = ci_find_boot_level(&pi->dpm_table.mclk_table, |
pi->vbios_boot_state.mclk_bootup_value, |
(u32 *)&pi->smc_state_table.MemoryBootLevel); |
table->BootVddc = pi->vbios_boot_state.vddc_bootup_value; |
table->BootVddci = pi->vbios_boot_state.vddci_bootup_value; |
table->BootMVdd = pi->vbios_boot_state.mvdd_bootup_value; |
ci_populate_smc_initial_state(rdev, radeon_boot_state); |
ret = ci_populate_bapm_parameters_in_dpm_table(rdev); |
if (ret) |
return ret; |
table->UVDInterval = 1; |
table->VCEInterval = 1; |
table->ACPInterval = 1; |
table->SAMUInterval = 1; |
table->GraphicsVoltageChangeEnable = 1; |
table->GraphicsThermThrottleEnable = 1; |
table->GraphicsInterval = 1; |
table->VoltageInterval = 1; |
table->ThermalInterval = 1; |
table->TemperatureLimitHigh = (u16)((pi->thermal_temp_setting.temperature_high * |
CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000); |
table->TemperatureLimitLow = (u16)((pi->thermal_temp_setting.temperature_low * |
CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000); |
table->MemoryVoltageChangeEnable = 1; |
table->MemoryInterval = 1; |
table->VoltageResponseTime = 0; |
table->VddcVddciDelta = 4000; |
table->PhaseResponseTime = 0; |
table->MemoryThermThrottleEnable = 1; |
table->PCIeBootLinkLevel = 0; |
table->PCIeGenInterval = 1; |
if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) |
table->SVI2Enable = 1; |
else |
table->SVI2Enable = 0; |
table->ThermGpio = 17; |
table->SclkStepSize = 0x4000; |
table->SystemFlags = cpu_to_be32(table->SystemFlags); |
table->SmioMaskVddcVid = cpu_to_be32(table->SmioMaskVddcVid); |
table->SmioMaskVddcPhase = cpu_to_be32(table->SmioMaskVddcPhase); |
table->SmioMaskVddciVid = cpu_to_be32(table->SmioMaskVddciVid); |
table->SmioMaskMvddVid = cpu_to_be32(table->SmioMaskMvddVid); |
table->SclkStepSize = cpu_to_be32(table->SclkStepSize); |
table->TemperatureLimitHigh = cpu_to_be16(table->TemperatureLimitHigh); |
table->TemperatureLimitLow = cpu_to_be16(table->TemperatureLimitLow); |
table->VddcVddciDelta = cpu_to_be16(table->VddcVddciDelta); |
table->VoltageResponseTime = cpu_to_be16(table->VoltageResponseTime); |
table->PhaseResponseTime = cpu_to_be16(table->PhaseResponseTime); |
table->BootVddc = cpu_to_be16(table->BootVddc * VOLTAGE_SCALE); |
table->BootVddci = cpu_to_be16(table->BootVddci * VOLTAGE_SCALE); |
table->BootMVdd = cpu_to_be16(table->BootMVdd * VOLTAGE_SCALE); |
ret = ci_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Discrete_DpmTable, SystemFlags), |
(u8 *)&table->SystemFlags, |
sizeof(SMU7_Discrete_DpmTable) - 3 * sizeof(SMU7_PIDController), |
pi->sram_end); |
if (ret) |
return ret; |
return 0; |
} |
static void ci_trim_single_dpm_states(struct radeon_device *rdev, |
struct ci_single_dpm_table *dpm_table, |
u32 low_limit, u32 high_limit) |
{ |
u32 i; |
for (i = 0; i < dpm_table->count; i++) { |
if ((dpm_table->dpm_levels[i].value < low_limit) || |
(dpm_table->dpm_levels[i].value > high_limit)) |
dpm_table->dpm_levels[i].enabled = false; |
else |
dpm_table->dpm_levels[i].enabled = true; |
} |
} |
static void ci_trim_pcie_dpm_states(struct radeon_device *rdev, |
u32 speed_low, u32 lanes_low, |
u32 speed_high, u32 lanes_high) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_single_dpm_table *pcie_table = &pi->dpm_table.pcie_speed_table; |
u32 i, j; |
for (i = 0; i < pcie_table->count; i++) { |
if ((pcie_table->dpm_levels[i].value < speed_low) || |
(pcie_table->dpm_levels[i].param1 < lanes_low) || |
(pcie_table->dpm_levels[i].value > speed_high) || |
(pcie_table->dpm_levels[i].param1 > lanes_high)) |
pcie_table->dpm_levels[i].enabled = false; |
else |
pcie_table->dpm_levels[i].enabled = true; |
} |
for (i = 0; i < pcie_table->count; i++) { |
if (pcie_table->dpm_levels[i].enabled) { |
for (j = i + 1; j < pcie_table->count; j++) { |
if (pcie_table->dpm_levels[j].enabled) { |
if ((pcie_table->dpm_levels[i].value == pcie_table->dpm_levels[j].value) && |
(pcie_table->dpm_levels[i].param1 == pcie_table->dpm_levels[j].param1)) |
pcie_table->dpm_levels[j].enabled = false; |
} |
} |
} |
} |
} |
static int ci_trim_dpm_states(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct ci_ps *state = ci_get_ps(radeon_state); |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 high_limit_count; |
if (state->performance_level_count < 1) |
return -EINVAL; |
if (state->performance_level_count == 1) |
high_limit_count = 0; |
else |
high_limit_count = 1; |
ci_trim_single_dpm_states(rdev, |
&pi->dpm_table.sclk_table, |
state->performance_levels[0].sclk, |
state->performance_levels[high_limit_count].sclk); |
ci_trim_single_dpm_states(rdev, |
&pi->dpm_table.mclk_table, |
state->performance_levels[0].mclk, |
state->performance_levels[high_limit_count].mclk); |
ci_trim_pcie_dpm_states(rdev, |
state->performance_levels[0].pcie_gen, |
state->performance_levels[0].pcie_lane, |
state->performance_levels[high_limit_count].pcie_gen, |
state->performance_levels[high_limit_count].pcie_lane); |
return 0; |
} |
static int ci_apply_disp_minimum_voltage_request(struct radeon_device *rdev) |
{ |
struct radeon_clock_voltage_dependency_table *disp_voltage_table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk; |
struct radeon_clock_voltage_dependency_table *vddc_table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
u32 requested_voltage = 0; |
u32 i; |
if (disp_voltage_table == NULL) |
return -EINVAL; |
if (!disp_voltage_table->count) |
return -EINVAL; |
for (i = 0; i < disp_voltage_table->count; i++) { |
if (rdev->clock.current_dispclk == disp_voltage_table->entries[i].clk) |
requested_voltage = disp_voltage_table->entries[i].v; |
} |
for (i = 0; i < vddc_table->count; i++) { |
if (requested_voltage <= vddc_table->entries[i].v) { |
requested_voltage = vddc_table->entries[i].v; |
return (ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_VddC_Request, |
requested_voltage * VOLTAGE_SCALE) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
} |
return -EINVAL; |
} |
static int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result result; |
if (!pi->sclk_dpm_key_disabled) { |
if (pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { |
result = ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_SCLKDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask); |
if (result != PPSMC_Result_OK) |
return -EINVAL; |
} |
} |
if (!pi->mclk_dpm_key_disabled) { |
if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask) { |
result = ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_MCLKDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask); |
if (result != PPSMC_Result_OK) |
return -EINVAL; |
} |
} |
if (!pi->pcie_dpm_key_disabled) { |
if (pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { |
result = ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_PCIeDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.pcie_dpm_enable_mask); |
if (result != PPSMC_Result_OK) |
return -EINVAL; |
} |
} |
ci_apply_disp_minimum_voltage_request(rdev); |
return 0; |
} |
static void ci_find_dpm_states_clocks_in_dpm_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_ps *state = ci_get_ps(radeon_state); |
struct ci_single_dpm_table *sclk_table = &pi->dpm_table.sclk_table; |
u32 sclk = state->performance_levels[state->performance_level_count-1].sclk; |
struct ci_single_dpm_table *mclk_table = &pi->dpm_table.mclk_table; |
u32 mclk = state->performance_levels[state->performance_level_count-1].mclk; |
u32 i; |
pi->need_update_smu7_dpm_table = 0; |
for (i = 0; i < sclk_table->count; i++) { |
if (sclk == sclk_table->dpm_levels[i].value) |
break; |
} |
if (i >= sclk_table->count) { |
pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; |
} else { |
/* XXX check display min clock requirements */ |
if (0 != CISLAND_MINIMUM_ENGINE_CLOCK) |
pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK; |
} |
for (i = 0; i < mclk_table->count; i++) { |
if (mclk == mclk_table->dpm_levels[i].value) |
break; |
} |
if (i >= mclk_table->count) |
pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; |
if (rdev->pm.dpm.current_active_crtc_count != |
rdev->pm.dpm.new_active_crtc_count) |
pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK; |
} |
static int ci_populate_and_upload_sclk_mclk_dpm_levels(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_ps *state = ci_get_ps(radeon_state); |
u32 sclk = state->performance_levels[state->performance_level_count-1].sclk; |
u32 mclk = state->performance_levels[state->performance_level_count-1].mclk; |
struct ci_dpm_table *dpm_table = &pi->dpm_table; |
int ret; |
if (!pi->need_update_smu7_dpm_table) |
return 0; |
if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) |
dpm_table->sclk_table.dpm_levels[dpm_table->sclk_table.count-1].value = sclk; |
if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) |
dpm_table->mclk_table.dpm_levels[dpm_table->mclk_table.count-1].value = mclk; |
if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK)) { |
ret = ci_populate_all_graphic_levels(rdev); |
if (ret) |
return ret; |
} |
if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK | DPMTABLE_UPDATE_MCLK)) { |
ret = ci_populate_all_memory_levels(rdev); |
if (ret) |
return ret; |
} |
return 0; |
} |
static int ci_enable_uvd_dpm(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
const struct radeon_clock_and_voltage_limits *max_limits; |
int i; |
if (rdev->pm.dpm.ac_power) |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
else |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc; |
if (enable) { |
pi->dpm_level_enable_mask.uvd_dpm_enable_mask = 0; |
for (i = rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1; i >= 0; i--) { |
if (rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) { |
pi->dpm_level_enable_mask.uvd_dpm_enable_mask |= 1 << i; |
if (!pi->caps_uvd_dpm) |
break; |
} |
} |
ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_UVDDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.uvd_dpm_enable_mask); |
if (pi->last_mclk_dpm_enable_mask & 0x1) { |
pi->uvd_enabled = true; |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE; |
ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_MCLKDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask); |
} |
} else { |
if (pi->last_mclk_dpm_enable_mask & 0x1) { |
pi->uvd_enabled = false; |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask |= 1; |
ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_MCLKDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask); |
} |
} |
return (ci_send_msg_to_smc(rdev, enable ? |
PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
const struct radeon_clock_and_voltage_limits *max_limits; |
int i; |
if (rdev->pm.dpm.ac_power) |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
else |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc; |
if (enable) { |
pi->dpm_level_enable_mask.vce_dpm_enable_mask = 0; |
for (i = rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count - 1; i >= 0; i--) { |
if (rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) { |
pi->dpm_level_enable_mask.vce_dpm_enable_mask |= 1 << i; |
if (!pi->caps_vce_dpm) |
break; |
} |
} |
ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_VCEDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.vce_dpm_enable_mask); |
} |
return (ci_send_msg_to_smc(rdev, enable ? |
PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable) == PPSMC_Result_OK) ? |
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); |
const struct radeon_clock_and_voltage_limits *max_limits; |
int i; |
if (rdev->pm.dpm.ac_power) |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
else |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc; |
if (enable) { |
pi->dpm_level_enable_mask.samu_dpm_enable_mask = 0; |
for (i = rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count - 1; i >= 0; i--) { |
if (rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) { |
pi->dpm_level_enable_mask.samu_dpm_enable_mask |= 1 << i; |
if (!pi->caps_samu_dpm) |
break; |
} |
} |
ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_SAMUDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.samu_dpm_enable_mask); |
} |
return (ci_send_msg_to_smc(rdev, enable ? |
PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static int ci_enable_acp_dpm(struct radeon_device *rdev, bool enable) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
const struct radeon_clock_and_voltage_limits *max_limits; |
int i; |
if (rdev->pm.dpm.ac_power) |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
else |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc; |
if (enable) { |
pi->dpm_level_enable_mask.acp_dpm_enable_mask = 0; |
for (i = rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count - 1; i >= 0; i--) { |
if (rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) { |
pi->dpm_level_enable_mask.acp_dpm_enable_mask |= 1 << i; |
if (!pi->caps_acp_dpm) |
break; |
} |
} |
ci_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_ACPDPM_SetEnabledMask, |
pi->dpm_level_enable_mask.acp_dpm_enable_mask); |
} |
return (ci_send_msg_to_smc(rdev, enable ? |
PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
#endif |
static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 tmp; |
if (!gate) { |
if (pi->caps_uvd_dpm || |
(rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count <= 0)) |
pi->smc_state_table.UvdBootLevel = 0; |
else |
pi->smc_state_table.UvdBootLevel = |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1; |
tmp = RREG32_SMC(DPM_TABLE_475); |
tmp &= ~UvdBootLevel_MASK; |
tmp |= UvdBootLevel(pi->smc_state_table.UvdBootLevel); |
WREG32_SMC(DPM_TABLE_475, tmp); |
} |
return ci_enable_uvd_dpm(rdev, !gate); |
} |
static u8 ci_get_vce_boot_level(struct radeon_device *rdev) |
{ |
u8 i; |
u32 min_evclk = 30000; /* ??? */ |
struct radeon_vce_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; |
for (i = 0; i < table->count; i++) { |
if (table->entries[i].evclk >= min_evclk) |
return i; |
} |
return table->count - 1; |
} |
static int ci_update_vce_dpm(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int ret = 0; |
u32 tmp; |
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); |
WREG32_SMC(DPM_TABLE_475, tmp); |
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); |
} |
static int ci_update_acp_dpm(struct radeon_device *rdev, bool gate) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 tmp; |
if (!gate) { |
pi->smc_state_table.AcpBootLevel = 0; |
tmp = RREG32_SMC(DPM_TABLE_475); |
tmp &= ~AcpBootLevel_MASK; |
tmp |= AcpBootLevel(pi->smc_state_table.AcpBootLevel); |
WREG32_SMC(DPM_TABLE_475, tmp); |
} |
return ci_enable_acp_dpm(rdev, !gate); |
} |
#endif |
static int ci_generate_dpm_level_enable_mask(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int ret; |
ret = ci_trim_dpm_states(rdev, radeon_state); |
if (ret) |
return ret; |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask = |
ci_get_dpm_level_enable_mask_value(&pi->dpm_table.sclk_table); |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask = |
ci_get_dpm_level_enable_mask_value(&pi->dpm_table.mclk_table); |
pi->last_mclk_dpm_enable_mask = |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask; |
if (pi->uvd_enabled) { |
if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask & 1) |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE; |
} |
pi->dpm_level_enable_mask.pcie_dpm_enable_mask = |
ci_get_dpm_level_enable_mask_value(&pi->dpm_table.pcie_speed_table); |
return 0; |
} |
static u32 ci_get_lowest_enabled_level(struct radeon_device *rdev, |
u32 level_mask) |
{ |
u32 level = 0; |
while ((level_mask & (1 << level)) == 0) |
level++; |
return level; |
} |
int ci_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
PPSMC_Result smc_result; |
u32 tmp, levels, i; |
int ret; |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
if ((!pi->sclk_dpm_key_disabled) && |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { |
levels = 0; |
tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask; |
while (tmp >>= 1) |
levels++; |
if (levels) { |
ret = ci_dpm_force_state_sclk(rdev, levels); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & |
CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
} |
} |
} |
if ((!pi->mclk_dpm_key_disabled) && |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask) { |
levels = 0; |
tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask; |
while (tmp >>= 1) |
levels++; |
if (levels) { |
ret = ci_dpm_force_state_mclk(rdev, levels); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & |
CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
} |
} |
} |
if ((!pi->pcie_dpm_key_disabled) && |
pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { |
levels = 0; |
tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask; |
while (tmp >>= 1) |
levels++; |
if (levels) { |
ret = ci_dpm_force_state_pcie(rdev, level); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) & |
CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
} |
} |
} |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
if ((!pi->sclk_dpm_key_disabled) && |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { |
levels = ci_get_lowest_enabled_level(rdev, |
pi->dpm_level_enable_mask.sclk_dpm_enable_mask); |
ret = ci_dpm_force_state_sclk(rdev, levels); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & |
CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
} |
} |
if ((!pi->mclk_dpm_key_disabled) && |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask) { |
levels = ci_get_lowest_enabled_level(rdev, |
pi->dpm_level_enable_mask.mclk_dpm_enable_mask); |
ret = ci_dpm_force_state_mclk(rdev, levels); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & |
CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
} |
} |
if ((!pi->pcie_dpm_key_disabled) && |
pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { |
levels = ci_get_lowest_enabled_level(rdev, |
pi->dpm_level_enable_mask.pcie_dpm_enable_mask); |
ret = ci_dpm_force_state_pcie(rdev, levels); |
if (ret) |
return ret; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) & |
CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT; |
if (tmp == levels) |
break; |
udelay(1); |
} |
} |
} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { |
if (!pi->sclk_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
if (!pi->mclk_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_NoForcedLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
if (!pi->pcie_dpm_key_disabled) { |
smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_UnForceLevel); |
if (smc_result != PPSMC_Result_OK) |
return -EINVAL; |
} |
} |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
static int ci_set_mc_special_registers(struct radeon_device *rdev, |
struct ci_mc_reg_table *table) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u8 i, j, k; |
u32 temp_reg; |
for (i = 0, j = table->last; i < table->last; i++) { |
if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
switch(table->mc_reg_address[i].s1 << 2) { |
case MC_SEQ_MISC1: |
temp_reg = RREG32(MC_PMG_CMD_EMRS); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
for (k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
((temp_reg & 0xffff0000)) | ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16); |
} |
j++; |
if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
temp_reg = RREG32(MC_PMG_CMD_MRS); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
for (k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
(temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); |
if (!pi->mem_gddr5) |
table->mc_reg_table_entry[k].mc_data[j] |= 0x100; |
} |
j++; |
if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
if (!pi->mem_gddr5) { |
table->mc_reg_address[j].s1 = MC_PMG_AUTO_CMD >> 2; |
table->mc_reg_address[j].s0 = MC_PMG_AUTO_CMD >> 2; |
for (k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
(table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16; |
} |
j++; |
if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
} |
break; |
case MC_SEQ_RESERVE_M: |
temp_reg = RREG32(MC_PMG_CMD_MRS1); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
for (k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
(temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); |
} |
j++; |
if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
break; |
default: |
break; |
} |
} |
table->last = j; |
return 0; |
} |
static bool ci_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg) |
{ |
bool result = true; |
switch(in_reg) { |
case MC_SEQ_RAS_TIMING >> 2: |
*out_reg = MC_SEQ_RAS_TIMING_LP >> 2; |
break; |
case MC_SEQ_DLL_STBY >> 2: |
*out_reg = MC_SEQ_DLL_STBY_LP >> 2; |
break; |
case MC_SEQ_G5PDX_CMD0 >> 2: |
*out_reg = MC_SEQ_G5PDX_CMD0_LP >> 2; |
break; |
case MC_SEQ_G5PDX_CMD1 >> 2: |
*out_reg = MC_SEQ_G5PDX_CMD1_LP >> 2; |
break; |
case MC_SEQ_G5PDX_CTRL >> 2: |
*out_reg = MC_SEQ_G5PDX_CTRL_LP >> 2; |
break; |
case MC_SEQ_CAS_TIMING >> 2: |
*out_reg = MC_SEQ_CAS_TIMING_LP >> 2; |
break; |
case MC_SEQ_MISC_TIMING >> 2: |
*out_reg = MC_SEQ_MISC_TIMING_LP >> 2; |
break; |
case MC_SEQ_MISC_TIMING2 >> 2: |
*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2; |
break; |
case MC_SEQ_PMG_DVS_CMD >> 2: |
*out_reg = MC_SEQ_PMG_DVS_CMD_LP >> 2; |
break; |
case MC_SEQ_PMG_DVS_CTL >> 2: |
*out_reg = MC_SEQ_PMG_DVS_CTL_LP >> 2; |
break; |
case MC_SEQ_RD_CTL_D0 >> 2: |
*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2; |
break; |
case MC_SEQ_RD_CTL_D1 >> 2: |
*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_D0 >> 2: |
*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_D1 >> 2: |
*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2; |
break; |
case MC_PMG_CMD_EMRS >> 2: |
*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
break; |
case MC_PMG_CMD_MRS >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
break; |
case MC_PMG_CMD_MRS1 >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
break; |
case MC_SEQ_PMG_TIMING >> 2: |
*out_reg = MC_SEQ_PMG_TIMING_LP >> 2; |
break; |
case MC_PMG_CMD_MRS2 >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_2 >> 2: |
*out_reg = MC_SEQ_WR_CTL_2_LP >> 2; |
break; |
default: |
result = false; |
break; |
} |
return result; |
} |
static void ci_set_valid_flag(struct ci_mc_reg_table *table) |
{ |
u8 i, j; |
for (i = 0; i < table->last; i++) { |
for (j = 1; j < table->num_entries; j++) { |
if (table->mc_reg_table_entry[j-1].mc_data[i] != |
table->mc_reg_table_entry[j].mc_data[i]) { |
table->valid_flag |= 1 << i; |
break; |
} |
} |
} |
} |
static void ci_set_s0_mc_reg_index(struct ci_mc_reg_table *table) |
{ |
u32 i; |
u16 address; |
for (i = 0; i < table->last; i++) { |
table->mc_reg_address[i].s0 = |
ci_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ? |
address : table->mc_reg_address[i].s1; |
} |
} |
static int ci_copy_vbios_mc_reg_table(const struct atom_mc_reg_table *table, |
struct ci_mc_reg_table *ci_table) |
{ |
u8 i, j; |
if (table->last > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
if (table->num_entries > MAX_AC_TIMING_ENTRIES) |
return -EINVAL; |
for (i = 0; i < table->last; i++) |
ci_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1; |
ci_table->last = table->last; |
for (i = 0; i < table->num_entries; i++) { |
ci_table->mc_reg_table_entry[i].mclk_max = |
table->mc_reg_table_entry[i].mclk_max; |
for (j = 0; j < table->last; j++) |
ci_table->mc_reg_table_entry[i].mc_data[j] = |
table->mc_reg_table_entry[i].mc_data[j]; |
} |
ci_table->num_entries = table->num_entries; |
return 0; |
} |
static int ci_initialize_mc_reg_table(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct atom_mc_reg_table *table; |
struct ci_mc_reg_table *ci_table = &pi->mc_reg_table; |
u8 module_index = rv770_get_memory_module_index(rdev); |
int ret; |
table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL); |
if (!table) |
return -ENOMEM; |
WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING)); |
WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING)); |
WREG32(MC_SEQ_DLL_STBY_LP, RREG32(MC_SEQ_DLL_STBY)); |
WREG32(MC_SEQ_G5PDX_CMD0_LP, RREG32(MC_SEQ_G5PDX_CMD0)); |
WREG32(MC_SEQ_G5PDX_CMD1_LP, RREG32(MC_SEQ_G5PDX_CMD1)); |
WREG32(MC_SEQ_G5PDX_CTRL_LP, RREG32(MC_SEQ_G5PDX_CTRL)); |
WREG32(MC_SEQ_PMG_DVS_CMD_LP, RREG32(MC_SEQ_PMG_DVS_CMD)); |
WREG32(MC_SEQ_PMG_DVS_CTL_LP, RREG32(MC_SEQ_PMG_DVS_CTL)); |
WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING)); |
WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2)); |
WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS)); |
WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS)); |
WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1)); |
WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0)); |
WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1)); |
WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0)); |
WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1)); |
WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING)); |
WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2)); |
WREG32(MC_SEQ_WR_CTL_2_LP, RREG32(MC_SEQ_WR_CTL_2)); |
ret = radeon_atom_init_mc_reg_table(rdev, module_index, table); |
if (ret) |
goto init_mc_done; |
ret = ci_copy_vbios_mc_reg_table(table, ci_table); |
if (ret) |
goto init_mc_done; |
ci_set_s0_mc_reg_index(ci_table); |
ret = ci_set_mc_special_registers(rdev, ci_table); |
if (ret) |
goto init_mc_done; |
ci_set_valid_flag(ci_table); |
init_mc_done: |
kfree(table); |
return ret; |
} |
static int ci_populate_mc_reg_addresses(struct radeon_device *rdev, |
SMU7_Discrete_MCRegisters *mc_reg_table) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 i, j; |
for (i = 0, j = 0; j < pi->mc_reg_table.last; j++) { |
if (pi->mc_reg_table.valid_flag & (1 << j)) { |
if (i >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
mc_reg_table->address[i].s0 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s0); |
mc_reg_table->address[i].s1 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s1); |
i++; |
} |
} |
mc_reg_table->last = (u8)i; |
return 0; |
} |
static void ci_convert_mc_registers(const struct ci_mc_reg_entry *entry, |
SMU7_Discrete_MCRegisterSet *data, |
u32 num_entries, u32 valid_flag) |
{ |
u32 i, j; |
for (i = 0, j = 0; j < num_entries; j++) { |
if (valid_flag & (1 << j)) { |
data->value[i] = cpu_to_be32(entry->mc_data[j]); |
i++; |
} |
} |
} |
static void ci_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev, |
const u32 memory_clock, |
SMU7_Discrete_MCRegisterSet *mc_reg_table_data) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 i = 0; |
for(i = 0; i < pi->mc_reg_table.num_entries; i++) { |
if (memory_clock <= pi->mc_reg_table.mc_reg_table_entry[i].mclk_max) |
break; |
} |
if ((i == pi->mc_reg_table.num_entries) && (i > 0)) |
--i; |
ci_convert_mc_registers(&pi->mc_reg_table.mc_reg_table_entry[i], |
mc_reg_table_data, pi->mc_reg_table.last, |
pi->mc_reg_table.valid_flag); |
} |
static void ci_convert_mc_reg_table_to_smc(struct radeon_device *rdev, |
SMU7_Discrete_MCRegisters *mc_reg_table) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 i; |
for (i = 0; i < pi->dpm_table.mclk_table.count; i++) |
ci_convert_mc_reg_table_entry_to_smc(rdev, |
pi->dpm_table.mclk_table.dpm_levels[i].value, |
&mc_reg_table->data[i]); |
} |
static int ci_populate_initial_mc_reg_table(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
int ret; |
memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters)); |
ret = ci_populate_mc_reg_addresses(rdev, &pi->smc_mc_reg_table); |
if (ret) |
return ret; |
ci_convert_mc_reg_table_to_smc(rdev, &pi->smc_mc_reg_table); |
return ci_copy_bytes_to_smc(rdev, |
pi->mc_reg_table_start, |
(u8 *)&pi->smc_mc_reg_table, |
sizeof(SMU7_Discrete_MCRegisters), |
pi->sram_end); |
} |
static int ci_update_and_upload_mc_reg_table(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
if (!(pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) |
return 0; |
memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters)); |
ci_convert_mc_reg_table_to_smc(rdev, &pi->smc_mc_reg_table); |
return ci_copy_bytes_to_smc(rdev, |
pi->mc_reg_table_start + |
offsetof(SMU7_Discrete_MCRegisters, data[0]), |
(u8 *)&pi->smc_mc_reg_table.data[0], |
sizeof(SMU7_Discrete_MCRegisterSet) * |
pi->dpm_table.mclk_table.count, |
pi->sram_end); |
} |
static void ci_enable_voltage_control(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(GENERAL_PWRMGT); |
tmp |= VOLT_PWRMGT_EN; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
} |
static enum radeon_pcie_gen ci_get_maximum_link_speed(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct ci_ps *state = ci_get_ps(radeon_state); |
int i; |
u16 pcie_speed, max_speed = 0; |
for (i = 0; i < state->performance_level_count; i++) { |
pcie_speed = state->performance_levels[i].pcie_gen; |
if (max_speed < pcie_speed) |
max_speed = pcie_speed; |
} |
return max_speed; |
} |
static u16 ci_get_current_pcie_speed(struct radeon_device *rdev) |
{ |
u32 speed_cntl = 0; |
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE_MASK; |
speed_cntl >>= LC_CURRENT_DATA_RATE_SHIFT; |
return (u16)speed_cntl; |
} |
static int ci_get_current_pcie_lane_number(struct radeon_device *rdev) |
{ |
u32 link_width = 0; |
link_width = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL) & LC_LINK_WIDTH_RD_MASK; |
link_width >>= LC_LINK_WIDTH_RD_SHIFT; |
switch (link_width) { |
case RADEON_PCIE_LC_LINK_WIDTH_X1: |
return 1; |
case RADEON_PCIE_LC_LINK_WIDTH_X2: |
return 2; |
case RADEON_PCIE_LC_LINK_WIDTH_X4: |
return 4; |
case RADEON_PCIE_LC_LINK_WIDTH_X8: |
return 8; |
case RADEON_PCIE_LC_LINK_WIDTH_X12: |
/* not actually supported */ |
return 12; |
case RADEON_PCIE_LC_LINK_WIDTH_X0: |
case RADEON_PCIE_LC_LINK_WIDTH_X16: |
default: |
return 16; |
} |
} |
static void ci_request_link_speed_change_before_state_change(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
enum radeon_pcie_gen target_link_speed = |
ci_get_maximum_link_speed(rdev, radeon_new_state); |
enum radeon_pcie_gen current_link_speed; |
if (pi->force_pcie_gen == RADEON_PCIE_GEN_INVALID) |
current_link_speed = ci_get_maximum_link_speed(rdev, radeon_current_state); |
else |
current_link_speed = pi->force_pcie_gen; |
pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID; |
pi->pspp_notify_required = false; |
if (target_link_speed > current_link_speed) { |
switch (target_link_speed) { |
#ifdef CONFIG_ACPI |
case RADEON_PCIE_GEN3: |
if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN3, false) == 0) |
break; |
pi->force_pcie_gen = RADEON_PCIE_GEN2; |
if (current_link_speed == RADEON_PCIE_GEN2) |
break; |
case RADEON_PCIE_GEN2: |
if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, false) == 0) |
break; |
#endif |
default: |
pi->force_pcie_gen = ci_get_current_pcie_speed(rdev); |
break; |
} |
} else { |
if (target_link_speed < current_link_speed) |
pi->pspp_notify_required = true; |
} |
} |
static void ci_notify_link_speed_change_after_state_change(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
enum radeon_pcie_gen target_link_speed = |
ci_get_maximum_link_speed(rdev, radeon_new_state); |
u8 request; |
if (pi->pspp_notify_required) { |
if (target_link_speed == RADEON_PCIE_GEN3) |
request = PCIE_PERF_REQ_PECI_GEN3; |
else if (target_link_speed == RADEON_PCIE_GEN2) |
request = PCIE_PERF_REQ_PECI_GEN2; |
else |
request = PCIE_PERF_REQ_PECI_GEN1; |
if ((request == PCIE_PERF_REQ_PECI_GEN1) && |
(ci_get_current_pcie_speed(rdev) > 0)) |
return; |
#ifdef CONFIG_ACPI |
radeon_acpi_pcie_performance_request(rdev, request, false); |
#endif |
} |
} |
static int ci_set_private_data_variables_based_on_pptable(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_clock_voltage_dependency_table *allowed_sclk_vddc_table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
struct radeon_clock_voltage_dependency_table *allowed_mclk_vddc_table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk; |
struct radeon_clock_voltage_dependency_table *allowed_mclk_vddci_table = |
&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk; |
if (allowed_sclk_vddc_table == NULL) |
return -EINVAL; |
if (allowed_sclk_vddc_table->count < 1) |
return -EINVAL; |
if (allowed_mclk_vddc_table == NULL) |
return -EINVAL; |
if (allowed_mclk_vddc_table->count < 1) |
return -EINVAL; |
if (allowed_mclk_vddci_table == NULL) |
return -EINVAL; |
if (allowed_mclk_vddci_table->count < 1) |
return -EINVAL; |
pi->min_vddc_in_pp_table = allowed_sclk_vddc_table->entries[0].v; |
pi->max_vddc_in_pp_table = |
allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v; |
pi->min_vddci_in_pp_table = allowed_mclk_vddci_table->entries[0].v; |
pi->max_vddci_in_pp_table = |
allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v; |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = |
allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk; |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = |
allowed_mclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk; |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = |
allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v; |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = |
allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v; |
return 0; |
} |
static void ci_patch_with_vddc_leakage(struct radeon_device *rdev, u16 *vddc) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_leakage_voltage *leakage_table = &pi->vddc_leakage; |
u32 leakage_index; |
for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) { |
if (leakage_table->leakage_id[leakage_index] == *vddc) { |
*vddc = leakage_table->actual_voltage[leakage_index]; |
break; |
} |
} |
} |
static void ci_patch_with_vddci_leakage(struct radeon_device *rdev, u16 *vddci) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_leakage_voltage *leakage_table = &pi->vddci_leakage; |
u32 leakage_index; |
for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) { |
if (leakage_table->leakage_id[leakage_index] == *vddci) { |
*vddci = leakage_table->actual_voltage[leakage_index]; |
break; |
} |
} |
} |
static void ci_patch_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev, |
struct radeon_clock_voltage_dependency_table *table) |
{ |
u32 i; |
if (table) { |
for (i = 0; i < table->count; i++) |
ci_patch_with_vddc_leakage(rdev, &table->entries[i].v); |
} |
} |
static void ci_patch_clock_voltage_dependency_table_with_vddci_leakage(struct radeon_device *rdev, |
struct radeon_clock_voltage_dependency_table *table) |
{ |
u32 i; |
if (table) { |
for (i = 0; i < table->count; i++) |
ci_patch_with_vddci_leakage(rdev, &table->entries[i].v); |
} |
} |
static void ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev, |
struct radeon_vce_clock_voltage_dependency_table *table) |
{ |
u32 i; |
if (table) { |
for (i = 0; i < table->count; i++) |
ci_patch_with_vddc_leakage(rdev, &table->entries[i].v); |
} |
} |
static void ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev, |
struct radeon_uvd_clock_voltage_dependency_table *table) |
{ |
u32 i; |
if (table) { |
for (i = 0; i < table->count; i++) |
ci_patch_with_vddc_leakage(rdev, &table->entries[i].v); |
} |
} |
static void ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(struct radeon_device *rdev, |
struct radeon_phase_shedding_limits_table *table) |
{ |
u32 i; |
if (table) { |
for (i = 0; i < table->count; i++) |
ci_patch_with_vddc_leakage(rdev, &table->entries[i].voltage); |
} |
} |
static void ci_patch_clock_voltage_limits_with_vddc_leakage(struct radeon_device *rdev, |
struct radeon_clock_and_voltage_limits *table) |
{ |
if (table) { |
ci_patch_with_vddc_leakage(rdev, (u16 *)&table->vddc); |
ci_patch_with_vddci_leakage(rdev, (u16 *)&table->vddci); |
} |
} |
static void ci_patch_cac_leakage_table_with_vddc_leakage(struct radeon_device *rdev, |
struct radeon_cac_leakage_table *table) |
{ |
u32 i; |
if (table) { |
for (i = 0; i < table->count; i++) |
ci_patch_with_vddc_leakage(rdev, &table->entries[i].vddc); |
} |
} |
static void ci_patch_dependency_tables_with_leakage(struct radeon_device *rdev) |
{ |
ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk); |
ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk); |
ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk); |
ci_patch_clock_voltage_dependency_table_with_vddci_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk); |
ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table); |
ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table); |
ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table); |
ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table); |
ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table); |
ci_patch_clock_voltage_limits_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac); |
ci_patch_clock_voltage_limits_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc); |
ci_patch_cac_leakage_table_with_vddc_leakage(rdev, |
&rdev->pm.dpm.dyn_state.cac_leakage_table); |
} |
static void ci_get_memory_type(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
u32 tmp; |
tmp = RREG32(MC_SEQ_MISC0); |
if (((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT) == |
MC_SEQ_MISC0_GDDR5_VALUE) |
pi->mem_gddr5 = true; |
else |
pi->mem_gddr5 = false; |
} |
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); |
pi->current_rps = *rps; |
pi->current_ps = *new_ps; |
pi->current_rps.ps_priv = &pi->current_ps; |
} |
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); |
pi->requested_rps = *rps; |
pi->requested_ps = *new_ps; |
pi->requested_rps.ps_priv = &pi->requested_ps; |
} |
int ci_dpm_pre_set_power_state(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; |
struct radeon_ps *new_ps = &requested_ps; |
ci_update_requested_ps(rdev, new_ps); |
ci_apply_state_adjust_rules(rdev, &pi->requested_rps); |
return 0; |
} |
void ci_dpm_post_set_power_state(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_ps *new_ps = &pi->requested_rps; |
ci_update_current_ps(rdev, new_ps); |
} |
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); |
ci_init_sclk_t(rdev); |
} |
int ci_dpm_enable(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
int ret; |
if (ci_is_smc_running(rdev)) |
return -EINVAL; |
if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) { |
ci_enable_voltage_control(rdev); |
ret = ci_construct_voltage_tables(rdev); |
if (ret) { |
DRM_ERROR("ci_construct_voltage_tables failed\n"); |
return ret; |
} |
} |
if (pi->caps_dynamic_ac_timing) { |
ret = ci_initialize_mc_reg_table(rdev); |
if (ret) |
pi->caps_dynamic_ac_timing = false; |
} |
if (pi->dynamic_ss) |
ci_enable_spread_spectrum(rdev, true); |
if (pi->thermal_protection) |
ci_enable_thermal_protection(rdev, true); |
ci_program_sstp(rdev); |
ci_enable_display_gap(rdev); |
ci_program_vc(rdev); |
ret = ci_upload_firmware(rdev); |
if (ret) { |
DRM_ERROR("ci_upload_firmware failed\n"); |
return ret; |
} |
ret = ci_process_firmware_header(rdev); |
if (ret) { |
DRM_ERROR("ci_process_firmware_header failed\n"); |
return ret; |
} |
ret = ci_initial_switch_from_arb_f0_to_f1(rdev); |
if (ret) { |
DRM_ERROR("ci_initial_switch_from_arb_f0_to_f1 failed\n"); |
return ret; |
} |
ret = ci_init_smc_table(rdev); |
if (ret) { |
DRM_ERROR("ci_init_smc_table failed\n"); |
return ret; |
} |
ret = ci_init_arb_table_index(rdev); |
if (ret) { |
DRM_ERROR("ci_init_arb_table_index failed\n"); |
return ret; |
} |
if (pi->caps_dynamic_ac_timing) { |
ret = ci_populate_initial_mc_reg_table(rdev); |
if (ret) { |
DRM_ERROR("ci_populate_initial_mc_reg_table failed\n"); |
return ret; |
} |
} |
ret = ci_populate_pm_base(rdev); |
if (ret) { |
DRM_ERROR("ci_populate_pm_base failed\n"); |
return ret; |
} |
ci_dpm_start_smc(rdev); |
ci_enable_vr_hot_gpio_interrupt(rdev); |
ret = ci_notify_smc_display_change(rdev, false); |
if (ret) { |
DRM_ERROR("ci_notify_smc_display_change failed\n"); |
return ret; |
} |
ci_enable_sclk_control(rdev, true); |
ret = ci_enable_ulv(rdev, true); |
if (ret) { |
DRM_ERROR("ci_enable_ulv failed\n"); |
return ret; |
} |
ret = ci_enable_ds_master_switch(rdev, true); |
if (ret) { |
DRM_ERROR("ci_enable_ds_master_switch failed\n"); |
return ret; |
} |
ret = ci_start_dpm(rdev); |
if (ret) { |
DRM_ERROR("ci_start_dpm failed\n"); |
return ret; |
} |
ret = ci_enable_didt(rdev, true); |
if (ret) { |
DRM_ERROR("ci_enable_didt failed\n"); |
return ret; |
} |
ret = ci_enable_smc_cac(rdev, true); |
if (ret) { |
DRM_ERROR("ci_enable_smc_cac failed\n"); |
return ret; |
} |
ret = ci_enable_power_containment(rdev, true); |
if (ret) { |
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 |
PPSMC_Result result; |
#endif |
ret = ci_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); |
if (ret) { |
DRM_ERROR("ci_set_thermal_temperature_range failed\n"); |
return ret; |
} |
rdev->irq.dpm_thermal = true; |
radeon_irq_set(rdev); |
#if 0 |
result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); |
if (result != PPSMC_Result_OK) |
DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); |
#endif |
} |
ci_dpm_powergate_uvd(rdev, true); |
return 0; |
} |
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; |
ci_dpm_powergate_uvd(rdev, false); |
if (!ci_is_smc_running(rdev)) |
return; |
if (pi->thermal_protection) |
ci_enable_thermal_protection(rdev, false); |
ci_enable_power_containment(rdev, false); |
ci_enable_smc_cac(rdev, false); |
ci_enable_didt(rdev, false); |
ci_enable_spread_spectrum(rdev, false); |
ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false); |
ci_stop_dpm(rdev); |
ci_enable_ds_master_switch(rdev, true); |
ci_enable_ulv(rdev, false); |
ci_clear_vc(rdev); |
ci_reset_to_default(rdev); |
ci_dpm_stop_smc(rdev); |
ci_force_switch_to_arb_f0(rdev); |
ci_update_current_ps(rdev, boot_ps); |
} |
int ci_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct radeon_ps *new_ps = &pi->requested_rps; |
struct radeon_ps *old_ps = &pi->current_rps; |
int ret; |
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); |
ret = ci_freeze_sclk_mclk_dpm(rdev); |
if (ret) { |
DRM_ERROR("ci_freeze_sclk_mclk_dpm failed\n"); |
return ret; |
} |
ret = ci_populate_and_upload_sclk_mclk_dpm_levels(rdev, new_ps); |
if (ret) { |
DRM_ERROR("ci_populate_and_upload_sclk_mclk_dpm_levels failed\n"); |
return ret; |
} |
ret = ci_generate_dpm_level_enable_mask(rdev, new_ps); |
if (ret) { |
DRM_ERROR("ci_generate_dpm_level_enable_mask failed\n"); |
return ret; |
} |
ret = ci_update_vce_dpm(rdev, new_ps, old_ps); |
if (ret) { |
DRM_ERROR("ci_update_vce_dpm failed\n"); |
return ret; |
} |
ret = ci_update_sclk_t(rdev); |
if (ret) { |
DRM_ERROR("ci_update_sclk_t failed\n"); |
return ret; |
} |
if (pi->caps_dynamic_ac_timing) { |
ret = ci_update_and_upload_mc_reg_table(rdev); |
if (ret) { |
DRM_ERROR("ci_update_and_upload_mc_reg_table failed\n"); |
return ret; |
} |
} |
ret = ci_program_memory_timing_parameters(rdev); |
if (ret) { |
DRM_ERROR("ci_program_memory_timing_parameters failed\n"); |
return ret; |
} |
ret = ci_unfreeze_sclk_mclk_dpm(rdev); |
if (ret) { |
DRM_ERROR("ci_unfreeze_sclk_mclk_dpm failed\n"); |
return ret; |
} |
ret = ci_upload_dpm_level_enable_mask(rdev); |
if (ret) { |
DRM_ERROR("ci_upload_dpm_level_enable_mask failed\n"); |
return ret; |
} |
if (pi->pcie_performance_request) |
ci_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps); |
return 0; |
} |
int ci_dpm_power_control_set_level(struct radeon_device *rdev) |
{ |
return ci_power_control_set_level(rdev); |
} |
void ci_dpm_reset_asic(struct radeon_device *rdev) |
{ |
ci_set_boot_state(rdev); |
} |
void ci_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
ci_program_display_gap(rdev); |
} |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
struct _ATOM_PPLIB_SI_CLOCK_INFO si; |
struct _ATOM_PPLIB_CI_CLOCK_INFO ci; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void ci_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, |
u8 table_rev) |
{ |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { |
rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); |
rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) |
rdev->pm.dpm.boot_ps = rps; |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void ci_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, int index, |
union pplib_clock_info *clock_info) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_ps *ps = ci_get_ps(rps); |
struct ci_pl *pl = &ps->performance_levels[index]; |
ps->performance_level_count = index + 1; |
pl->sclk = le16_to_cpu(clock_info->ci.usEngineClockLow); |
pl->sclk |= clock_info->ci.ucEngineClockHigh << 16; |
pl->mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow); |
pl->mclk |= clock_info->ci.ucMemoryClockHigh << 16; |
pl->pcie_gen = r600_get_pcie_gen_support(rdev, |
pi->sys_pcie_mask, |
pi->vbios_boot_state.pcie_gen_bootup_value, |
clock_info->ci.ucPCIEGen); |
pl->pcie_lane = r600_get_pcie_lane_support(rdev, |
pi->vbios_boot_state.pcie_lane_bootup_value, |
le16_to_cpu(clock_info->ci.usPCIELane)); |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { |
pi->acpi_pcie_gen = pl->pcie_gen; |
} |
if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) { |
pi->ulv.supported = true; |
pi->ulv.pl = *pl; |
pi->ulv.cg_ulv_parameter = CISLANDS_CGULVPARAMETER_DFLT; |
} |
/* patch up boot state */ |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
pl->mclk = pi->vbios_boot_state.mclk_bootup_value; |
pl->sclk = pi->vbios_boot_state.sclk_bootup_value; |
pl->pcie_gen = pi->vbios_boot_state.pcie_gen_bootup_value; |
pl->pcie_lane = pi->vbios_boot_state.pcie_lane_bootup_value; |
} |
switch (rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { |
case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: |
pi->use_pcie_powersaving_levels = true; |
if (pi->pcie_gen_powersaving.max < pl->pcie_gen) |
pi->pcie_gen_powersaving.max = pl->pcie_gen; |
if (pi->pcie_gen_powersaving.min > pl->pcie_gen) |
pi->pcie_gen_powersaving.min = pl->pcie_gen; |
if (pi->pcie_lane_powersaving.max < pl->pcie_lane) |
pi->pcie_lane_powersaving.max = pl->pcie_lane; |
if (pi->pcie_lane_powersaving.min > pl->pcie_lane) |
pi->pcie_lane_powersaving.min = pl->pcie_lane; |
break; |
case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE: |
pi->use_pcie_performance_levels = true; |
if (pi->pcie_gen_performance.max < pl->pcie_gen) |
pi->pcie_gen_performance.max = pl->pcie_gen; |
if (pi->pcie_gen_performance.min > pl->pcie_gen) |
pi->pcie_gen_performance.min = pl->pcie_gen; |
if (pi->pcie_lane_performance.max < pl->pcie_lane) |
pi->pcie_lane_performance.max = pl->pcie_lane; |
if (pi->pcie_lane_performance.min > pl->pcie_lane) |
pi->pcie_lane_performance.min = pl->pcie_lane; |
break; |
default: |
break; |
} |
} |
static int ci_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i, j, k, non_clock_array_index, clock_array_index; |
union pplib_clock_info *clock_info; |
struct _StateArray *state_array; |
struct _ClockInfoArray *clock_info_array; |
struct _NonClockInfoArray *non_clock_info_array; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
u8 *power_state_offset; |
struct ci_ps *ps; |
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); |
state_array = (struct _StateArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset)); |
clock_info_array = (struct _ClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); |
non_clock_info_array = (struct _NonClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); |
rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * |
state_array->ucNumEntries, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
power_state_offset = (u8 *)state_array->states; |
for (i = 0; i < state_array->ucNumEntries; i++) { |
u8 *idx; |
power_state = (union pplib_power_state *)power_state_offset; |
non_clock_array_index = power_state->v2.nonClockInfoIndex; |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
&non_clock_info_array->nonClockInfo[non_clock_array_index]; |
if (!rdev->pm.power_state[i].clock_info) |
return -EINVAL; |
ps = kzalloc(sizeof(struct ci_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
ci_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info, |
non_clock_info_array->ucEntrySize); |
k = 0; |
idx = (u8 *)&power_state->v2.clockInfoIndex[0]; |
for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { |
clock_array_index = idx[j]; |
if (clock_array_index >= clock_info_array->ucNumEntries) |
continue; |
if (k >= CISLANDS_MAX_HARDWARE_POWERLEVELS) |
break; |
clock_info = (union pplib_clock_info *) |
((u8 *)&clock_info_array->clockInfo[0] + |
(clock_array_index * clock_info_array->ucEntrySize)); |
ci_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], k, |
clock_info); |
k++; |
} |
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; |
} |
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); |
ATOM_FIRMWARE_INFO_V2_2 *firmware_info; |
u8 frev, crev; |
u16 data_offset; |
if (atom_parse_data_header(mode_info->atom_context, index, NULL, |
&frev, &crev, &data_offset)) { |
firmware_info = |
(ATOM_FIRMWARE_INFO_V2_2 *)(mode_info->atom_context->bios + |
data_offset); |
boot_state->mvdd_bootup_value = le16_to_cpu(firmware_info->usBootUpMVDDCVoltage); |
boot_state->vddc_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCVoltage); |
boot_state->vddci_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCIVoltage); |
boot_state->pcie_gen_bootup_value = ci_get_current_pcie_speed(rdev); |
boot_state->pcie_lane_bootup_value = ci_get_current_pcie_lane_number(rdev); |
boot_state->sclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultEngineClock); |
boot_state->mclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultMemoryClock); |
return 0; |
} |
return -EINVAL; |
} |
void ci_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries); |
r600_free_extended_power_table(rdev); |
} |
int ci_dpm_init(struct radeon_device *rdev) |
{ |
int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); |
u16 data_offset, size; |
u8 frev, crev; |
struct ci_power_info *pi; |
int ret; |
u32 mask; |
pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL); |
if (pi == NULL) |
return -ENOMEM; |
rdev->pm.dpm.priv = pi; |
ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); |
if (ret) |
pi->sys_pcie_mask = 0; |
else |
pi->sys_pcie_mask = mask; |
pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID; |
pi->pcie_gen_performance.max = RADEON_PCIE_GEN1; |
pi->pcie_gen_performance.min = RADEON_PCIE_GEN3; |
pi->pcie_gen_powersaving.max = RADEON_PCIE_GEN1; |
pi->pcie_gen_powersaving.min = RADEON_PCIE_GEN3; |
pi->pcie_lane_performance.max = 0; |
pi->pcie_lane_performance.min = 16; |
pi->pcie_lane_powersaving.max = 0; |
pi->pcie_lane_powersaving.min = 16; |
ret = ci_get_vbios_boot_values(rdev, &pi->vbios_boot_state); |
if (ret) { |
ci_dpm_fini(rdev); |
return ret; |
} |
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; |
pi->activity_target[0] = CISLAND_TARGETACTIVITY_DFLT; |
pi->activity_target[1] = CISLAND_TARGETACTIVITY_DFLT; |
pi->activity_target[2] = CISLAND_TARGETACTIVITY_DFLT; |
pi->activity_target[3] = CISLAND_TARGETACTIVITY_DFLT; |
pi->activity_target[4] = CISLAND_TARGETACTIVITY_DFLT; |
pi->activity_target[5] = CISLAND_TARGETACTIVITY_DFLT; |
pi->activity_target[6] = CISLAND_TARGETACTIVITY_DFLT; |
pi->activity_target[7] = CISLAND_TARGETACTIVITY_DFLT; |
pi->mclk_activity_target = CISLAND_MCLK_TARGETACTIVITY_DFLT; |
pi->sclk_dpm_key_disabled = 0; |
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; |
pi->mclk_stutter_mode_threshold = 40000; |
pi->mclk_edc_enable_threshold = 40000; |
pi->mclk_edc_wr_enable_threshold = 40000; |
ci_initialize_powertune_defaults(rdev); |
pi->caps_fps = false; |
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); |
ci_set_private_data_variables_based_on_pptable(rdev); |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = |
kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { |
ci_dpm_fini(rdev); |
return -ENOMEM; |
} |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900; |
rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 4; |
rdev->pm.dpm.dyn_state.sclk_mclk_delta = 15000; |
rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200; |
rdev->pm.dpm.dyn_state.valid_sclk_values.count = 0; |
rdev->pm.dpm.dyn_state.valid_sclk_values.values = NULL; |
rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0; |
rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL; |
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; |
pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_NONE; |
pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_NONE; |
pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_NONE; |
if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT)) |
pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO; |
else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2)) |
pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL) { |
if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT)) |
pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO; |
else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2)) |
pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2; |
else |
rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL) { |
if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT)) |
pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO; |
else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2)) |
pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2; |
else |
rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_MVDDCONTROL; |
} |
pi->vddc_phase_shed_control = true; |
#if defined(CONFIG_ACPI) |
pi->pcie_performance_request = |
radeon_acpi_is_pcie_performance_request_supported(rdev); |
#else |
pi->pcie_performance_request = false; |
#endif |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
pi->caps_sclk_ss_support = true; |
pi->caps_mclk_ss_support = true; |
pi->dynamic_ss = true; |
} else { |
pi->caps_sclk_ss_support = false; |
pi->caps_mclk_ss_support = false; |
pi->dynamic_ss = true; |
} |
if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) |
pi->thermal_protection = true; |
else |
pi->thermal_protection = false; |
pi->caps_dynamic_ac_timing = true; |
pi->uvd_power_gated = false; |
/* make sure dc limits are valid */ |
if ((rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) || |
(rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0)) |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc = |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
return 0; |
} |
void ci_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m) |
{ |
u32 sclk = ci_get_average_sclk_freq(rdev); |
u32 mclk = ci_get_average_mclk_freq(rdev); |
seq_printf(m, "power level avg sclk: %u mclk: %u\n", |
sclk, mclk); |
} |
void ci_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct ci_ps *ps = ci_get_ps(rps); |
struct ci_pl *pl; |
int i; |
r600_dpm_print_class_info(rps->class, rps->class2); |
r600_dpm_print_cap_info(rps->caps); |
printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
for (i = 0; i < ps->performance_level_count; i++) { |
pl = &ps->performance_levels[i]; |
printk("\t\tpower level %d sclk: %u mclk: %u pcie gen: %u pcie lanes: %u\n", |
i, pl->sclk, pl->mclk, pl->pcie_gen + 1, pl->pcie_lane); |
} |
r600_dpm_print_ps_status(rdev, rps); |
} |
u32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps); |
if (low) |
return requested_state->performance_levels[0].sclk; |
else |
return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk; |
} |
u32 ci_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct ci_power_info *pi = ci_get_pi(rdev); |
struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps); |
if (low) |
return requested_state->performance_levels[0].mclk; |
else |
return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk; |
} |
/drivers/video/drm/radeon/ci_dpm.h |
---|
0,0 → 1,332 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __CI_DPM_H__ |
#define __CI_DPM_H__ |
#include "ppsmc.h" |
#define SMU__NUM_SCLK_DPM_STATE 8 |
#define SMU__NUM_MCLK_DPM_LEVELS 6 |
#define SMU__NUM_LCLK_DPM_LEVELS 8 |
#define SMU__NUM_PCIE_DPM_LEVELS 8 |
#include "smu7_discrete.h" |
#define CISLANDS_MAX_HARDWARE_POWERLEVELS 2 |
struct ci_pl { |
u32 mclk; |
u32 sclk; |
enum radeon_pcie_gen pcie_gen; |
u16 pcie_lane; |
}; |
struct ci_ps { |
u16 performance_level_count; |
bool dc_compatible; |
u32 sclk_t; |
struct ci_pl performance_levels[CISLANDS_MAX_HARDWARE_POWERLEVELS]; |
}; |
struct ci_dpm_level { |
bool enabled; |
u32 value; |
u32 param1; |
}; |
#define CISLAND_MAX_DEEPSLEEP_DIVIDER_ID 5 |
#define MAX_REGULAR_DPM_NUMBER 8 |
#define CISLAND_MINIMUM_ENGINE_CLOCK 800 |
struct ci_single_dpm_table { |
u32 count; |
struct ci_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER]; |
}; |
struct ci_dpm_table { |
struct ci_single_dpm_table sclk_table; |
struct ci_single_dpm_table mclk_table; |
struct ci_single_dpm_table pcie_speed_table; |
struct ci_single_dpm_table vddc_table; |
struct ci_single_dpm_table vddci_table; |
struct ci_single_dpm_table mvdd_table; |
}; |
struct ci_mc_reg_entry { |
u32 mclk_max; |
u32 mc_data[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE]; |
}; |
struct ci_mc_reg_table { |
u8 last; |
u8 num_entries; |
u16 valid_flag; |
struct ci_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES]; |
SMU7_Discrete_MCRegisterAddress mc_reg_address[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE]; |
}; |
struct ci_ulv_parm |
{ |
bool supported; |
u32 cg_ulv_parameter; |
u32 volt_change_delay; |
struct ci_pl pl; |
}; |
#define CISLANDS_MAX_LEAKAGE_COUNT 8 |
struct ci_leakage_voltage { |
u16 count; |
u16 leakage_id[CISLANDS_MAX_LEAKAGE_COUNT]; |
u16 actual_voltage[CISLANDS_MAX_LEAKAGE_COUNT]; |
}; |
struct ci_dpm_level_enable_mask { |
u32 uvd_dpm_enable_mask; |
u32 vce_dpm_enable_mask; |
u32 acp_dpm_enable_mask; |
u32 samu_dpm_enable_mask; |
u32 sclk_dpm_enable_mask; |
u32 mclk_dpm_enable_mask; |
u32 pcie_dpm_enable_mask; |
}; |
struct ci_vbios_boot_state |
{ |
u16 mvdd_bootup_value; |
u16 vddc_bootup_value; |
u16 vddci_bootup_value; |
u32 sclk_bootup_value; |
u32 mclk_bootup_value; |
u16 pcie_gen_bootup_value; |
u16 pcie_lane_bootup_value; |
}; |
struct ci_clock_registers { |
u32 cg_spll_func_cntl; |
u32 cg_spll_func_cntl_2; |
u32 cg_spll_func_cntl_3; |
u32 cg_spll_func_cntl_4; |
u32 cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2; |
u32 dll_cntl; |
u32 mclk_pwrmgt_cntl; |
u32 mpll_ad_func_cntl; |
u32 mpll_dq_func_cntl; |
u32 mpll_func_cntl; |
u32 mpll_func_cntl_1; |
u32 mpll_func_cntl_2; |
u32 mpll_ss1; |
u32 mpll_ss2; |
}; |
struct ci_thermal_temperature_setting { |
s32 temperature_low; |
s32 temperature_high; |
s32 temperature_shutdown; |
}; |
struct ci_pcie_perf_range { |
u16 max; |
u16 min; |
}; |
enum ci_pt_config_reg_type { |
CISLANDS_CONFIGREG_MMR = 0, |
CISLANDS_CONFIGREG_SMC_IND, |
CISLANDS_CONFIGREG_DIDT_IND, |
CISLANDS_CONFIGREG_CACHE, |
CISLANDS_CONFIGREG_MAX |
}; |
#define POWERCONTAINMENT_FEATURE_BAPM 0x00000001 |
#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002 |
#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004 |
struct ci_pt_config_reg { |
u32 offset; |
u32 mask; |
u32 shift; |
u32 value; |
enum ci_pt_config_reg_type type; |
}; |
struct ci_pt_defaults { |
u8 svi_load_line_en; |
u8 svi_load_line_vddc; |
u8 tdc_vddc_throttle_release_limit_perc; |
u8 tdc_mawt; |
u8 tdc_waterfall_ctl; |
u8 dte_ambient_temp_base; |
u32 display_cac; |
u32 bapm_temp_gradient; |
u16 bapmti_r[SMU7_DTE_ITERATIONS * SMU7_DTE_SOURCES * SMU7_DTE_SINKS]; |
u16 bapmti_rc[SMU7_DTE_ITERATIONS * SMU7_DTE_SOURCES * SMU7_DTE_SINKS]; |
}; |
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001 |
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002 |
#define DPMTABLE_UPDATE_SCLK 0x00000004 |
#define DPMTABLE_UPDATE_MCLK 0x00000008 |
struct ci_power_info { |
struct ci_dpm_table dpm_table; |
u32 voltage_control; |
u32 mvdd_control; |
u32 vddci_control; |
u32 active_auto_throttle_sources; |
struct ci_clock_registers clock_registers; |
u16 acpi_vddc; |
u16 acpi_vddci; |
enum radeon_pcie_gen force_pcie_gen; |
enum radeon_pcie_gen acpi_pcie_gen; |
struct ci_leakage_voltage vddc_leakage; |
struct ci_leakage_voltage vddci_leakage; |
u16 max_vddc_in_pp_table; |
u16 min_vddc_in_pp_table; |
u16 max_vddci_in_pp_table; |
u16 min_vddci_in_pp_table; |
u32 mclk_strobe_mode_threshold; |
u32 mclk_stutter_mode_threshold; |
u32 mclk_edc_enable_threshold; |
u32 mclk_edc_wr_enable_threshold; |
struct ci_vbios_boot_state vbios_boot_state; |
/* smc offsets */ |
u32 sram_end; |
u32 dpm_table_start; |
u32 soft_regs_start; |
u32 mc_reg_table_start; |
u32 fan_table_start; |
u32 arb_table_start; |
/* smc tables */ |
SMU7_Discrete_DpmTable smc_state_table; |
SMU7_Discrete_MCRegisters smc_mc_reg_table; |
SMU7_Discrete_PmFuses smc_powertune_table; |
/* other stuff */ |
struct ci_mc_reg_table mc_reg_table; |
struct atom_voltage_table vddc_voltage_table; |
struct atom_voltage_table vddci_voltage_table; |
struct atom_voltage_table mvdd_voltage_table; |
struct ci_ulv_parm ulv; |
u32 power_containment_features; |
const struct ci_pt_defaults *powertune_defaults; |
u32 dte_tj_offset; |
bool vddc_phase_shed_control; |
struct ci_thermal_temperature_setting thermal_temp_setting; |
struct ci_dpm_level_enable_mask dpm_level_enable_mask; |
u32 need_update_smu7_dpm_table; |
u32 sclk_dpm_key_disabled; |
u32 mclk_dpm_key_disabled; |
u32 pcie_dpm_key_disabled; |
struct ci_pcie_perf_range pcie_gen_performance; |
struct ci_pcie_perf_range pcie_lane_performance; |
struct ci_pcie_perf_range pcie_gen_powersaving; |
struct ci_pcie_perf_range pcie_lane_powersaving; |
u32 activity_target[SMU7_MAX_LEVELS_GRAPHICS]; |
u32 mclk_activity_target; |
u32 low_sclk_interrupt_t; |
u32 last_mclk_dpm_enable_mask; |
u32 sys_pcie_mask; |
/* caps */ |
bool caps_power_containment; |
bool caps_cac; |
bool caps_sq_ramping; |
bool caps_db_ramping; |
bool caps_td_ramping; |
bool caps_tcp_ramping; |
bool caps_fps; |
bool caps_sclk_ds; |
bool caps_sclk_ss_support; |
bool caps_mclk_ss_support; |
bool caps_uvd_dpm; |
bool caps_vce_dpm; |
bool caps_samu_dpm; |
bool caps_acp_dpm; |
bool caps_automatic_dc_transition; |
bool caps_sclk_throttle_low_notification; |
bool caps_dynamic_ac_timing; |
/* flags */ |
bool thermal_protection; |
bool pcie_performance_request; |
bool dynamic_ss; |
bool dll_default_on; |
bool cac_enabled; |
bool uvd_enabled; |
bool battery_state; |
bool pspp_notify_required; |
bool mem_gddr5; |
bool enable_bapm_feature; |
bool enable_tdc_limit_feature; |
bool enable_pkg_pwr_tracking_feature; |
bool use_pcie_performance_levels; |
bool use_pcie_powersaving_levels; |
bool uvd_power_gated; |
/* driver states */ |
struct radeon_ps current_rps; |
struct ci_ps current_ps; |
struct radeon_ps requested_rps; |
struct ci_ps requested_ps; |
}; |
#define CISLANDS_VOLTAGE_CONTROL_NONE 0x0 |
#define CISLANDS_VOLTAGE_CONTROL_BY_GPIO 0x1 |
#define CISLANDS_VOLTAGE_CONTROL_BY_SVID2 0x2 |
#define CISLANDS_Q88_FORMAT_CONVERSION_UNIT 256 |
#define CISLANDS_VRC_DFLT0 0x3FFFC000 |
#define CISLANDS_VRC_DFLT1 0x000400 |
#define CISLANDS_VRC_DFLT2 0xC00080 |
#define CISLANDS_VRC_DFLT3 0xC00200 |
#define CISLANDS_VRC_DFLT4 0xC01680 |
#define CISLANDS_VRC_DFLT5 0xC00033 |
#define CISLANDS_VRC_DFLT6 0xC00033 |
#define CISLANDS_VRC_DFLT7 0x3FFFC000 |
#define CISLANDS_CGULVPARAMETER_DFLT 0x00040035 |
#define CISLAND_TARGETACTIVITY_DFLT 30 |
#define CISLAND_MCLK_TARGETACTIVITY_DFLT 10 |
#define PCIE_PERF_REQ_REMOVE_REGISTRY 0 |
#define PCIE_PERF_REQ_FORCE_LOWPOWER 1 |
#define PCIE_PERF_REQ_PECI_GEN1 2 |
#define PCIE_PERF_REQ_PECI_GEN2 3 |
#define PCIE_PERF_REQ_PECI_GEN3 4 |
int ci_copy_bytes_to_smc(struct radeon_device *rdev, |
u32 smc_start_address, |
const u8 *src, u32 byte_count, u32 limit); |
void ci_start_smc(struct radeon_device *rdev); |
void ci_reset_smc(struct radeon_device *rdev); |
int ci_program_jump_on_start(struct radeon_device *rdev); |
void ci_stop_smc_clock(struct radeon_device *rdev); |
void ci_start_smc_clock(struct radeon_device *rdev); |
bool ci_is_smc_running(struct radeon_device *rdev); |
PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg); |
PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev); |
int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit); |
int ci_read_smc_sram_dword(struct radeon_device *rdev, |
u32 smc_address, u32 *value, u32 limit); |
int ci_write_smc_sram_dword(struct radeon_device *rdev, |
u32 smc_address, u32 value, u32 limit); |
#endif |
/drivers/video/drm/radeon/ci_smc.c |
---|
0,0 → 1,293 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include <linux/firmware.h> |
#include "drmP.h" |
#include "radeon.h" |
#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) |
{ |
if (smc_address & 3) |
return -EINVAL; |
if ((smc_address + 3) > limit) |
return -EINVAL; |
WREG32(SMC_IND_INDEX_0, smc_address); |
WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); |
return 0; |
} |
int ci_copy_bytes_to_smc(struct radeon_device *rdev, |
u32 smc_start_address, |
const u8 *src, u32 byte_count, u32 limit) |
{ |
unsigned long flags; |
u32 data, original_data; |
u32 addr; |
u32 extra_shift; |
int ret = 0; |
if (smc_start_address & 3) |
return -EINVAL; |
if ((smc_start_address + byte_count) > limit) |
return -EINVAL; |
addr = smc_start_address; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
while (byte_count >= 4) { |
/* SMC address space is BE */ |
data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; |
ret = ci_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
WREG32(SMC_IND_DATA_0, data); |
src += 4; |
byte_count -= 4; |
addr += 4; |
} |
/* RMW for the final bytes */ |
if (byte_count > 0) { |
data = 0; |
ret = ci_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
original_data = RREG32(SMC_IND_DATA_0); |
extra_shift = 8 * (4 - byte_count); |
while (byte_count > 0) { |
data = (data << 8) + *src++; |
byte_count--; |
} |
data <<= extra_shift; |
data |= (original_data & ~((~0UL) << extra_shift)); |
ret = ci_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
WREG32(SMC_IND_DATA_0, data); |
} |
done: |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
void ci_start_smc(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL); |
tmp &= ~RST_REG; |
WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp); |
} |
void ci_reset_smc(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL); |
tmp |= RST_REG; |
WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp); |
} |
int ci_program_jump_on_start(struct radeon_device *rdev) |
{ |
static u8 data[] = { 0xE0, 0x00, 0x80, 0x40 }; |
return ci_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1); |
} |
void ci_stop_smc_clock(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0); |
tmp |= CK_DISABLE; |
WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp); |
} |
void ci_start_smc_clock(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0); |
tmp &= ~CK_DISABLE; |
WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp); |
} |
bool ci_is_smc_running(struct radeon_device *rdev) |
{ |
u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0); |
u32 pc_c = RREG32_SMC(SMC_PC_C); |
if (!(clk & CK_DISABLE) && (0x20100 <= pc_c)) |
return true; |
return false; |
} |
PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg) |
{ |
u32 tmp; |
int i; |
if (!ci_is_smc_running(rdev)) |
return PPSMC_Result_Failed; |
WREG32(SMC_MESSAGE_0, msg); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(SMC_RESP_0); |
if (tmp != 0) |
break; |
udelay(1); |
} |
tmp = RREG32(SMC_RESP_0); |
return (PPSMC_Result)tmp; |
} |
PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev) |
{ |
u32 tmp; |
int i; |
if (!ci_is_smc_running(rdev)) |
return PPSMC_Result_OK; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0); |
if ((tmp & CKEN) == 0) |
break; |
udelay(1); |
} |
return PPSMC_Result_OK; |
} |
int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit) |
{ |
unsigned long flags; |
u32 ucode_start_address; |
u32 ucode_size; |
const u8 *src; |
u32 data; |
if (!rdev->smc_fw) |
return -EINVAL; |
if (rdev->new_fw) { |
const struct smc_firmware_header_v1_0 *hdr = |
(const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data; |
radeon_ucode_print_smc_hdr(&hdr->header); |
ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); |
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); |
src = (const u8 *) |
(rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
} else { |
switch (rdev->family) { |
case CHIP_BONAIRE: |
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(); |
} |
src = (const u8 *)rdev->smc_fw->data; |
} |
if (ucode_size & 3) |
return -EINVAL; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
WREG32(SMC_IND_INDEX_0, ucode_start_address); |
WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); |
while (ucode_size >= 4) { |
/* SMC address space is BE */ |
data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; |
WREG32(SMC_IND_DATA_0, data); |
src += 4; |
ucode_size -= 4; |
} |
WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return 0; |
} |
int ci_read_smc_sram_dword(struct radeon_device *rdev, |
u32 smc_address, u32 *value, u32 limit) |
{ |
unsigned long flags; |
int ret; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
ret = ci_set_smc_sram_address(rdev, smc_address, limit); |
if (ret == 0) |
*value = RREG32(SMC_IND_DATA_0); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
int ci_write_smc_sram_dword(struct radeon_device *rdev, |
u32 smc_address, u32 value, u32 limit) |
{ |
unsigned long flags; |
int ret; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
ret = ci_set_smc_sram_address(rdev, smc_address, limit); |
if (ret == 0) |
WREG32(SMC_IND_DATA_0, value); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
/drivers/video/drm/radeon/cik.c |
---|
0,0 → 1,9694 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include <linux/firmware.h> |
#include <linux/slab.h> |
#include <linux/module.h> |
#include "drmP.h" |
#include "radeon.h" |
#include "radeon_asic.h" |
#include "cikd.h" |
#include "atom.h" |
#include "cik_blit_shaders.h" |
#include "radeon_ucode.h" |
#include "clearstate_ci.h" |
MODULE_FIRMWARE("radeon/BONAIRE_pfp.bin"); |
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/bonaire_pfp.bin"); |
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_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/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_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"); |
MODULE_FIRMWARE("radeon/KAVERI_mec.bin"); |
MODULE_FIRMWARE("radeon/KAVERI_rlc.bin"); |
MODULE_FIRMWARE("radeon/KAVERI_sdma.bin"); |
MODULE_FIRMWARE("radeon/kaveri_pfp.bin"); |
MODULE_FIRMWARE("radeon/kaveri_me.bin"); |
MODULE_FIRMWARE("radeon/kaveri_ce.bin"); |
MODULE_FIRMWARE("radeon/kaveri_mec.bin"); |
MODULE_FIRMWARE("radeon/kaveri_mec2.bin"); |
MODULE_FIRMWARE("radeon/kaveri_rlc.bin"); |
MODULE_FIRMWARE("radeon/kaveri_sdma.bin"); |
MODULE_FIRMWARE("radeon/KABINI_pfp.bin"); |
MODULE_FIRMWARE("radeon/KABINI_me.bin"); |
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/kabini_pfp.bin"); |
MODULE_FIRMWARE("radeon/kabini_me.bin"); |
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"); |
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); |
extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save); |
extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save); |
extern bool evergreen_is_display_hung(struct radeon_device *rdev); |
extern void sumo_rlc_fini(struct radeon_device *rdev); |
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 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); |
/* get temperature in millidegrees */ |
int ci_get_temp(struct radeon_device *rdev) |
{ |
u32 temp; |
int actual_temp = 0; |
temp = (RREG32_SMC(CG_MULT_THERMAL_STATUS) & CTF_TEMP_MASK) >> |
CTF_TEMP_SHIFT; |
if (temp & 0x200) |
actual_temp = 255; |
else |
actual_temp = temp & 0x1ff; |
actual_temp = actual_temp * 1000; |
return actual_temp; |
} |
/* get temperature in millidegrees */ |
int kv_get_temp(struct radeon_device *rdev) |
{ |
u32 temp; |
int actual_temp = 0; |
temp = RREG32_SMC(0xC0300E0C); |
if (temp) |
actual_temp = (temp / 8) - 49; |
else |
actual_temp = 0; |
actual_temp = actual_temp * 1000; |
return actual_temp; |
} |
/* |
* Indirect registers accessor |
*/ |
u32 cik_pciep_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->pciep_idx_lock, flags); |
WREG32(PCIE_INDEX, reg); |
(void)RREG32(PCIE_INDEX); |
r = RREG32(PCIE_DATA); |
spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags); |
return r; |
} |
void cik_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->pciep_idx_lock, flags); |
WREG32(PCIE_INDEX, reg); |
(void)RREG32(PCIE_INDEX); |
WREG32(PCIE_DATA, v); |
(void)RREG32(PCIE_DATA); |
spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags); |
} |
static const u32 spectre_rlc_save_restore_register_list[] = |
{ |
(0x0e00 << 16) | (0xc12c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc140 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc150 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc15c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc168 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc170 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc178 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc204 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2b4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2b8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2bc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2c0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8228 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x829c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x869c >> 2), |
0x00000000, |
(0x0600 << 16) | (0x98f4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x98f8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9900 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc260 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x90e8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c000 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c00c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c1c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9700 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x8e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x9e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0xae00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0xbe00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x89bc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8900 >> 2), |
0x00000000, |
0x3, |
(0x0e00 << 16) | (0xc130 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc134 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc1fc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc208 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc264 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc268 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc26c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc270 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc274 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc278 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc27c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc280 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc284 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc288 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc28c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc290 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc294 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc298 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc29c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2a0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2a4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2a8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2ac >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2b0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x301d0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30238 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30250 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30254 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30258 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3025c >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x8e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x9e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0xae00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0xbe00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x8e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x9e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0xae00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0xbe00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x8e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x9e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0xae00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0xbe00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x8e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x9e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0xae00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0xbe00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x8e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x9e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0xae00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0xbe00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc99c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9834 >> 2), |
0x00000000, |
(0x0000 << 16) | (0x30f00 >> 2), |
0x00000000, |
(0x0001 << 16) | (0x30f00 >> 2), |
0x00000000, |
(0x0000 << 16) | (0x30f04 >> 2), |
0x00000000, |
(0x0001 << 16) | (0x30f04 >> 2), |
0x00000000, |
(0x0000 << 16) | (0x30f08 >> 2), |
0x00000000, |
(0x0001 << 16) | (0x30f08 >> 2), |
0x00000000, |
(0x0000 << 16) | (0x30f0c >> 2), |
0x00000000, |
(0x0001 << 16) | (0x30f0c >> 2), |
0x00000000, |
(0x0600 << 16) | (0x9b7c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8a14 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8a18 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a00 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8bf0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8bcc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8b24 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30a04 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a10 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a14 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a18 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a2c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc700 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc704 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc708 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc768 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc770 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc774 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc778 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc77c >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc780 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc784 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc788 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc78c >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc798 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc79c >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc7a0 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc7a4 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc7a8 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc7ac >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc7b0 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc7b4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9100 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c010 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92a8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92ac >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92b4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92b8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92bc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92c0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92c4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92c8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92cc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x92d0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c00 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c04 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c20 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c38 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c3c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xae00 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9604 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac08 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac0c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac10 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac14 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac58 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac68 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac6c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac70 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac74 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac78 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac7c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac80 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac84 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac88 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac8c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x970c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9714 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9718 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x971c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x8e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x9e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0xae00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0xbe00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xcd10 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xcd14 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88b0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88b4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88b8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88bc >> 2), |
0x00000000, |
(0x0400 << 16) | (0x89c0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88c4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88c8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88d0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88d4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88d8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8980 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30938 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3093c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30940 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x89a0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30900 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30904 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x89b4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c210 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c214 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c218 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8904 >> 2), |
0x00000000, |
0x5, |
(0x0e00 << 16) | (0x8c28 >> 2), |
(0x0e00 << 16) | (0x8c2c >> 2), |
(0x0e00 << 16) | (0x8c30 >> 2), |
(0x0e00 << 16) | (0x8c34 >> 2), |
(0x0e00 << 16) | (0x9600 >> 2), |
}; |
static const u32 kalindi_rlc_save_restore_register_list[] = |
{ |
(0x0e00 << 16) | (0xc12c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc140 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc150 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc15c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc168 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc170 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc204 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2b4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2b8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2bc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2c0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8228 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x829c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x869c >> 2), |
0x00000000, |
(0x0600 << 16) | (0x98f4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x98f8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9900 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc260 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x90e8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c000 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c00c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c1c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9700 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xcd20 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x89bc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8900 >> 2), |
0x00000000, |
0x3, |
(0x0e00 << 16) | (0xc130 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc134 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc1fc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc208 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc264 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc268 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc26c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc270 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc274 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc28c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc290 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc294 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc298 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2a0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2a4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2a8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc2ac >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x301d0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30238 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30250 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30254 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30258 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3025c >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc900 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc904 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc908 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc90c >> 2), |
0x00000000, |
(0x4e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0xc910 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc99c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9834 >> 2), |
0x00000000, |
(0x0000 << 16) | (0x30f00 >> 2), |
0x00000000, |
(0x0000 << 16) | (0x30f04 >> 2), |
0x00000000, |
(0x0000 << 16) | (0x30f08 >> 2), |
0x00000000, |
(0x0000 << 16) | (0x30f0c >> 2), |
0x00000000, |
(0x0600 << 16) | (0x9b7c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8a14 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8a18 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a00 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8bf0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8bcc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8b24 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30a04 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a10 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a14 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a18 >> 2), |
0x00000000, |
(0x0600 << 16) | (0x30a2c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc700 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc704 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc708 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xc768 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc770 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc774 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc798 >> 2), |
0x00000000, |
(0x0400 << 16) | (0xc79c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9100 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c010 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c00 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c04 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c20 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c38 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8c3c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xae00 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9604 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac08 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac0c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac10 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac14 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac58 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac68 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac6c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac70 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac74 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac78 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac7c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac80 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac84 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac88 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xac8c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x970c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9714 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x9718 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x971c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x4e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x5e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x6e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x7e00 << 16) | (0x31068 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xcd10 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0xcd14 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88b0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88b4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88b8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88bc >> 2), |
0x00000000, |
(0x0400 << 16) | (0x89c0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88c4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88c8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88d0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88d4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x88d8 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8980 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30938 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3093c >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30940 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x89a0 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30900 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x30904 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x89b4 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3e1fc >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c210 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c214 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x3c218 >> 2), |
0x00000000, |
(0x0e00 << 16) | (0x8904 >> 2), |
0x00000000, |
0x5, |
(0x0e00 << 16) | (0x8c28 >> 2), |
(0x0e00 << 16) | (0x8c2c >> 2), |
(0x0e00 << 16) | (0x8c30 >> 2), |
(0x0e00 << 16) | (0x8c34 >> 2), |
(0x0e00 << 16) | (0x9600 >> 2), |
}; |
static const u32 bonaire_golden_spm_registers[] = |
{ |
0x30800, 0xe0ffffff, 0xe0000000 |
}; |
static const u32 bonaire_golden_common_registers[] = |
{ |
0xc770, 0xffffffff, 0x00000800, |
0xc774, 0xffffffff, 0x00000800, |
0xc798, 0xffffffff, 0x00007fbf, |
0xc79c, 0xffffffff, 0x00007faf |
}; |
static const u32 bonaire_golden_registers[] = |
{ |
0x3354, 0x00000333, 0x00000333, |
0x3350, 0x000c0fc0, 0x00040200, |
0x9a10, 0x00010000, 0x00058208, |
0x3c000, 0xffff1fff, 0x00140000, |
0x3c200, 0xfdfc0fff, 0x00000100, |
0x3c234, 0x40000000, 0x40000200, |
0x9830, 0xffffffff, 0x00000000, |
0x9834, 0xf00fffff, 0x00000400, |
0x9838, 0x0002021c, 0x00020200, |
0xc78, 0x00000080, 0x00000000, |
0x5bb0, 0x000000f0, 0x00000070, |
0x5bc0, 0xf0311fff, 0x80300000, |
0x98f8, 0x73773777, 0x12010001, |
0x350c, 0x00810000, 0x408af000, |
0x7030, 0x31000111, 0x00000011, |
0x2f48, 0x73773777, 0x12010001, |
0x220c, 0x00007fb6, 0x0021a1b1, |
0x2210, 0x00007fb6, 0x002021b1, |
0x2180, 0x00007fb6, 0x00002191, |
0x2218, 0x00007fb6, 0x002121b1, |
0x221c, 0x00007fb6, 0x002021b1, |
0x21dc, 0x00007fb6, 0x00002191, |
0x21e0, 0x00007fb6, 0x00002191, |
0x3628, 0x0000003f, 0x0000000a, |
0x362c, 0x0000003f, 0x0000000a, |
0x2ae4, 0x00073ffe, 0x000022a2, |
0x240c, 0x000007ff, 0x00000000, |
0x8a14, 0xf000003f, 0x00000007, |
0x8bf0, 0x00002001, 0x00000001, |
0x8b24, 0xffffffff, 0x00ffffff, |
0x30a04, 0x0000ff0f, 0x00000000, |
0x28a4c, 0x07ffffff, 0x06000000, |
0x4d8, 0x00000fff, 0x00000100, |
0x3e78, 0x00000001, 0x00000002, |
0x9100, 0x03000000, 0x0362c688, |
0x8c00, 0x000000ff, 0x00000001, |
0xe40, 0x00001fff, 0x00001fff, |
0x9060, 0x0000007f, 0x00000020, |
0x9508, 0x00010000, 0x00010000, |
0xac14, 0x000003ff, 0x000000f3, |
0xac0c, 0xffffffff, 0x00001032 |
}; |
static const u32 bonaire_mgcg_cgcg_init[] = |
{ |
0xc420, 0xffffffff, 0xfffffffc, |
0x30800, 0xffffffff, 0xe0000000, |
0x3c2a0, 0xffffffff, 0x00000100, |
0x3c208, 0xffffffff, 0x00000100, |
0x3c2c0, 0xffffffff, 0xc0000100, |
0x3c2c8, 0xffffffff, 0xc0000100, |
0x3c2c4, 0xffffffff, 0xc0000100, |
0x55e4, 0xffffffff, 0x00600100, |
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, |
0x3c000, 0xffffffff, 0x96e00200, |
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 spectre_golden_spm_registers[] = |
{ |
0x30800, 0xe0ffffff, 0xe0000000 |
}; |
static const u32 spectre_golden_common_registers[] = |
{ |
0xc770, 0xffffffff, 0x00000800, |
0xc774, 0xffffffff, 0x00000800, |
0xc798, 0xffffffff, 0x00007fbf, |
0xc79c, 0xffffffff, 0x00007faf |
}; |
static const u32 spectre_golden_registers[] = |
{ |
0x3c000, 0xffff1fff, 0x96940200, |
0x3c00c, 0xffff0001, 0xff000000, |
0x3c200, 0xfffc0fff, 0x00000100, |
0x6ed8, 0x00010101, 0x00010000, |
0x9834, 0xf00fffff, 0x00000400, |
0x9838, 0xfffffffc, 0x00020200, |
0x5bb0, 0x000000f0, 0x00000070, |
0x5bc0, 0xf0311fff, 0x80300000, |
0x98f8, 0x73773777, 0x12010001, |
0x9b7c, 0x00ff0000, 0x00fc0000, |
0x2f48, 0x73773777, 0x12010001, |
0x8a14, 0xf000003f, 0x00000007, |
0x8b24, 0xffffffff, 0x00ffffff, |
0x28350, 0x3f3f3fff, 0x00000082, |
0x28354, 0x0000003f, 0x00000000, |
0x3e78, 0x00000001, 0x00000002, |
0x913c, 0xffff03df, 0x00000004, |
0xc768, 0x00000008, 0x00000008, |
0x8c00, 0x000008ff, 0x00000800, |
0x9508, 0x00010000, 0x00010000, |
0xac0c, 0xffffffff, 0x54763210, |
0x214f8, 0x01ff01ff, 0x00000002, |
0x21498, 0x007ff800, 0x00200000, |
0x2015c, 0xffffffff, 0x00000f40, |
0x30934, 0xffffffff, 0x00000001 |
}; |
static const u32 spectre_mgcg_cgcg_init[] = |
{ |
0xc420, 0xffffffff, 0xfffffffc, |
0x30800, 0xffffffff, 0xe0000000, |
0x3c2a0, 0xffffffff, 0x00000100, |
0x3c208, 0xffffffff, 0x00000100, |
0x3c2c0, 0xffffffff, 0x00000100, |
0x3c2c8, 0xffffffff, 0x00000100, |
0x3c2c4, 0xffffffff, 0x00000100, |
0x55e4, 0xffffffff, 0x00600100, |
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, |
0x3c000, 0xffffffff, 0x96e00200, |
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 kalindi_golden_spm_registers[] = |
{ |
0x30800, 0xe0ffffff, 0xe0000000 |
}; |
static const u32 kalindi_golden_common_registers[] = |
{ |
0xc770, 0xffffffff, 0x00000800, |
0xc774, 0xffffffff, 0x00000800, |
0xc798, 0xffffffff, 0x00007fbf, |
0xc79c, 0xffffffff, 0x00007faf |
}; |
static const u32 kalindi_golden_registers[] = |
{ |
0x3c000, 0xffffdfff, 0x6e944040, |
0x55e4, 0xff607fff, 0xfc000100, |
0x3c220, 0xff000fff, 0x00000100, |
0x3c224, 0xff000fff, 0x00000100, |
0x3c200, 0xfffc0fff, 0x00000100, |
0x6ed8, 0x00010101, 0x00010000, |
0x9830, 0xffffffff, 0x00000000, |
0x9834, 0xf00fffff, 0x00000400, |
0x5bb0, 0x000000f0, 0x00000070, |
0x5bc0, 0xf0311fff, 0x80300000, |
0x98f8, 0x73773777, 0x12010001, |
0x98fc, 0xffffffff, 0x00000010, |
0x9b7c, 0x00ff0000, 0x00fc0000, |
0x8030, 0x00001f0f, 0x0000100a, |
0x2f48, 0x73773777, 0x12010001, |
0x2408, 0x000fffff, 0x000c007f, |
0x8a14, 0xf000003f, 0x00000007, |
0x8b24, 0x3fff3fff, 0x00ffcfff, |
0x30a04, 0x0000ff0f, 0x00000000, |
0x28a4c, 0x07ffffff, 0x06000000, |
0x4d8, 0x00000fff, 0x00000100, |
0x3e78, 0x00000001, 0x00000002, |
0xc768, 0x00000008, 0x00000008, |
0x8c00, 0x000000ff, 0x00000003, |
0x214f8, 0x01ff01ff, 0x00000002, |
0x21498, 0x007ff800, 0x00200000, |
0x2015c, 0xffffffff, 0x00000f40, |
0x88c4, 0x001f3ae3, 0x00000082, |
0x88d4, 0x0000001f, 0x00000010, |
0x30934, 0xffffffff, 0x00000000 |
}; |
static const u32 kalindi_mgcg_cgcg_init[] = |
{ |
0xc420, 0xffffffff, 0xfffffffc, |
0x30800, 0xffffffff, 0xe0000000, |
0x3c2a0, 0xffffffff, 0x00000100, |
0x3c208, 0xffffffff, 0x00000100, |
0x3c2c0, 0xffffffff, 0x00000100, |
0x3c2c8, 0xffffffff, 0x00000100, |
0x3c2c4, 0xffffffff, 0x00000100, |
0x55e4, 0xffffffff, 0x00600100, |
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, |
0x3c000, 0xffffffff, 0x96e00200, |
0x8708, 0xffffffff, 0x00900100, |
0xc424, 0xffffffff, 0x0020003f, |
0x38, 0xffffffff, 0x0140001c, |
0x3c, 0x000f0000, 0x000f0000, |
0x220, 0xffffffff, 0xC060000C, |
0x224, 0xc0000fff, 0x00000100, |
0x20a8, 0xffffffff, 0x00000104, |
0x55e4, 0xff000fff, 0x00000100, |
0x30cc, 0xc0000fff, 0x00000104, |
0xc1e4, 0x00000001, 0x00000001, |
0xd00c, 0xff000ff0, 0x00000100, |
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) { |
case CHIP_BONAIRE: |
radeon_program_register_sequence(rdev, |
bonaire_mgcg_cgcg_init, |
(const u32)ARRAY_SIZE(bonaire_mgcg_cgcg_init)); |
radeon_program_register_sequence(rdev, |
bonaire_golden_registers, |
(const u32)ARRAY_SIZE(bonaire_golden_registers)); |
radeon_program_register_sequence(rdev, |
bonaire_golden_common_registers, |
(const u32)ARRAY_SIZE(bonaire_golden_common_registers)); |
radeon_program_register_sequence(rdev, |
bonaire_golden_spm_registers, |
(const u32)ARRAY_SIZE(bonaire_golden_spm_registers)); |
break; |
case CHIP_KABINI: |
radeon_program_register_sequence(rdev, |
kalindi_mgcg_cgcg_init, |
(const u32)ARRAY_SIZE(kalindi_mgcg_cgcg_init)); |
radeon_program_register_sequence(rdev, |
kalindi_golden_registers, |
(const u32)ARRAY_SIZE(kalindi_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_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, |
(const u32)ARRAY_SIZE(spectre_mgcg_cgcg_init)); |
radeon_program_register_sequence(rdev, |
spectre_golden_registers, |
(const u32)ARRAY_SIZE(spectre_golden_registers)); |
radeon_program_register_sequence(rdev, |
spectre_golden_common_registers, |
(const u32)ARRAY_SIZE(spectre_golden_common_registers)); |
radeon_program_register_sequence(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; |
} |
} |
/** |
* cik_get_xclk - get the xclk |
* |
* @rdev: radeon_device pointer |
* |
* Returns the reference clock used by the gfx engine |
* (CIK). |
*/ |
u32 cik_get_xclk(struct radeon_device *rdev) |
{ |
u32 reference_clock = rdev->clock.spll.reference_freq; |
if (rdev->flags & RADEON_IS_IGP) { |
if (RREG32_SMC(GENERAL_PWRMGT) & GPU_COUNTER_CLK) |
return reference_clock / 2; |
} else { |
if (RREG32_SMC(CG_CLKPIN_CNTL) & XTALIN_DIVIDE) |
return reference_clock / 4; |
} |
return reference_clock; |
} |
/** |
* cik_mm_rdoorbell - read a doorbell dword |
* |
* @rdev: radeon_device pointer |
* @index: doorbell index |
* |
* Returns the value in the doorbell aperture at the |
* requested doorbell index (CIK). |
*/ |
u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 index) |
{ |
if (index < rdev->doorbell.num_doorbells) { |
return readl(rdev->doorbell.ptr + index); |
} else { |
DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index); |
return 0; |
} |
} |
/** |
* cik_mm_wdoorbell - write a doorbell dword |
* |
* @rdev: radeon_device pointer |
* @index: doorbell index |
* @v: value to write |
* |
* Writes @v to the doorbell aperture at the |
* requested doorbell index (CIK). |
*/ |
void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v) |
{ |
if (index < rdev->doorbell.num_doorbells) { |
writel(v, rdev->doorbell.ptr + index); |
} else { |
DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index); |
} |
} |
#define BONAIRE_IO_MC_REGS_SIZE 36 |
static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] = |
{ |
{0x00000070, 0x04400000}, |
{0x00000071, 0x80c01803}, |
{0x00000072, 0x00004004}, |
{0x00000073, 0x00000100}, |
{0x00000074, 0x00ff0000}, |
{0x00000075, 0x34000000}, |
{0x00000076, 0x08000014}, |
{0x00000077, 0x00cc08ec}, |
{0x00000078, 0x00000400}, |
{0x00000079, 0x00000000}, |
{0x0000007a, 0x04090000}, |
{0x0000007c, 0x00000000}, |
{0x0000007e, 0x4408a8e8}, |
{0x0000007f, 0x00000304}, |
{0x00000080, 0x00000000}, |
{0x00000082, 0x00000001}, |
{0x00000083, 0x00000002}, |
{0x00000084, 0xf3e4f400}, |
{0x00000085, 0x052024e3}, |
{0x00000087, 0x00000000}, |
{0x00000088, 0x01000000}, |
{0x0000008a, 0x1c0a0000}, |
{0x0000008b, 0xff010000}, |
{0x0000008d, 0xffffefff}, |
{0x0000008e, 0xfff3efff}, |
{0x0000008f, 0xfff3efbf}, |
{0x00000092, 0xf7ffffff}, |
{0x00000093, 0xffffff7f}, |
{0x00000095, 0x00101101}, |
{0x00000096, 0x00000fff}, |
{0x00000097, 0x00116fff}, |
{0x00000098, 0x60010000}, |
{0x00000099, 0x10010000}, |
{0x0000009a, 0x00006000}, |
{0x0000009b, 0x00001000}, |
{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 |
* |
* @rdev: radeon_device pointer |
* @me: selected ME (micro engine) |
* @pipe: pipe |
* @queue: queue |
* @vmid: VMID |
* |
* Switches the currently active registers instances. Some |
* registers are instanced per VMID, others are instanced per |
* me/pipe/queue combination. |
*/ |
static void cik_srbm_select(struct radeon_device *rdev, |
u32 me, u32 pipe, u32 queue, u32 vmid) |
{ |
u32 srbm_gfx_cntl = (PIPEID(pipe & 0x3) | |
MEID(me & 0x3) | |
VMID(vmid & 0xf) | |
QUEUEID(queue & 0x7)); |
WREG32(SRBM_GFX_CNTL, srbm_gfx_cntl); |
} |
/* ucode loading */ |
/** |
* ci_mc_load_microcode - load MC ucode into the hw |
* |
* @rdev: radeon_device pointer |
* |
* Load the GDDR MC ucode into the hw (CIK). |
* Returns 0 on success, error on failure. |
*/ |
int ci_mc_load_microcode(struct radeon_device *rdev) |
{ |
const __be32 *fw_data = NULL; |
const __le32 *new_fw_data = NULL; |
u32 running, blackout = 0; |
u32 *io_mc_regs = NULL; |
const __le32 *new_io_mc_regs = NULL; |
int i, regs_size, ucode_size; |
if (!rdev->mc_fw) |
return -EINVAL; |
if (rdev->new_fw) { |
const struct mc_firmware_header_v1_0 *hdr = |
(const struct mc_firmware_header_v1_0 *)rdev->mc_fw->data; |
radeon_ucode_print_mc_hdr(&hdr->header); |
regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2); |
new_io_mc_regs = (const __le32 *) |
(rdev->mc_fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); |
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; |
new_fw_data = (const __le32 *) |
(rdev->mc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
} else { |
ucode_size = rdev->mc_fw->size / 4; |
switch (rdev->family) { |
case CHIP_BONAIRE: |
io_mc_regs = (u32 *)&bonaire_io_mc_regs; |
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; |
} |
fw_data = (const __be32 *)rdev->mc_fw->data; |
} |
running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; |
if (running == 0) { |
if (running) { |
blackout = RREG32(MC_SHARED_BLACKOUT_CNTL); |
WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1); |
} |
/* reset the engine and set to writable */ |
WREG32(MC_SEQ_SUP_CNTL, 0x00000008); |
WREG32(MC_SEQ_SUP_CNTL, 0x00000010); |
/* load mc io regs */ |
for (i = 0; i < regs_size; i++) { |
if (rdev->new_fw) { |
WREG32(MC_SEQ_IO_DEBUG_INDEX, le32_to_cpup(new_io_mc_regs++)); |
WREG32(MC_SEQ_IO_DEBUG_DATA, le32_to_cpup(new_io_mc_regs++)); |
} else { |
WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]); |
WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); |
} |
} |
/* load the MC ucode */ |
for (i = 0; i < ucode_size; i++) { |
if (rdev->new_fw) |
WREG32(MC_SEQ_SUP_PGM, le32_to_cpup(new_fw_data++)); |
else |
WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++)); |
} |
/* put the engine back into the active state */ |
WREG32(MC_SEQ_SUP_CNTL, 0x00000008); |
WREG32(MC_SEQ_SUP_CNTL, 0x00000004); |
WREG32(MC_SEQ_SUP_CNTL, 0x00000001); |
/* wait for training to complete */ |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D0) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D1) |
break; |
udelay(1); |
} |
if (running) |
WREG32(MC_SHARED_BLACKOUT_CNTL, blackout); |
} |
return 0; |
} |
/** |
* cik_init_microcode - load ucode images from disk |
* |
* @rdev: radeon_device pointer |
* |
* Use the firmware interface to load the ucode images into |
* the driver (not loaded into hw). |
* Returns 0 on success, error on failure. |
*/ |
static int cik_init_microcode(struct radeon_device *rdev) |
{ |
const char *chip_name; |
const char *new_chip_name; |
size_t pfp_req_size, me_req_size, ce_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 new_fw = 0; |
int err; |
int num_fw; |
DRM_DEBUG("\n"); |
switch (rdev->family) { |
case CHIP_BONAIRE: |
chip_name = "BONAIRE"; |
new_chip_name = "bonaire"; |
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 = 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); |
num_fw = 8; |
break; |
case CHIP_HAWAII: |
chip_name = "HAWAII"; |
new_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); |
num_fw = 8; |
break; |
case CHIP_KAVERI: |
chip_name = "KAVERI"; |
new_chip_name = "kaveri"; |
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 = KV_RLC_UCODE_SIZE * 4; |
sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; |
num_fw = 7; |
break; |
case CHIP_KABINI: |
chip_name = "KABINI"; |
new_chip_name = "kabini"; |
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 = KB_RLC_UCODE_SIZE * 4; |
sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; |
num_fw = 6; |
break; |
case CHIP_MULLINS: |
chip_name = "MULLINS"; |
new_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; |
num_fw = 6; |
break; |
default: BUG(); |
} |
DRM_INFO("Loading %s Microcode\n", new_chip_name); |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", new_chip_name); |
err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); |
err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->pfp_fw->size != pfp_req_size) { |
printk(KERN_ERR |
"cik_cp: Bogus length %zu in firmware \"%s\"\n", |
rdev->pfp_fw->size, fw_name); |
err = -EINVAL; |
goto out; |
} |
} else { |
err = radeon_ucode_validate(rdev->pfp_fw); |
if (err) { |
printk(KERN_ERR |
"cik_fw: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", new_chip_name); |
err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); |
err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->me_fw->size != me_req_size) { |
printk(KERN_ERR |
"cik_cp: Bogus length %zu in firmware \"%s\"\n", |
rdev->me_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->me_fw); |
if (err) { |
printk(KERN_ERR |
"cik_fw: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", new_chip_name); |
err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); |
err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->ce_fw->size != ce_req_size) { |
printk(KERN_ERR |
"cik_cp: Bogus length %zu in firmware \"%s\"\n", |
rdev->ce_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->ce_fw); |
if (err) { |
printk(KERN_ERR |
"cik_fw: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", new_chip_name); |
err = request_firmware(&rdev->mec_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name); |
err = request_firmware(&rdev->mec_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->mec_fw->size != mec_req_size) { |
printk(KERN_ERR |
"cik_cp: Bogus length %zu in firmware \"%s\"\n", |
rdev->mec_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->mec_fw); |
if (err) { |
printk(KERN_ERR |
"cik_fw: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
if (rdev->family == CHIP_KAVERI) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec2.bin", new_chip_name); |
err = request_firmware(&rdev->mec2_fw, fw_name, rdev->dev); |
if (err) { |
goto out; |
} else { |
err = radeon_ucode_validate(rdev->mec2_fw); |
if (err) { |
goto out; |
} else { |
new_fw++; |
} |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", new_chip_name); |
err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); |
err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->rlc_fw->size != rlc_req_size) { |
printk(KERN_ERR |
"cik_rlc: Bogus length %zu in firmware \"%s\"\n", |
rdev->rlc_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->rlc_fw); |
if (err) { |
printk(KERN_ERR |
"cik_fw: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", new_chip_name); |
err = request_firmware(&rdev->sdma_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name); |
err = request_firmware(&rdev->sdma_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->sdma_fw->size != sdma_req_size) { |
printk(KERN_ERR |
"cik_sdma: Bogus length %zu in firmware \"%s\"\n", |
rdev->sdma_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->sdma_fw); |
if (err) { |
printk(KERN_ERR |
"cik_fw: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
/* No SMC, MC ucode on APUs */ |
if (!(rdev->flags & RADEON_IS_IGP)) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name); |
err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name); |
err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); |
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); |
} else { |
err = radeon_ucode_validate(rdev->mc_fw); |
if (err) { |
printk(KERN_ERR |
"cik_fw: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", new_chip_name); |
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); |
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); |
if (err) { |
printk(KERN_ERR |
"smc: error loading firmware \"%s\"\n", |
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", |
rdev->smc_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->smc_fw); |
if (err) { |
printk(KERN_ERR |
"cik_fw: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
} |
if (new_fw == 0) { |
rdev->new_fw = false; |
} else if (new_fw < num_fw) { |
printk(KERN_ERR "ci_fw: mixing new and old firmware!\n"); |
err = -EINVAL; |
} else { |
rdev->new_fw = true; |
} |
out: |
if (err) { |
if (err != -EINVAL) |
printk(KERN_ERR |
"cik_cp: Failed to load firmware \"%s\"\n", |
fw_name); |
release_firmware(rdev->pfp_fw); |
rdev->pfp_fw = NULL; |
release_firmware(rdev->me_fw); |
rdev->me_fw = NULL; |
release_firmware(rdev->ce_fw); |
rdev->ce_fw = NULL; |
release_firmware(rdev->mec_fw); |
rdev->mec_fw = NULL; |
release_firmware(rdev->mec2_fw); |
rdev->mec2_fw = NULL; |
release_firmware(rdev->rlc_fw); |
rdev->rlc_fw = NULL; |
release_firmware(rdev->sdma_fw); |
rdev->sdma_fw = NULL; |
release_firmware(rdev->mc_fw); |
rdev->mc_fw = NULL; |
release_firmware(rdev->smc_fw); |
rdev->smc_fw = NULL; |
} |
return err; |
} |
/* |
* Core functions |
*/ |
/** |
* cik_tiling_mode_table_init - init the hw tiling table |
* |
* @rdev: radeon_device pointer |
* |
* Starting with SI, the tiling setup is done globally in a |
* set of 32 tiling modes. Rather than selecting each set of |
* parameters per surface as on older asics, we just select |
* which index in the tiling table we want to use, and the |
* surface uses those parameters (CIK). |
*/ |
static void cik_tiling_mode_table_init(struct radeon_device *rdev) |
{ |
const u32 num_tile_mode_states = 32; |
const u32 num_secondary_tile_mode_states = 16; |
u32 reg_offset, gb_tile_moden, split_equal_to_row_size; |
u32 num_pipe_configs; |
u32 num_rbs = rdev->config.cik.max_backends_per_se * |
rdev->config.cik.max_shader_engines; |
switch (rdev->config.cik.mem_row_size_in_kb) { |
case 1: |
split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_1KB; |
break; |
case 2: |
default: |
split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_2KB; |
break; |
case 4: |
split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_4KB; |
break; |
} |
num_pipe_configs = rdev->config.cik.max_tile_pipes; |
if (num_pipe_configs > 8) |
num_pipe_configs = 16; |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P8_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_P8_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_P8_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_P8_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_P8_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_P8_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_P8_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_P8_32x32_16x16) | |
TILE_SPLIT(split_equal_to_row_size)); |
break; |
case 8: |
gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | |
PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P8_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_P8_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_P8_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_P8_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_P8_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_P8_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_P8_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_P8_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_P8_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_P8_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_P8_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_4) | |
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_2) | |
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_2) | |
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_8) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
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_4) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
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_2) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | |
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_2) | |
NUM_BANKS(ADDR_SURF_16_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_8_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_4_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 == 4) { |
if (num_rbs == 4) { |
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_P4_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_P4_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_P4_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_P4_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_P4_16x16) | |
TILE_SPLIT(split_equal_to_row_size)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P4_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_P4_16x16) | |
TILE_SPLIT(split_equal_to_row_size)); |
break; |
case 8: |
gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | |
PIPE_CONFIG(ADDR_SURF_P4_16x16)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P4_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_P4_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_P4_16x16) | |
SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P4_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_P4_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_P4_16x16) | |
SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P4_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_P4_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_P4_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); |
} |
} else if (num_rbs < 4) { |
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_P4_8x16) | |
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_P4_8x16) | |
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_P4_8x16) | |
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_P4_8x16) | |
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_P4_8x16) | |
TILE_SPLIT(split_equal_to_row_size)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P4_8x16) | |
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_P4_8x16) | |
TILE_SPLIT(split_equal_to_row_size)); |
break; |
case 8: |
gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | |
PIPE_CONFIG(ADDR_SURF_P4_8x16)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P4_8x16) | |
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_P4_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_P4_8x16) | |
SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P4_8x16) | |
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_P4_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_P4_8x16) | |
SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P4_8x16) | |
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_P4_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_P4_8x16) | |
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_4) | |
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_4) | |
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_2) | |
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_2) | |
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_2) | |
NUM_BANKS(ADDR_SURF_16_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_2) | |
NUM_BANKS(ADDR_SURF_8_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_4_BANK)); |
break; |
case 8: |
gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
NUM_BANKS(ADDR_SURF_16_BANK)); |
break; |
case 9: |
gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
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_4) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
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_2) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
NUM_BANKS(ADDR_SURF_16_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_2) | |
NUM_BANKS(ADDR_SURF_16_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_2) | |
NUM_BANKS(ADDR_SURF_8_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_4_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 == 2) { |
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_P2) | |
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_P2) | |
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_P2) | |
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_P2) | |
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_P2) | |
TILE_SPLIT(split_equal_to_row_size)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P2) | |
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_P2) | |
TILE_SPLIT(split_equal_to_row_size)); |
break; |
case 8: |
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) | |
PIPE_CONFIG(ADDR_SURF_P2)); |
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_P2) | |
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_P2) | |
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_P2) | |
SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); |
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: |
gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P2) | |
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_P2) | |
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_P2) | |
SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); |
break; |
case 27: |
gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | |
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) | |
MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | |
PIPE_CONFIG(ADDR_SURF_P2) | |
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_P2) | |
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_P2) | |
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_2) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
NUM_BANKS(ADDR_SURF_16_BANK)); |
break; |
case 1: |
gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
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_2) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
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_4) | |
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_4) | |
NUM_BANKS(ADDR_SURF_16_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_4) | |
NUM_BANKS(ADDR_SURF_16_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_2) | |
NUM_BANKS(ADDR_SURF_8_BANK)); |
break; |
case 8: |
gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
NUM_BANKS(ADDR_SURF_16_BANK)); |
break; |
case 9: |
gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
NUM_BANKS(ADDR_SURF_16_BANK)); |
break; |
case 10: |
gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
NUM_BANKS(ADDR_SURF_16_BANK)); |
break; |
case 11: |
gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
NUM_BANKS(ADDR_SURF_16_BANK)); |
break; |
case 12: |
gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | |
NUM_BANKS(ADDR_SURF_16_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_4) | |
NUM_BANKS(ADDR_SURF_16_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_2) | |
NUM_BANKS(ADDR_SURF_8_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 |
DRM_ERROR("unknown num pipe config: 0x%x\n", num_pipe_configs); |
} |
/** |
* cik_select_se_sh - select which SE, SH to address |
* |
* @rdev: radeon_device pointer |
* @se_num: shader engine to address |
* @sh_num: sh block to address |
* |
* Select which SE, SH combinations to address. Certain |
* registers are instanced per SE or SH. 0xffffffff means |
* broadcast to all SEs or SHs (CIK). |
*/ |
static void cik_select_se_sh(struct radeon_device *rdev, |
u32 se_num, u32 sh_num) |
{ |
u32 data = INSTANCE_BROADCAST_WRITES; |
if ((se_num == 0xffffffff) && (sh_num == 0xffffffff)) |
data |= SH_BROADCAST_WRITES | SE_BROADCAST_WRITES; |
else if (se_num == 0xffffffff) |
data |= SE_BROADCAST_WRITES | SH_INDEX(sh_num); |
else if (sh_num == 0xffffffff) |
data |= SH_BROADCAST_WRITES | SE_INDEX(se_num); |
else |
data |= SH_INDEX(sh_num) | SE_INDEX(se_num); |
WREG32(GRBM_GFX_INDEX, data); |
} |
/** |
* cik_create_bitmask - create a bitmask |
* |
* @bit_width: length of the mask |
* |
* create a variable length bit mask (CIK). |
* Returns the bitmask. |
*/ |
static u32 cik_create_bitmask(u32 bit_width) |
{ |
u32 i, mask = 0; |
for (i = 0; i < bit_width; i++) { |
mask <<= 1; |
mask |= 1; |
} |
return mask; |
} |
/** |
* cik_get_rb_disabled - computes the mask of disabled RBs |
* |
* @rdev: radeon_device pointer |
* @max_rb_num: max RBs (render backends) for the asic |
* @se_num: number of SEs (shader engines) for the asic |
* @sh_per_se: number of SH blocks per SE for the asic |
* |
* Calculates the bitmask of disabled RBs (CIK). |
* Returns the disabled RB bitmask. |
*/ |
static u32 cik_get_rb_disabled(struct radeon_device *rdev, |
u32 max_rb_num_per_se, |
u32 sh_per_se) |
{ |
u32 data, mask; |
data = RREG32(CC_RB_BACKEND_DISABLE); |
if (data & 1) |
data &= BACKEND_DISABLE_MASK; |
else |
data = 0; |
data |= RREG32(GC_USER_RB_BACKEND_DISABLE); |
data >>= BACKEND_DISABLE_SHIFT; |
mask = cik_create_bitmask(max_rb_num_per_se / sh_per_se); |
return data & mask; |
} |
/** |
* cik_setup_rb - setup the RBs on the asic |
* |
* @rdev: radeon_device pointer |
* @se_num: number of SEs (shader engines) for the asic |
* @sh_per_se: number of SH blocks per SE for the asic |
* @max_rb_num: max RBs (render backends) for the asic |
* |
* Configures per-SE/SH RB registers (CIK). |
*/ |
static void cik_setup_rb(struct radeon_device *rdev, |
u32 se_num, u32 sh_per_se, |
u32 max_rb_num_per_se) |
{ |
int i, j; |
u32 data, mask; |
u32 disabled_rbs = 0; |
u32 enabled_rbs = 0; |
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_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_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; |
case 2: |
data |= (RASTER_CONFIG_RB_MAP_3 << (i * sh_per_se + j) * 2); |
break; |
case 3: |
default: |
data |= (RASTER_CONFIG_RB_MAP_2 << (i * sh_per_se + j) * 2); |
break; |
} |
enabled_rbs >>= 2; |
} |
WREG32(PA_SC_RASTER_CONFIG, data); |
} |
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
} |
/** |
* cik_gpu_init - setup the 3D engine |
* |
* @rdev: radeon_device pointer |
* |
* Configures the 3D engine and tiling configuration |
* registers so that the 3D engine is usable. |
*/ |
static void cik_gpu_init(struct radeon_device *rdev) |
{ |
u32 gb_addr_config = RREG32(GB_ADDR_CONFIG); |
u32 mc_shared_chmap, mc_arb_ramcfg; |
u32 hdp_host_path_cntl; |
u32 tmp; |
int i, j; |
switch (rdev->family) { |
case CHIP_BONAIRE: |
rdev->config.cik.max_shader_engines = 2; |
rdev->config.cik.max_tile_pipes = 4; |
rdev->config.cik.max_cu_per_sh = 7; |
rdev->config.cik.max_sh_per_se = 1; |
rdev->config.cik.max_backends_per_se = 2; |
rdev->config.cik.max_texture_channel_caches = 4; |
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 = 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; |
if ((rdev->pdev->device == 0x1304) || |
(rdev->pdev->device == 0x1305) || |
(rdev->pdev->device == 0x130C) || |
(rdev->pdev->device == 0x130F) || |
(rdev->pdev->device == 0x1310) || |
(rdev->pdev->device == 0x1311) || |
(rdev->pdev->device == 0x131C)) { |
rdev->config.cik.max_cu_per_sh = 8; |
rdev->config.cik.max_backends_per_se = 2; |
} else if ((rdev->pdev->device == 0x1309) || |
(rdev->pdev->device == 0x130A) || |
(rdev->pdev->device == 0x130D) || |
(rdev->pdev->device == 0x1313) || |
(rdev->pdev->device == 0x131D)) { |
rdev->config.cik.max_cu_per_sh = 6; |
rdev->config.cik.max_backends_per_se = 2; |
} else if ((rdev->pdev->device == 0x1306) || |
(rdev->pdev->device == 0x1307) || |
(rdev->pdev->device == 0x130B) || |
(rdev->pdev->device == 0x130E) || |
(rdev->pdev->device == 0x1315) || |
(rdev->pdev->device == 0x1318) || |
(rdev->pdev->device == 0x131B)) { |
rdev->config.cik.max_cu_per_sh = 4; |
rdev->config.cik.max_backends_per_se = 1; |
} else { |
rdev->config.cik.max_cu_per_sh = 3; |
rdev->config.cik.max_backends_per_se = 1; |
} |
rdev->config.cik.max_sh_per_se = 1; |
rdev->config.cik.max_texture_channel_caches = 4; |
rdev->config.cik.max_gprs = 256; |
rdev->config.cik.max_gs_threads = 16; |
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 = 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; |
rdev->config.cik.max_cu_per_sh = 2; |
rdev->config.cik.max_sh_per_se = 1; |
rdev->config.cik.max_backends_per_se = 1; |
rdev->config.cik.max_texture_channel_caches = 2; |
rdev->config.cik.max_gprs = 256; |
rdev->config.cik.max_gs_threads = 16; |
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 = BONAIRE_GB_ADDR_CONFIG_GOLDEN; |
break; |
} |
/* Initialize HDP */ |
for (i = 0, j = 0; i < 32; i++, j += 0x18) { |
WREG32((0x2c14 + j), 0x00000000); |
WREG32((0x2c18 + j), 0x00000000); |
WREG32((0x2c1c + j), 0x00000000); |
WREG32((0x2c20 + j), 0x00000000); |
WREG32((0x2c24 + j), 0x00000000); |
} |
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); |
WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN); |
mc_shared_chmap = RREG32(MC_SHARED_CHMAP); |
mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); |
rdev->config.cik.num_tile_pipes = rdev->config.cik.max_tile_pipes; |
rdev->config.cik.mem_max_burst_length_bytes = 256; |
tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT; |
rdev->config.cik.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024; |
if (rdev->config.cik.mem_row_size_in_kb > 4) |
rdev->config.cik.mem_row_size_in_kb = 4; |
/* XXX use MC settings? */ |
rdev->config.cik.shader_engine_tile_size = 32; |
rdev->config.cik.num_gpus = 1; |
rdev->config.cik.multi_gpu_tile_size = 64; |
/* fix up row size */ |
gb_addr_config &= ~ROW_SIZE_MASK; |
switch (rdev->config.cik.mem_row_size_in_kb) { |
case 1: |
default: |
gb_addr_config |= ROW_SIZE(0); |
break; |
case 2: |
gb_addr_config |= ROW_SIZE(1); |
break; |
case 4: |
gb_addr_config |= ROW_SIZE(2); |
break; |
} |
/* setup tiling info dword. gb_addr_config is not adequate since it does |
* not have bank info, so create a custom tiling dword. |
* bits 3:0 num_pipes |
* bits 7:4 num_banks |
* bits 11:8 group_size |
* bits 15:12 row_size |
*/ |
rdev->config.cik.tile_config = 0; |
switch (rdev->config.cik.num_tile_pipes) { |
case 1: |
rdev->config.cik.tile_config |= (0 << 0); |
break; |
case 2: |
rdev->config.cik.tile_config |= (1 << 0); |
break; |
case 4: |
rdev->config.cik.tile_config |= (2 << 0); |
break; |
case 8: |
default: |
/* XXX what about 12? */ |
rdev->config.cik.tile_config |= (3 << 0); |
break; |
} |
rdev->config.cik.tile_config |= |
((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; |
rdev->config.cik.tile_config |= |
((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8; |
rdev->config.cik.tile_config |= |
((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12; |
WREG32(GB_ADDR_CONFIG, gb_addr_config); |
WREG32(HDP_ADDR_CONFIG, gb_addr_config); |
WREG32(DMIF_ADDR_CALC, gb_addr_config); |
WREG32(SDMA0_TILING_CONFIG + SDMA0_REGISTER_OFFSET, gb_addr_config & 0x70); |
WREG32(SDMA0_TILING_CONFIG + SDMA1_REGISTER_OFFSET, gb_addr_config & 0x70); |
WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config); |
WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config); |
WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config); |
cik_tiling_mode_table_init(rdev); |
cik_setup_rb(rdev, rdev->config.cik.max_shader_engines, |
rdev->config.cik.max_sh_per_se, |
rdev->config.cik.max_backends_per_se); |
rdev->config.cik.active_cus = 0; |
for (i = 0; i < rdev->config.cik.max_shader_engines; i++) { |
for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) { |
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)); |
WREG32(SX_DEBUG_1, 0x20); |
WREG32(TA_CNTL_AUX, 0x00010000); |
tmp = RREG32(SPI_CONFIG_CNTL); |
tmp |= 0x03000000; |
WREG32(SPI_CONFIG_CNTL, tmp); |
WREG32(SQ_CONFIG, 1); |
WREG32(DB_DEBUG, 0); |
tmp = RREG32(DB_DEBUG2) & ~0xf00fffff; |
tmp |= 0x00000400; |
WREG32(DB_DEBUG2, tmp); |
tmp = RREG32(DB_DEBUG3) & ~0x0002021c; |
tmp |= 0x00020200; |
WREG32(DB_DEBUG3, tmp); |
tmp = RREG32(CB_HW_CONTROL) & ~0x00010000; |
tmp |= 0x00018208; |
WREG32(CB_HW_CONTROL, tmp); |
WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4)); |
WREG32(PA_SC_FIFO_SIZE, (SC_FRONTEND_PRIM_FIFO_SIZE(rdev->config.cik.sc_prim_fifo_size_frontend) | |
SC_BACKEND_PRIM_FIFO_SIZE(rdev->config.cik.sc_prim_fifo_size_backend) | |
SC_HIZ_TILE_FIFO_SIZE(rdev->config.cik.sc_hiz_tile_fifo_size) | |
SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.cik.sc_earlyz_tile_fifo_size))); |
WREG32(VGT_NUM_INSTANCES, 1); |
WREG32(CP_PERFMON_CNTL, 0); |
WREG32(SQ_CONFIG, 0); |
WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) | |
FORCE_EOV_MAX_REZ_CNT(255))); |
WREG32(VGT_CACHE_INVALIDATION, CACHE_INVALIDATION(VC_AND_TC) | |
AUTO_INVLD_EN(ES_AND_GS_AUTO)); |
WREG32(VGT_GS_VERTEX_REUSE, 16); |
WREG32(PA_SC_LINE_STIPPLE_STATE, 0); |
tmp = RREG32(HDP_MISC_CNTL); |
tmp |= HDP_FLUSH_INVALIDATE_CACHE; |
WREG32(HDP_MISC_CNTL, tmp); |
hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL); |
WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl); |
WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3)); |
WREG32(PA_SC_ENHANCE, ENABLE_PA_SC_OUT_OF_ORDER); |
udelay(50); |
} |
/* |
* GPU scratch registers helpers function. |
*/ |
/** |
* cik_scratch_init - setup driver info for CP scratch regs |
* |
* @rdev: radeon_device pointer |
* |
* Set up the number and offset of the CP scratch registers. |
* NOTE: use of CP scratch registers is a legacy inferface and |
* is not used by default on newer asics (r6xx+). On newer asics, |
* memory buffers are used for fences rather than scratch regs. |
*/ |
static void cik_scratch_init(struct radeon_device *rdev) |
{ |
int i; |
rdev->scratch.num_reg = 7; |
rdev->scratch.reg_base = SCRATCH_REG0; |
for (i = 0; i < rdev->scratch.num_reg; i++) { |
rdev->scratch.free[i] = true; |
rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4); |
} |
} |
/** |
* cik_ring_test - basic gfx ring test |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Allocate a scratch register and write to it using the gfx ring (CIK). |
* Provides a basic gfx ring test to verify that the ring is working. |
* Used by cik_cp_gfx_resume(); |
* Returns 0 on success, error on failure. |
*/ |
int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
uint32_t scratch; |
uint32_t tmp = 0; |
unsigned i; |
int r; |
r = radeon_scratch_get(rdev, &scratch); |
if (r) { |
DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r); |
return r; |
} |
WREG32(scratch, 0xCAFEDEAD); |
r = radeon_ring_lock(rdev, ring, 3); |
if (r) { |
DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", ring->idx, r); |
radeon_scratch_free(rdev, scratch); |
return r; |
} |
radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1)); |
radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2)); |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring, false); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(scratch); |
if (tmp == 0xDEADBEEF) |
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 (scratch(0x%04X)=0x%08X)\n", |
ring->idx, scratch, tmp); |
r = -EINVAL; |
} |
radeon_scratch_free(rdev, scratch); |
return r; |
} |
/** |
* 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 |
* @fence: radeon fence object |
* |
* Emits a fence sequnce number on the gfx ring and flushes |
* GPU caches. |
*/ |
void cik_fence_gfx_ring_emit(struct radeon_device *rdev, |
struct radeon_fence *fence) |
{ |
struct radeon_ring *ring = &rdev->ring[fence->ring]; |
u64 addr = rdev->fence_drv[fence->ring].gpu_addr; |
/* EVENT_WRITE_EOP - flush caches, send int */ |
radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); |
radeon_ring_write(ring, (EOP_TCL1_ACTION_EN | |
EOP_TC_ACTION_EN | |
EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) | |
EVENT_INDEX(5))); |
radeon_ring_write(ring, addr & 0xfffffffc); |
radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | DATA_SEL(1) | INT_SEL(2)); |
radeon_ring_write(ring, fence->seq); |
radeon_ring_write(ring, 0); |
} |
/** |
* cik_fence_compute_ring_emit - emit a fence on the compute ring |
* |
* @rdev: radeon_device pointer |
* @fence: radeon fence object |
* |
* Emits a fence sequnce number on the compute ring and flushes |
* GPU caches. |
*/ |
void cik_fence_compute_ring_emit(struct radeon_device *rdev, |
struct radeon_fence *fence) |
{ |
struct radeon_ring *ring = &rdev->ring[fence->ring]; |
u64 addr = rdev->fence_drv[fence->ring].gpu_addr; |
/* RELEASE_MEM - flush caches, send int */ |
radeon_ring_write(ring, PACKET3(PACKET3_RELEASE_MEM, 5)); |
radeon_ring_write(ring, (EOP_TCL1_ACTION_EN | |
EOP_TC_ACTION_EN | |
EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) | |
EVENT_INDEX(5))); |
radeon_ring_write(ring, DATA_SEL(1) | INT_SEL(2)); |
radeon_ring_write(ring, addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(addr)); |
radeon_ring_write(ring, fence->seq); |
radeon_ring_write(ring, 0); |
} |
/** |
* cik_semaphore_ring_emit - emit a semaphore on the CP ring |
* |
* @rdev: radeon_device pointer |
* @ring: radeon ring buffer object |
* @semaphore: radeon semaphore object |
* @emit_wait: Is this a sempahore wait? |
* |
* Emits a semaphore signal/wait packet to the CP ring and prevents the PFP |
* from running ahead of semaphore waits. |
*/ |
bool cik_semaphore_ring_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait) |
{ |
uint64_t addr = semaphore->gpu_addr; |
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, lower_32_bits(addr)); |
radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel); |
if (emit_wait && ring->idx == RADEON_RING_TYPE_GFX_INDEX) { |
/* Prevent the PFP from running ahead of the semaphore wait */ |
radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); |
radeon_ring_write(ring, 0x0); |
} |
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, false); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
/* |
* IB stuff |
*/ |
/** |
* cik_ring_ib_execute - emit an IB (Indirect Buffer) on the gfx ring |
* |
* @rdev: radeon_device pointer |
* @ib: radeon indirect buffer object |
* |
* Emits an DE (drawing engine) or CE (constant engine) IB |
* on the gfx ring. IBs are usually generated by userspace |
* acceleration drivers and submitted to the kernel for |
* sheduling on the ring. This function schedules the IB |
* on the gfx ring for execution by the GPU. |
*/ |
void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
u32 header, control = INDIRECT_BUFFER_VALID; |
if (ib->is_const_ib) { |
/* set switch buffer packet before const IB */ |
radeon_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0)); |
radeon_ring_write(ring, 0); |
header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2); |
} else { |
u32 next_rptr; |
if (ring->rptr_save_reg) { |
next_rptr = ring->wptr + 3 + 4; |
radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1)); |
radeon_ring_write(ring, ((ring->rptr_save_reg - |
PACKET3_SET_UCONFIG_REG_START) >> 2)); |
radeon_ring_write(ring, next_rptr); |
} else if (rdev->wb.enabled) { |
next_rptr = ring->wptr + 5 + 4; |
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)); |
radeon_ring_write(ring, next_rptr); |
} |
header = PACKET3(PACKET3_INDIRECT_BUFFER, 2); |
} |
control |= ib->length_dw | |
(ib->vm ? (ib->vm->id << 24) : 0); |
radeon_ring_write(ring, header); |
radeon_ring_write(ring, |
#ifdef __BIG_ENDIAN |
(2 << 0) | |
#endif |
(ib->gpu_addr & 0xFFFFFFFC)); |
radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF); |
radeon_ring_write(ring, control); |
} |
/** |
* cik_ib_test - basic gfx ring IB test |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Allocate an IB and execute it on the gfx ring (CIK). |
* Provides a basic gfx ring test to verify that IBs are working. |
* Returns 0 on success, error on failure. |
*/ |
int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
struct radeon_ib ib; |
uint32_t scratch; |
uint32_t tmp = 0; |
unsigned i; |
int r; |
r = radeon_scratch_get(rdev, &scratch); |
if (r) { |
DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r); |
return r; |
} |
WREG32(scratch, 0xCAFEDEAD); |
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); |
ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2); |
ib.ptr[2] = 0xDEADBEEF; |
ib.length_dw = 3; |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
if (r) { |
radeon_scratch_free(rdev, scratch); |
radeon_ib_free(rdev, &ib); |
DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); |
return r; |
} |
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++) { |
tmp = RREG32(scratch); |
if (tmp == 0xDEADBEEF) |
break; |
DRM_UDELAY(1); |
} |
if (i < rdev->usec_timeout) { |
DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i); |
} else { |
DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n", |
scratch, tmp); |
r = -EINVAL; |
} |
radeon_scratch_free(rdev, scratch); |
radeon_ib_free(rdev, &ib); |
return r; |
} |
/* |
* CP. |
* On CIK, gfx and compute now have independant command processors. |
* |
* GFX |
* Gfx consists of a single ring and can process both gfx jobs and |
* compute jobs. The gfx CP consists of three microengines (ME): |
* PFP - Pre-Fetch Parser |
* ME - Micro Engine |
* CE - Constant Engine |
* The PFP and ME make up what is considered the Drawing Engine (DE). |
* The CE is an asynchronous engine used for updating buffer desciptors |
* used by the DE so that they can be loaded into cache in parallel |
* while the DE is processing state update packets. |
* |
* Compute |
* The compute CP consists of two microengines (ME): |
* MEC1 - Compute MicroEngine 1 |
* MEC2 - Compute MicroEngine 2 |
* Each MEC supports 4 compute pipes and each pipe supports 8 queues. |
* The queues are exposed to userspace and are programmed directly |
* by the compute runtime. |
*/ |
/** |
* cik_cp_gfx_enable - enable/disable the gfx CP MEs |
* |
* @rdev: radeon_device pointer |
* @enable: enable or disable the MEs |
* |
* Halts or unhalts the gfx MEs. |
*/ |
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; |
} |
udelay(50); |
} |
/** |
* cik_cp_gfx_load_microcode - load the gfx CP ME ucode |
* |
* @rdev: radeon_device pointer |
* |
* Loads the gfx PFP, ME, and CE ucode. |
* Returns 0 for success, -EINVAL if the ucode is not available. |
*/ |
static int cik_cp_gfx_load_microcode(struct radeon_device *rdev) |
{ |
int i; |
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw) |
return -EINVAL; |
cik_cp_gfx_enable(rdev, false); |
if (rdev->new_fw) { |
const struct gfx_firmware_header_v1_0 *pfp_hdr = |
(const struct gfx_firmware_header_v1_0 *)rdev->pfp_fw->data; |
const struct gfx_firmware_header_v1_0 *ce_hdr = |
(const struct gfx_firmware_header_v1_0 *)rdev->ce_fw->data; |
const struct gfx_firmware_header_v1_0 *me_hdr = |
(const struct gfx_firmware_header_v1_0 *)rdev->me_fw->data; |
const __le32 *fw_data; |
u32 fw_size; |
radeon_ucode_print_gfx_hdr(&pfp_hdr->header); |
radeon_ucode_print_gfx_hdr(&ce_hdr->header); |
radeon_ucode_print_gfx_hdr(&me_hdr->header); |
/* PFP */ |
fw_data = (const __le32 *) |
(rdev->pfp_fw->data + le32_to_cpu(pfp_hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(pfp_hdr->header.ucode_size_bytes) / 4; |
WREG32(CP_PFP_UCODE_ADDR, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(CP_PFP_UCODE_DATA, le32_to_cpup(fw_data++)); |
WREG32(CP_PFP_UCODE_ADDR, 0); |
/* CE */ |
fw_data = (const __le32 *) |
(rdev->ce_fw->data + le32_to_cpu(ce_hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(ce_hdr->header.ucode_size_bytes) / 4; |
WREG32(CP_CE_UCODE_ADDR, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(CP_CE_UCODE_DATA, le32_to_cpup(fw_data++)); |
WREG32(CP_CE_UCODE_ADDR, 0); |
/* ME */ |
fw_data = (const __be32 *) |
(rdev->me_fw->data + le32_to_cpu(me_hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(me_hdr->header.ucode_size_bytes) / 4; |
WREG32(CP_ME_RAM_WADDR, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(CP_ME_RAM_DATA, le32_to_cpup(fw_data++)); |
WREG32(CP_ME_RAM_WADDR, 0); |
} else { |
const __be32 *fw_data; |
/* PFP */ |
fw_data = (const __be32 *)rdev->pfp_fw->data; |
WREG32(CP_PFP_UCODE_ADDR, 0); |
for (i = 0; i < CIK_PFP_UCODE_SIZE; i++) |
WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); |
WREG32(CP_PFP_UCODE_ADDR, 0); |
/* CE */ |
fw_data = (const __be32 *)rdev->ce_fw->data; |
WREG32(CP_CE_UCODE_ADDR, 0); |
for (i = 0; i < CIK_CE_UCODE_SIZE; i++) |
WREG32(CP_CE_UCODE_DATA, be32_to_cpup(fw_data++)); |
WREG32(CP_CE_UCODE_ADDR, 0); |
/* ME */ |
fw_data = (const __be32 *)rdev->me_fw->data; |
WREG32(CP_ME_RAM_WADDR, 0); |
for (i = 0; i < CIK_ME_UCODE_SIZE; i++) |
WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); |
WREG32(CP_ME_RAM_WADDR, 0); |
} |
WREG32(CP_PFP_UCODE_ADDR, 0); |
WREG32(CP_CE_UCODE_ADDR, 0); |
WREG32(CP_ME_RAM_WADDR, 0); |
WREG32(CP_ME_RAM_RADDR, 0); |
return 0; |
} |
/** |
* cik_cp_gfx_start - start the gfx ring |
* |
* @rdev: radeon_device pointer |
* |
* Enables the ring and loads the clear state context and other |
* packets required to init the ring. |
* Returns 0 for success, error for failure. |
*/ |
static int cik_cp_gfx_start(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
int r, i; |
/* init the CP */ |
WREG32(CP_MAX_CONTEXT, rdev->config.cik.max_hw_contexts - 1); |
WREG32(CP_ENDIAN_SWAP, 0); |
WREG32(CP_DEVICE_ID, 1); |
cik_cp_gfx_enable(rdev, true); |
r = radeon_ring_lock(rdev, ring, cik_default_size + 17); |
if (r) { |
DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); |
return r; |
} |
/* init the CE partitions. CE only used for gfx on CIK */ |
radeon_ring_write(ring, PACKET3(PACKET3_SET_BASE, 2)); |
radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE)); |
radeon_ring_write(ring, 0xc000); |
radeon_ring_write(ring, 0xc000); |
/* setup clear context state */ |
radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0)); |
radeon_ring_write(ring, PACKET3_PREAMBLE_BEGIN_CLEAR_STATE); |
radeon_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1)); |
radeon_ring_write(ring, 0x80000000); |
radeon_ring_write(ring, 0x80000000); |
for (i = 0; i < cik_default_size; i++) |
radeon_ring_write(ring, cik_default_state[i]); |
radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0)); |
radeon_ring_write(ring, PACKET3_PREAMBLE_END_CLEAR_STATE); |
/* set clear context state */ |
radeon_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, PACKET3(PACKET3_SET_CONTEXT_REG, 2)); |
radeon_ring_write(ring, 0x00000316); |
radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ |
radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */ |
radeon_ring_unlock_commit(rdev, ring, false); |
return 0; |
} |
/** |
* cik_cp_gfx_fini - stop the gfx ring |
* |
* @rdev: radeon_device pointer |
* |
* Stop the gfx ring and tear down the driver ring |
* info. |
*/ |
static void cik_cp_gfx_fini(struct radeon_device *rdev) |
{ |
cik_cp_gfx_enable(rdev, false); |
radeon_ring_fini(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); |
} |
/** |
* cik_cp_gfx_resume - setup the gfx ring buffer registers |
* |
* @rdev: radeon_device pointer |
* |
* Program the location and size of the gfx ring buffer |
* and test it to make sure it's working. |
* Returns 0 for success, error for failure. |
*/ |
static int cik_cp_gfx_resume(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring; |
u32 tmp; |
u32 rb_bufsz; |
u64 rb_addr; |
int r; |
WREG32(CP_SEM_WAIT_TIMER, 0x0); |
if (rdev->family != CHIP_HAWAII) |
WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0); |
/* Set the write pointer delay */ |
WREG32(CP_RB_WPTR_DELAY, 0); |
/* set the RB to use vmid 0 */ |
WREG32(CP_RB_VMID, 0); |
WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF); |
/* ring 0 - compute and gfx */ |
/* Set ring buffer size */ |
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
rb_bufsz = order_base_2(ring->ring_size / 8); |
tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
#ifdef __BIG_ENDIAN |
tmp |= BUF_SWAP_32BIT; |
#endif |
WREG32(CP_RB0_CNTL, tmp); |
/* Initialize the ring buffer's read and write pointers */ |
WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA); |
ring->wptr = 0; |
WREG32(CP_RB0_WPTR, ring->wptr); |
/* set the wb address wether it's enabled or not */ |
WREG32(CP_RB0_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC); |
WREG32(CP_RB0_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF); |
/* scratch register shadowing is no longer supported */ |
WREG32(SCRATCH_UMSK, 0); |
if (!rdev->wb.enabled) |
tmp |= RB_NO_UPDATE; |
mdelay(1); |
WREG32(CP_RB0_CNTL, tmp); |
rb_addr = ring->gpu_addr >> 8; |
WREG32(CP_RB0_BASE, rb_addr); |
WREG32(CP_RB0_BASE_HI, upper_32_bits(rb_addr)); |
/* start the ring */ |
cik_cp_gfx_start(rdev); |
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = true; |
r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); |
if (r) { |
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_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 = rdev->wb.wb[ring->rptr_offs/4]; |
} else { |
mutex_lock(&rdev->srbm_mutex); |
cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); |
rptr = RREG32(CP_HQD_PQ_RPTR); |
cik_srbm_select(rdev, 0, 0, 0, 0); |
mutex_unlock(&rdev->srbm_mutex); |
} |
return rptr; |
} |
u32 cik_compute_get_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
u32 wptr; |
if (rdev->wb.enabled) { |
/* 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); |
wptr = RREG32(CP_HQD_PQ_WPTR); |
cik_srbm_select(rdev, 0, 0, 0, 0); |
mutex_unlock(&rdev->srbm_mutex); |
} |
return wptr; |
} |
void cik_compute_set_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
/* XXX check if swapping is necessary on BE */ |
rdev->wb.wb[ring->wptr_offs/4] = ring->wptr; |
WDOORBELL32(ring->doorbell_index, ring->wptr); |
} |
/** |
* cik_cp_compute_enable - enable/disable the compute CP MEs |
* |
* @rdev: radeon_device pointer |
* @enable: enable or disable the MEs |
* |
* Halts or unhalts the compute MEs. |
*/ |
static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32(CP_MEC_CNTL, 0); |
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); |
} |
/** |
* cik_cp_compute_load_microcode - load the compute CP ME ucode |
* |
* @rdev: radeon_device pointer |
* |
* Loads the compute MEC1&2 ucode. |
* Returns 0 for success, -EINVAL if the ucode is not available. |
*/ |
static int cik_cp_compute_load_microcode(struct radeon_device *rdev) |
{ |
int i; |
if (!rdev->mec_fw) |
return -EINVAL; |
cik_cp_compute_enable(rdev, false); |
if (rdev->new_fw) { |
const struct gfx_firmware_header_v1_0 *mec_hdr = |
(const struct gfx_firmware_header_v1_0 *)rdev->mec_fw->data; |
const __le32 *fw_data; |
u32 fw_size; |
radeon_ucode_print_gfx_hdr(&mec_hdr->header); |
/* MEC1 */ |
fw_data = (const __le32 *) |
(rdev->mec_fw->data + le32_to_cpu(mec_hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(mec_hdr->header.ucode_size_bytes) / 4; |
WREG32(CP_MEC_ME1_UCODE_ADDR, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(CP_MEC_ME1_UCODE_DATA, le32_to_cpup(fw_data++)); |
WREG32(CP_MEC_ME1_UCODE_ADDR, 0); |
/* MEC2 */ |
if (rdev->family == CHIP_KAVERI) { |
const struct gfx_firmware_header_v1_0 *mec2_hdr = |
(const struct gfx_firmware_header_v1_0 *)rdev->mec2_fw->data; |
fw_data = (const __le32 *) |
(rdev->mec2_fw->data + |
le32_to_cpu(mec2_hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(mec2_hdr->header.ucode_size_bytes) / 4; |
WREG32(CP_MEC_ME2_UCODE_ADDR, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(CP_MEC_ME2_UCODE_DATA, le32_to_cpup(fw_data++)); |
WREG32(CP_MEC_ME2_UCODE_ADDR, 0); |
} |
} else { |
const __be32 *fw_data; |
/* MEC1 */ |
fw_data = (const __be32 *)rdev->mec_fw->data; |
WREG32(CP_MEC_ME1_UCODE_ADDR, 0); |
for (i = 0; i < CIK_MEC_UCODE_SIZE; i++) |
WREG32(CP_MEC_ME1_UCODE_DATA, be32_to_cpup(fw_data++)); |
WREG32(CP_MEC_ME1_UCODE_ADDR, 0); |
if (rdev->family == CHIP_KAVERI) { |
/* MEC2 */ |
fw_data = (const __be32 *)rdev->mec_fw->data; |
WREG32(CP_MEC_ME2_UCODE_ADDR, 0); |
for (i = 0; i < CIK_MEC_UCODE_SIZE; i++) |
WREG32(CP_MEC_ME2_UCODE_DATA, be32_to_cpup(fw_data++)); |
WREG32(CP_MEC_ME2_UCODE_ADDR, 0); |
} |
} |
return 0; |
} |
/** |
* cik_cp_compute_start - start the compute queues |
* |
* @rdev: radeon_device pointer |
* |
* Enable the compute queues. |
* Returns 0 for success, error for failure. |
*/ |
static int cik_cp_compute_start(struct radeon_device *rdev) |
{ |
cik_cp_compute_enable(rdev, true); |
return 0; |
} |
/** |
* cik_cp_compute_fini - stop the compute queues |
* |
* @rdev: radeon_device pointer |
* |
* Stop the compute queues and tear down the driver queue |
* info. |
*/ |
static void cik_cp_compute_fini(struct radeon_device *rdev) |
{ |
int i, idx, r; |
cik_cp_compute_enable(rdev, false); |
for (i = 0; i < 2; i++) { |
if (i == 0) |
idx = CAYMAN_RING_TYPE_CP1_INDEX; |
else |
idx = CAYMAN_RING_TYPE_CP2_INDEX; |
if (rdev->ring[idx].mqd_obj) { |
r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false); |
if (unlikely(r != 0)) |
dev_warn(rdev->dev, "(%d) reserve MQD bo failed\n", r); |
radeon_bo_unpin(rdev->ring[idx].mqd_obj); |
radeon_bo_unreserve(rdev->ring[idx].mqd_obj); |
radeon_bo_unref(&rdev->ring[idx].mqd_obj); |
rdev->ring[idx].mqd_obj = NULL; |
} |
} |
} |
static void cik_mec_fini(struct radeon_device *rdev) |
{ |
int r; |
if (rdev->mec.hpd_eop_obj) { |
r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false); |
if (unlikely(r != 0)) |
dev_warn(rdev->dev, "(%d) reserve HPD EOP bo failed\n", r); |
radeon_bo_unpin(rdev->mec.hpd_eop_obj); |
radeon_bo_unreserve(rdev->mec.hpd_eop_obj); |
radeon_bo_unref(&rdev->mec.hpd_eop_obj); |
rdev->mec.hpd_eop_obj = NULL; |
} |
} |
#define MEC_HPD_SIZE 2048 |
static int cik_mec_init(struct radeon_device *rdev) |
{ |
int r; |
u32 *hpd; |
/* |
* KV: 2 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 64 Queues total |
* CI/KB: 1 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 32 Queues total |
*/ |
if (rdev->family == CHIP_KAVERI) |
rdev->mec.num_mec = 2; |
else |
rdev->mec.num_mec = 1; |
rdev->mec.num_pipe = 4; |
rdev->mec.num_queue = rdev->mec.num_mec * rdev->mec.num_pipe * 8; |
if (rdev->mec.hpd_eop_obj == NULL) { |
r = radeon_bo_create(rdev, |
rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2, |
PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_GTT, 0, NULL, |
&rdev->mec.hpd_eop_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r); |
return r; |
} |
} |
r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false); |
if (unlikely(r != 0)) { |
cik_mec_fini(rdev); |
return r; |
} |
r = radeon_bo_pin(rdev->mec.hpd_eop_obj, RADEON_GEM_DOMAIN_GTT, |
&rdev->mec.hpd_eop_gpu_addr); |
if (r) { |
dev_warn(rdev->dev, "(%d) pin HDP EOP bo failed\n", r); |
cik_mec_fini(rdev); |
return r; |
} |
r = radeon_bo_kmap(rdev->mec.hpd_eop_obj, (void **)&hpd); |
if (r) { |
dev_warn(rdev->dev, "(%d) map HDP EOP bo failed\n", r); |
cik_mec_fini(rdev); |
return r; |
} |
/* clear memory. Not sure if this is required or not */ |
memset(hpd, 0, rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2); |
radeon_bo_kunmap(rdev->mec.hpd_eop_obj); |
radeon_bo_unreserve(rdev->mec.hpd_eop_obj); |
return 0; |
} |
struct hqd_registers |
{ |
u32 cp_mqd_base_addr; |
u32 cp_mqd_base_addr_hi; |
u32 cp_hqd_active; |
u32 cp_hqd_vmid; |
u32 cp_hqd_persistent_state; |
u32 cp_hqd_pipe_priority; |
u32 cp_hqd_queue_priority; |
u32 cp_hqd_quantum; |
u32 cp_hqd_pq_base; |
u32 cp_hqd_pq_base_hi; |
u32 cp_hqd_pq_rptr; |
u32 cp_hqd_pq_rptr_report_addr; |
u32 cp_hqd_pq_rptr_report_addr_hi; |
u32 cp_hqd_pq_wptr_poll_addr; |
u32 cp_hqd_pq_wptr_poll_addr_hi; |
u32 cp_hqd_pq_doorbell_control; |
u32 cp_hqd_pq_wptr; |
u32 cp_hqd_pq_control; |
u32 cp_hqd_ib_base_addr; |
u32 cp_hqd_ib_base_addr_hi; |
u32 cp_hqd_ib_rptr; |
u32 cp_hqd_ib_control; |
u32 cp_hqd_iq_timer; |
u32 cp_hqd_iq_rptr; |
u32 cp_hqd_dequeue_request; |
u32 cp_hqd_dma_offload; |
u32 cp_hqd_sema_cmd; |
u32 cp_hqd_msg_type; |
u32 cp_hqd_atomic0_preop_lo; |
u32 cp_hqd_atomic0_preop_hi; |
u32 cp_hqd_atomic1_preop_lo; |
u32 cp_hqd_atomic1_preop_hi; |
u32 cp_hqd_hq_scheduler0; |
u32 cp_hqd_hq_scheduler1; |
u32 cp_mqd_control; |
}; |
struct bonaire_mqd |
{ |
u32 header; |
u32 dispatch_initiator; |
u32 dimensions[3]; |
u32 start_idx[3]; |
u32 num_threads[3]; |
u32 pipeline_stat_enable; |
u32 perf_counter_enable; |
u32 pgm[2]; |
u32 tba[2]; |
u32 tma[2]; |
u32 pgm_rsrc[2]; |
u32 vmid; |
u32 resource_limits; |
u32 static_thread_mgmt01[2]; |
u32 tmp_ring_size; |
u32 static_thread_mgmt23[2]; |
u32 restart[3]; |
u32 thread_trace_enable; |
u32 reserved1; |
u32 user_data[16]; |
u32 vgtcs_invoke_count[2]; |
struct hqd_registers queue_state; |
u32 dequeue_cntr; |
u32 interrupt_queue[64]; |
}; |
/** |
* cik_cp_compute_resume - setup the compute queue registers |
* |
* @rdev: radeon_device pointer |
* |
* Program the compute queues and test them to make sure they |
* are working. |
* Returns 0 for success, error for failure. |
*/ |
static int cik_cp_compute_resume(struct radeon_device *rdev) |
{ |
int r, i, idx; |
u32 tmp; |
bool use_doorbell = true; |
u64 hqd_gpu_addr; |
u64 mqd_gpu_addr; |
u64 eop_gpu_addr; |
u64 wb_gpu_addr; |
u32 *buf; |
struct bonaire_mqd *mqd; |
r = cik_cp_compute_start(rdev); |
if (r) |
return r; |
/* fix up chicken bits */ |
tmp = RREG32(CP_CPF_DEBUG); |
tmp |= (1 << 23); |
WREG32(CP_CPF_DEBUG, tmp); |
/* init the pipes */ |
mutex_lock(&rdev->srbm_mutex); |
for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) { |
int me = (i < 4) ? 1 : 2; |
int pipe = (i < 4) ? i : (i - 4); |
eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE * 2); |
cik_srbm_select(rdev, me, pipe, 0, 0); |
/* write the EOP addr */ |
WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8); |
WREG32(CP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr) >> 8); |
/* set the VMID assigned */ |
WREG32(CP_HPD_EOP_VMID, 0); |
/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */ |
tmp = RREG32(CP_HPD_EOP_CONTROL); |
tmp &= ~EOP_SIZE_MASK; |
tmp |= order_base_2(MEC_HPD_SIZE / 8); |
WREG32(CP_HPD_EOP_CONTROL, tmp); |
} |
cik_srbm_select(rdev, 0, 0, 0, 0); |
mutex_unlock(&rdev->srbm_mutex); |
/* init the queues. Just two for now. */ |
for (i = 0; i < 2; i++) { |
if (i == 0) |
idx = CAYMAN_RING_TYPE_CP1_INDEX; |
else |
idx = CAYMAN_RING_TYPE_CP2_INDEX; |
if (rdev->ring[idx].mqd_obj == NULL) { |
r = radeon_bo_create(rdev, |
sizeof(struct bonaire_mqd), |
PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_GTT, 0, NULL, |
&rdev->ring[idx].mqd_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r); |
return r; |
} |
} |
r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false); |
if (unlikely(r != 0)) { |
cik_cp_compute_fini(rdev); |
return r; |
} |
r = radeon_bo_pin(rdev->ring[idx].mqd_obj, RADEON_GEM_DOMAIN_GTT, |
&mqd_gpu_addr); |
if (r) { |
dev_warn(rdev->dev, "(%d) pin MQD bo failed\n", r); |
cik_cp_compute_fini(rdev); |
return r; |
} |
r = radeon_bo_kmap(rdev->ring[idx].mqd_obj, (void **)&buf); |
if (r) { |
dev_warn(rdev->dev, "(%d) map MQD bo failed\n", r); |
cik_cp_compute_fini(rdev); |
return r; |
} |
/* init the mqd struct */ |
memset(buf, 0, sizeof(struct bonaire_mqd)); |
mqd = (struct bonaire_mqd *)buf; |
mqd->header = 0xC0310800; |
mqd->static_thread_mgmt01[0] = 0xffffffff; |
mqd->static_thread_mgmt01[1] = 0xffffffff; |
mqd->static_thread_mgmt23[0] = 0xffffffff; |
mqd->static_thread_mgmt23[1] = 0xffffffff; |
mutex_lock(&rdev->srbm_mutex); |
cik_srbm_select(rdev, rdev->ring[idx].me, |
rdev->ring[idx].pipe, |
rdev->ring[idx].queue, 0); |
/* disable wptr polling */ |
tmp = RREG32(CP_PQ_WPTR_POLL_CNTL); |
tmp &= ~WPTR_POLL_EN; |
WREG32(CP_PQ_WPTR_POLL_CNTL, tmp); |
/* enable doorbell? */ |
mqd->queue_state.cp_hqd_pq_doorbell_control = |
RREG32(CP_HQD_PQ_DOORBELL_CONTROL); |
if (use_doorbell) |
mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN; |
else |
mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_EN; |
WREG32(CP_HQD_PQ_DOORBELL_CONTROL, |
mqd->queue_state.cp_hqd_pq_doorbell_control); |
/* disable the queue if it's active */ |
mqd->queue_state.cp_hqd_dequeue_request = 0; |
mqd->queue_state.cp_hqd_pq_rptr = 0; |
mqd->queue_state.cp_hqd_pq_wptr= 0; |
if (RREG32(CP_HQD_ACTIVE) & 1) { |
WREG32(CP_HQD_DEQUEUE_REQUEST, 1); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (!(RREG32(CP_HQD_ACTIVE) & 1)) |
break; |
udelay(1); |
} |
WREG32(CP_HQD_DEQUEUE_REQUEST, mqd->queue_state.cp_hqd_dequeue_request); |
WREG32(CP_HQD_PQ_RPTR, mqd->queue_state.cp_hqd_pq_rptr); |
WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr); |
} |
/* set the pointer to the MQD */ |
mqd->queue_state.cp_mqd_base_addr = mqd_gpu_addr & 0xfffffffc; |
mqd->queue_state.cp_mqd_base_addr_hi = upper_32_bits(mqd_gpu_addr); |
WREG32(CP_MQD_BASE_ADDR, mqd->queue_state.cp_mqd_base_addr); |
WREG32(CP_MQD_BASE_ADDR_HI, mqd->queue_state.cp_mqd_base_addr_hi); |
/* set MQD vmid to 0 */ |
mqd->queue_state.cp_mqd_control = RREG32(CP_MQD_CONTROL); |
mqd->queue_state.cp_mqd_control &= ~MQD_VMID_MASK; |
WREG32(CP_MQD_CONTROL, mqd->queue_state.cp_mqd_control); |
/* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */ |
hqd_gpu_addr = rdev->ring[idx].gpu_addr >> 8; |
mqd->queue_state.cp_hqd_pq_base = hqd_gpu_addr; |
mqd->queue_state.cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr); |
WREG32(CP_HQD_PQ_BASE, mqd->queue_state.cp_hqd_pq_base); |
WREG32(CP_HQD_PQ_BASE_HI, mqd->queue_state.cp_hqd_pq_base_hi); |
/* set up the HQD, this is similar to CP_RB0_CNTL */ |
mqd->queue_state.cp_hqd_pq_control = RREG32(CP_HQD_PQ_CONTROL); |
mqd->queue_state.cp_hqd_pq_control &= |
~(QUEUE_SIZE_MASK | RPTR_BLOCK_SIZE_MASK); |
mqd->queue_state.cp_hqd_pq_control |= |
order_base_2(rdev->ring[idx].ring_size / 8); |
mqd->queue_state.cp_hqd_pq_control |= |
(order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8); |
#ifdef __BIG_ENDIAN |
mqd->queue_state.cp_hqd_pq_control |= BUF_SWAP_32BIT; |
#endif |
mqd->queue_state.cp_hqd_pq_control &= |
~(UNORD_DISPATCH | ROQ_PQ_IB_FLIP | PQ_VOLATILE); |
mqd->queue_state.cp_hqd_pq_control |= |
PRIV_STATE | KMD_QUEUE; /* assuming kernel queue control */ |
WREG32(CP_HQD_PQ_CONTROL, mqd->queue_state.cp_hqd_pq_control); |
/* only used if CP_PQ_WPTR_POLL_CNTL.WPTR_POLL_EN=1 */ |
if (i == 0) |
wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP1_WPTR_OFFSET; |
else |
wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP2_WPTR_OFFSET; |
mqd->queue_state.cp_hqd_pq_wptr_poll_addr = wb_gpu_addr & 0xfffffffc; |
mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff; |
WREG32(CP_HQD_PQ_WPTR_POLL_ADDR, mqd->queue_state.cp_hqd_pq_wptr_poll_addr); |
WREG32(CP_HQD_PQ_WPTR_POLL_ADDR_HI, |
mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi); |
/* set the wb address wether it's enabled or not */ |
if (i == 0) |
wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET; |
else |
wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET; |
mqd->queue_state.cp_hqd_pq_rptr_report_addr = wb_gpu_addr & 0xfffffffc; |
mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi = |
upper_32_bits(wb_gpu_addr) & 0xffff; |
WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR, |
mqd->queue_state.cp_hqd_pq_rptr_report_addr); |
WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR_HI, |
mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi); |
/* enable the doorbell if requested */ |
if (use_doorbell) { |
mqd->queue_state.cp_hqd_pq_doorbell_control = |
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_index); |
mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN; |
mqd->queue_state.cp_hqd_pq_doorbell_control &= |
~(DOORBELL_SOURCE | DOORBELL_HIT); |
} else { |
mqd->queue_state.cp_hqd_pq_doorbell_control = 0; |
} |
WREG32(CP_HQD_PQ_DOORBELL_CONTROL, |
mqd->queue_state.cp_hqd_pq_doorbell_control); |
/* read and write pointers, similar to CP_RB0_WPTR/_RPTR */ |
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); |
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; |
WREG32(CP_HQD_VMID, mqd->queue_state.cp_hqd_vmid); |
/* activate the queue */ |
mqd->queue_state.cp_hqd_active = 1; |
WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active); |
cik_srbm_select(rdev, 0, 0, 0, 0); |
mutex_unlock(&rdev->srbm_mutex); |
radeon_bo_kunmap(rdev->ring[idx].mqd_obj); |
radeon_bo_unreserve(rdev->ring[idx].mqd_obj); |
rdev->ring[idx].ready = true; |
r = radeon_ring_test(rdev, idx, &rdev->ring[idx]); |
if (r) |
rdev->ring[idx].ready = false; |
} |
return 0; |
} |
static void cik_cp_enable(struct radeon_device *rdev, bool enable) |
{ |
cik_cp_gfx_enable(rdev, enable); |
cik_cp_compute_enable(rdev, enable); |
} |
static int cik_cp_load_microcode(struct radeon_device *rdev) |
{ |
int r; |
r = cik_cp_gfx_load_microcode(rdev); |
if (r) |
return r; |
r = cik_cp_compute_load_microcode(rdev); |
if (r) |
return r; |
return 0; |
} |
static void cik_cp_fini(struct radeon_device *rdev) |
{ |
cik_cp_gfx_fini(rdev); |
cik_cp_compute_fini(rdev); |
} |
static int cik_cp_resume(struct radeon_device *rdev) |
{ |
int r; |
cik_enable_gui_idle_interrupt(rdev, false); |
r = cik_cp_load_microcode(rdev); |
if (r) |
return r; |
r = cik_cp_gfx_resume(rdev); |
if (r) |
return r; |
r = cik_cp_compute_resume(rdev); |
if (r) |
return r; |
cik_enable_gui_idle_interrupt(rdev, true); |
return 0; |
} |
static void cik_print_gpu_status_regs(struct radeon_device *rdev) |
{ |
dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", |
RREG32(GRBM_STATUS)); |
dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n", |
RREG32(GRBM_STATUS2)); |
dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", |
RREG32(GRBM_STATUS_SE0)); |
dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", |
RREG32(GRBM_STATUS_SE1)); |
dev_info(rdev->dev, " GRBM_STATUS_SE2=0x%08X\n", |
RREG32(GRBM_STATUS_SE2)); |
dev_info(rdev->dev, " GRBM_STATUS_SE3=0x%08X\n", |
RREG32(GRBM_STATUS_SE3)); |
dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", |
RREG32(SRBM_STATUS)); |
dev_info(rdev->dev, " SRBM_STATUS2=0x%08X\n", |
RREG32(SRBM_STATUS2)); |
dev_info(rdev->dev, " SDMA0_STATUS_REG = 0x%08X\n", |
RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET)); |
dev_info(rdev->dev, " SDMA1_STATUS_REG = 0x%08X\n", |
RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET)); |
dev_info(rdev->dev, " CP_STAT = 0x%08x\n", RREG32(CP_STAT)); |
dev_info(rdev->dev, " CP_STALLED_STAT1 = 0x%08x\n", |
RREG32(CP_STALLED_STAT1)); |
dev_info(rdev->dev, " CP_STALLED_STAT2 = 0x%08x\n", |
RREG32(CP_STALLED_STAT2)); |
dev_info(rdev->dev, " CP_STALLED_STAT3 = 0x%08x\n", |
RREG32(CP_STALLED_STAT3)); |
dev_info(rdev->dev, " CP_CPF_BUSY_STAT = 0x%08x\n", |
RREG32(CP_CPF_BUSY_STAT)); |
dev_info(rdev->dev, " CP_CPF_STALLED_STAT1 = 0x%08x\n", |
RREG32(CP_CPF_STALLED_STAT1)); |
dev_info(rdev->dev, " CP_CPF_STATUS = 0x%08x\n", RREG32(CP_CPF_STATUS)); |
dev_info(rdev->dev, " CP_CPC_BUSY_STAT = 0x%08x\n", RREG32(CP_CPC_BUSY_STAT)); |
dev_info(rdev->dev, " CP_CPC_STALLED_STAT1 = 0x%08x\n", |
RREG32(CP_CPC_STALLED_STAT1)); |
dev_info(rdev->dev, " CP_CPC_STATUS = 0x%08x\n", RREG32(CP_CPC_STATUS)); |
} |
/** |
* cik_gpu_check_soft_reset - check which blocks are busy |
* |
* @rdev: radeon_device pointer |
* |
* Check which blocks are busy and return the relevant reset |
* mask to be used by cik_gpu_soft_reset(). |
* Returns a mask of the blocks to be reset. |
*/ |
u32 cik_gpu_check_soft_reset(struct radeon_device *rdev) |
{ |
u32 reset_mask = 0; |
u32 tmp; |
/* GRBM_STATUS */ |
tmp = RREG32(GRBM_STATUS); |
if (tmp & (PA_BUSY | SC_BUSY | |
BCI_BUSY | SX_BUSY | |
TA_BUSY | VGT_BUSY | |
DB_BUSY | CB_BUSY | |
GDS_BUSY | SPI_BUSY | |
IA_BUSY | IA_BUSY_NO_DMA)) |
reset_mask |= RADEON_RESET_GFX; |
if (tmp & (CP_BUSY | CP_COHERENCY_BUSY)) |
reset_mask |= RADEON_RESET_CP; |
/* GRBM_STATUS2 */ |
tmp = RREG32(GRBM_STATUS2); |
if (tmp & RLC_BUSY) |
reset_mask |= RADEON_RESET_RLC; |
/* SDMA0_STATUS_REG */ |
tmp = RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET); |
if (!(tmp & SDMA_IDLE)) |
reset_mask |= RADEON_RESET_DMA; |
/* SDMA1_STATUS_REG */ |
tmp = RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET); |
if (!(tmp & SDMA_IDLE)) |
reset_mask |= RADEON_RESET_DMA1; |
/* SRBM_STATUS2 */ |
tmp = RREG32(SRBM_STATUS2); |
if (tmp & SDMA_BUSY) |
reset_mask |= RADEON_RESET_DMA; |
if (tmp & SDMA1_BUSY) |
reset_mask |= RADEON_RESET_DMA1; |
/* SRBM_STATUS */ |
tmp = RREG32(SRBM_STATUS); |
if (tmp & IH_BUSY) |
reset_mask |= RADEON_RESET_IH; |
if (tmp & SEM_BUSY) |
reset_mask |= RADEON_RESET_SEM; |
if (tmp & GRBM_RQ_PENDING) |
reset_mask |= RADEON_RESET_GRBM; |
if (tmp & VMC_BUSY) |
reset_mask |= RADEON_RESET_VMC; |
if (tmp & (MCB_BUSY | MCB_NON_DISPLAY_BUSY | |
MCC_BUSY | MCD_BUSY)) |
reset_mask |= RADEON_RESET_MC; |
if (evergreen_is_display_hung(rdev)) |
reset_mask |= RADEON_RESET_DISPLAY; |
/* Skip MC reset as it's mostly likely not hung, just busy */ |
if (reset_mask & RADEON_RESET_MC) { |
DRM_DEBUG("MC busy: 0x%08X, clearing.\n", reset_mask); |
reset_mask &= ~RADEON_RESET_MC; |
} |
return reset_mask; |
} |
/** |
* cik_gpu_soft_reset - soft reset GPU |
* |
* @rdev: radeon_device pointer |
* @reset_mask: mask of which blocks to reset |
* |
* Soft reset the blocks specified in @reset_mask. |
*/ |
static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) |
{ |
struct evergreen_mc_save save; |
u32 grbm_soft_reset = 0, srbm_soft_reset = 0; |
u32 tmp; |
if (reset_mask == 0) |
return; |
dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask); |
cik_print_gpu_status_regs(rdev); |
dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", |
RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); |
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); |
/* 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); |
if (reset_mask & RADEON_RESET_DMA) { |
/* sdma0 */ |
tmp = RREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET); |
tmp |= SDMA_HALT; |
WREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET, tmp); |
} |
if (reset_mask & RADEON_RESET_DMA1) { |
/* sdma1 */ |
tmp = RREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET); |
tmp |= SDMA_HALT; |
WREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET, tmp); |
} |
evergreen_mc_stop(rdev, &save); |
if (evergreen_mc_wait_for_idle(rdev)) { |
dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); |
} |
if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE | RADEON_RESET_CP)) |
grbm_soft_reset = SOFT_RESET_CP | SOFT_RESET_GFX; |
if (reset_mask & RADEON_RESET_CP) { |
grbm_soft_reset |= SOFT_RESET_CP; |
srbm_soft_reset |= SOFT_RESET_GRBM; |
} |
if (reset_mask & RADEON_RESET_DMA) |
srbm_soft_reset |= SOFT_RESET_SDMA; |
if (reset_mask & RADEON_RESET_DMA1) |
srbm_soft_reset |= SOFT_RESET_SDMA1; |
if (reset_mask & RADEON_RESET_DISPLAY) |
srbm_soft_reset |= SOFT_RESET_DC; |
if (reset_mask & RADEON_RESET_RLC) |
grbm_soft_reset |= SOFT_RESET_RLC; |
if (reset_mask & RADEON_RESET_SEM) |
srbm_soft_reset |= SOFT_RESET_SEM; |
if (reset_mask & RADEON_RESET_IH) |
srbm_soft_reset |= SOFT_RESET_IH; |
if (reset_mask & RADEON_RESET_GRBM) |
srbm_soft_reset |= SOFT_RESET_GRBM; |
if (reset_mask & RADEON_RESET_VMC) |
srbm_soft_reset |= SOFT_RESET_VMC; |
if (!(rdev->flags & RADEON_IS_IGP)) { |
if (reset_mask & RADEON_RESET_MC) |
srbm_soft_reset |= SOFT_RESET_MC; |
} |
if (grbm_soft_reset) { |
tmp = RREG32(GRBM_SOFT_RESET); |
tmp |= grbm_soft_reset; |
dev_info(rdev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp); |
WREG32(GRBM_SOFT_RESET, tmp); |
tmp = RREG32(GRBM_SOFT_RESET); |
udelay(50); |
tmp &= ~grbm_soft_reset; |
WREG32(GRBM_SOFT_RESET, tmp); |
tmp = RREG32(GRBM_SOFT_RESET); |
} |
if (srbm_soft_reset) { |
tmp = RREG32(SRBM_SOFT_RESET); |
tmp |= srbm_soft_reset; |
dev_info(rdev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); |
WREG32(SRBM_SOFT_RESET, tmp); |
tmp = RREG32(SRBM_SOFT_RESET); |
udelay(50); |
tmp &= ~srbm_soft_reset; |
WREG32(SRBM_SOFT_RESET, tmp); |
tmp = RREG32(SRBM_SOFT_RESET); |
} |
/* Wait a little for things to settle down */ |
udelay(50); |
evergreen_mc_resume(rdev, &save); |
udelay(50); |
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 |
* |
* @rdev: radeon_device pointer |
* |
* Look up which blocks are hung and attempt |
* to reset them. |
* Returns 0 for success. |
*/ |
int cik_asic_reset(struct radeon_device *rdev) |
{ |
u32 reset_mask; |
reset_mask = cik_gpu_check_soft_reset(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); |
return 0; |
} |
/** |
* cik_gfx_is_lockup - check if the 3D engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the 3D engine is locked up (CIK). |
* Returns true if the engine is locked, false if not. |
*/ |
bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
u32 reset_mask = cik_gpu_check_soft_reset(rdev); |
if (!(reset_mask & (RADEON_RESET_GFX | |
RADEON_RESET_COMPUTE | |
RADEON_RESET_CP))) { |
radeon_ring_lockup_update(rdev, ring); |
return false; |
} |
return radeon_ring_test_lockup(rdev, ring); |
} |
/* MC */ |
/** |
* cik_mc_program - program the GPU memory controller |
* |
* @rdev: radeon_device pointer |
* |
* Set the location of vram, gart, and AGP in the GPU's |
* physical address space (CIK). |
*/ |
static void cik_mc_program(struct radeon_device *rdev) |
{ |
struct evergreen_mc_save save; |
u32 tmp; |
int i, j; |
/* Initialize HDP */ |
for (i = 0, j = 0; i < 32; i++, j += 0x18) { |
WREG32((0x2c14 + j), 0x00000000); |
WREG32((0x2c18 + j), 0x00000000); |
WREG32((0x2c1c + j), 0x00000000); |
WREG32((0x2c20 + j), 0x00000000); |
WREG32((0x2c24 + j), 0x00000000); |
} |
WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0); |
evergreen_mc_stop(rdev, &save); |
if (radeon_mc_wait_for_idle(rdev)) { |
dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); |
} |
/* Lockout access through VGA aperture*/ |
WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE); |
/* Update configuration */ |
WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR, |
rdev->mc.vram_start >> 12); |
WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, |
rdev->mc.vram_end >> 12); |
WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, |
rdev->vram_scratch.gpu_addr >> 12); |
tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; |
tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); |
WREG32(MC_VM_FB_LOCATION, tmp); |
/* XXX double check these! */ |
WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8)); |
WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30)); |
WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF); |
WREG32(MC_VM_AGP_BASE, 0); |
WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF); |
WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF); |
if (radeon_mc_wait_for_idle(rdev)) { |
dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); |
} |
evergreen_mc_resume(rdev, &save); |
/* we need to own VRAM, so turn off the VGA renderer here |
* to stop it overwriting our objects */ |
rv515_vga_render_disable(rdev); |
} |
/** |
* cik_mc_init - initialize the memory controller driver params |
* |
* @rdev: radeon_device pointer |
* |
* Look up the amount of vram, vram width, and decide how to place |
* vram and gart within the GPU's physical address space (CIK). |
* Returns 0 for success. |
*/ |
static int cik_mc_init(struct radeon_device *rdev) |
{ |
u32 tmp; |
int chansize, numchan; |
/* Get VRAM informations */ |
rdev->mc.vram_is_ddr = true; |
tmp = RREG32(MC_ARB_RAMCFG); |
if (tmp & CHANSIZE_MASK) { |
chansize = 64; |
} else { |
chansize = 32; |
} |
tmp = RREG32(MC_SHARED_CHMAP); |
switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { |
case 0: |
default: |
numchan = 1; |
break; |
case 1: |
numchan = 2; |
break; |
case 2: |
numchan = 4; |
break; |
case 3: |
numchan = 8; |
break; |
case 4: |
numchan = 3; |
break; |
case 5: |
numchan = 6; |
break; |
case 6: |
numchan = 10; |
break; |
case 7: |
numchan = 12; |
break; |
case 8: |
numchan = 16; |
break; |
} |
rdev->mc.vram_width = numchan * chansize; |
/* Could aper size report 0 ? */ |
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; |
rdev->mc.visible_vram_size = rdev->mc.aper_size; |
si_vram_gtt_location(rdev, &rdev->mc); |
radeon_update_bandwidth_info(rdev); |
return 0; |
} |
/* |
* GART |
* VMID 0 is the physical GPU addresses as used by the kernel. |
* VMIDs 1-15 are used for userspace clients and are handled |
* by the radeon vm/hsa code. |
*/ |
/** |
* cik_pcie_gart_tlb_flush - gart tlb flush callback |
* |
* @rdev: radeon_device pointer |
* |
* Flush the TLB for the VMID 0 page table (CIK). |
*/ |
void cik_pcie_gart_tlb_flush(struct radeon_device *rdev) |
{ |
/* flush hdp cache */ |
WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0); |
/* bits 0-15 are the VM contexts0-15 */ |
WREG32(VM_INVALIDATE_REQUEST, 0x1); |
} |
/** |
* cik_pcie_gart_enable - gart enable |
* |
* @rdev: radeon_device pointer |
* |
* This sets up the TLBs, programs the page tables for VMID0, |
* sets up the hw for VMIDs 1-15 which are allocated on |
* demand, and sets up the global locations for the LDS, GDS, |
* and GPUVM for FSA64 clients (CIK). |
* Returns 0 for success, errors for failure. |
*/ |
static int cik_pcie_gart_enable(struct radeon_device *rdev) |
{ |
int r, i; |
if (rdev->gart.robj == NULL) { |
dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); |
return -EINVAL; |
} |
r = radeon_gart_table_vram_pin(rdev); |
if (r) |
return r; |
/* Setup TLB control */ |
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 | |
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); |
WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); |
WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, |
(u32)(rdev->dummy_page.addr >> 12)); |
WREG32(VM_CONTEXT0_CNTL2, 0); |
WREG32(VM_CONTEXT0_CNTL, (ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) | |
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT)); |
WREG32(0x15D4, 0); |
WREG32(0x15D8, 0); |
WREG32(0x15DC, 0); |
/* restore context1-15 */ |
/* set vm size, must be a multiple of 4 */ |
WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); |
WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); |
for (i = 1; i < 16; i++) { |
if (i < 8) |
WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), |
rdev->vm_manager.saved_table_addr[i]); |
else |
WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2), |
rdev->vm_manager.saved_table_addr[i]); |
} |
/* enable context1-15 */ |
WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR, |
(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 | |
DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT | |
PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT | |
PDE0_PROTECTION_FAULT_ENABLE_DEFAULT | |
VALID_PROTECTION_FAULT_ENABLE_INTERRUPT | |
VALID_PROTECTION_FAULT_ENABLE_DEFAULT | |
READ_PROTECTION_FAULT_ENABLE_INTERRUPT | |
READ_PROTECTION_FAULT_ENABLE_DEFAULT | |
WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT | |
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT); |
if (rdev->family == CHIP_KAVERI) { |
u32 tmp = RREG32(CHUB_CONTROL); |
tmp &= ~BYPASS_VM; |
WREG32(CHUB_CONTROL, tmp); |
} |
/* XXX SH_MEM regs */ |
/* where to put LDS, scratch, GPUVM in FSA64 space */ |
mutex_lock(&rdev->srbm_mutex); |
for (i = 0; i < 16; i++) { |
cik_srbm_select(rdev, 0, 0, 0, i); |
/* CP and shaders */ |
WREG32(SH_MEM_CONFIG, 0); |
WREG32(SH_MEM_APE1_BASE, 1); |
WREG32(SH_MEM_APE1_LIMIT, 0); |
WREG32(SH_MEM_BASES, 0); |
/* SDMA GFX */ |
WREG32(SDMA0_GFX_VIRTUAL_ADDR + SDMA0_REGISTER_OFFSET, 0); |
WREG32(SDMA0_GFX_APE1_CNTL + SDMA0_REGISTER_OFFSET, 0); |
WREG32(SDMA0_GFX_VIRTUAL_ADDR + SDMA1_REGISTER_OFFSET, 0); |
WREG32(SDMA0_GFX_APE1_CNTL + SDMA1_REGISTER_OFFSET, 0); |
/* XXX SDMA RLC - todo */ |
} |
cik_srbm_select(rdev, 0, 0, 0, 0); |
mutex_unlock(&rdev->srbm_mutex); |
cik_pcie_gart_tlb_flush(rdev); |
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", |
(unsigned)(rdev->mc.gtt_size >> 20), |
(unsigned long long)rdev->gart.table_addr); |
rdev->gart.ready = true; |
return 0; |
} |
/** |
* cik_pcie_gart_disable - gart disable |
* |
* @rdev: radeon_device pointer |
* |
* This disables all VM page table (CIK). |
*/ |
static void cik_pcie_gart_disable(struct radeon_device *rdev) |
{ |
unsigned i; |
for (i = 1; i < 16; ++i) { |
uint32_t reg; |
if (i < 8) |
reg = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2); |
else |
reg = VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2); |
rdev->vm_manager.saved_table_addr[i] = RREG32(reg); |
} |
/* Disable all tables */ |
WREG32(VM_CONTEXT0_CNTL, 0); |
WREG32(VM_CONTEXT1_CNTL, 0); |
/* Setup TLB control */ |
WREG32(MC_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE_NOT_IN_SYS | |
SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU); |
/* Setup L2 cache */ |
WREG32(VM_L2_CNTL, |
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, 0); |
WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY | |
L2_CACHE_BIGK_FRAGMENT_SIZE(6)); |
radeon_gart_table_vram_unpin(rdev); |
} |
/** |
* cik_pcie_gart_fini - vm fini callback |
* |
* @rdev: radeon_device pointer |
* |
* Tears down the driver GART/VM setup (CIK). |
*/ |
static void cik_pcie_gart_fini(struct radeon_device *rdev) |
{ |
cik_pcie_gart_disable(rdev); |
radeon_gart_table_vram_free(rdev); |
radeon_gart_fini(rdev); |
} |
/* vm parser */ |
/** |
* cik_ib_parse - vm ib_parse callback |
* |
* @rdev: radeon_device pointer |
* @ib: indirect buffer pointer |
* |
* CIK uses hw IB checking so this is a nop (CIK). |
*/ |
int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
return 0; |
} |
/* |
* vm |
* VMID 0 is the physical GPU addresses as used by the kernel. |
* VMIDs 1-15 are used for userspace clients and are handled |
* by the radeon vm/hsa code. |
*/ |
/** |
* cik_vm_init - cik vm init callback |
* |
* @rdev: radeon_device pointer |
* |
* Inits cik specific vm parameters (number of VMs, base of vram for |
* VMIDs 1-15) (CIK). |
* Returns 0 for success. |
*/ |
int cik_vm_init(struct radeon_device *rdev) |
{ |
/* number of VMs */ |
rdev->vm_manager.nvm = 16; |
/* base offset of vram pages */ |
if (rdev->flags & RADEON_IS_IGP) { |
u64 tmp = RREG32(MC_VM_FB_OFFSET); |
tmp <<= 22; |
rdev->vm_manager.vram_base_offset = tmp; |
} else |
rdev->vm_manager.vram_base_offset = 0; |
return 0; |
} |
/** |
* cik_vm_fini - cik vm fini callback |
* |
* @rdev: radeon_device pointer |
* |
* Tear down any asic specific VM setup (CIK). |
*/ |
void cik_vm_fini(struct radeon_device *rdev) |
{ |
} |
/** |
* cik_vm_decode_fault - print human readable fault info |
* |
* @rdev: radeon_device pointer |
* @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value |
* @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value |
* |
* Print human readable fault information (CIK). |
*/ |
static void cik_vm_decode_fault(struct radeon_device *rdev, |
u32 status, u32 addr, u32 mc_client) |
{ |
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", |
block, mc_client, mc_id); |
} |
/** |
* cik_vm_flush - cik vm flush using the CP |
* |
* @rdev: radeon_device pointer |
* |
* Update the page table base and flush the VM TLB |
* using the CP (CIK). |
*/ |
void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) |
{ |
struct radeon_ring *ring = &rdev->ring[ridx]; |
int usepfp = (ridx == RADEON_RING_TYPE_GFX_INDEX); |
if (vm == NULL) |
return; |
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | |
WRITE_DATA_DST_SEL(0))); |
if (vm->id < 8) { |
radeon_ring_write(ring, |
(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2); |
} else { |
radeon_ring_write(ring, |
(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2); |
} |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, vm->pd_gpu_addr >> 12); |
/* update SH_MEM_* regs */ |
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | |
WRITE_DATA_DST_SEL(0))); |
radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, VMID(vm->id)); |
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6)); |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | |
WRITE_DATA_DST_SEL(0))); |
radeon_ring_write(ring, SH_MEM_BASES >> 2); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, 0); /* SH_MEM_BASES */ |
radeon_ring_write(ring, 0); /* SH_MEM_CONFIG */ |
radeon_ring_write(ring, 1); /* SH_MEM_APE1_BASE */ |
radeon_ring_write(ring, 0); /* SH_MEM_APE1_LIMIT */ |
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | |
WRITE_DATA_DST_SEL(0))); |
radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, VMID(0)); |
/* HDP flush */ |
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)); |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | |
WRITE_DATA_DST_SEL(0))); |
radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, 1 << vm->id); |
/* compute doesn't have PFP */ |
if (usepfp) { |
/* sync PFP to ME, otherwise we might get invalid PFP reads */ |
radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); |
radeon_ring_write(ring, 0x0); |
} |
} |
/* |
* RLC |
* The RLC is a multi-purpose microengine that handles a |
* variety of functions, the most important of which is |
* the interrupt controller. |
*/ |
static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev, |
bool enable) |
{ |
u32 tmp = RREG32(CP_INT_CNTL_RING0); |
if (enable) |
tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
else |
tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
WREG32(CP_INT_CNTL_RING0, tmp); |
} |
static void cik_enable_lbpw(struct radeon_device *rdev, bool enable) |
{ |
u32 tmp; |
tmp = RREG32(RLC_LB_CNTL); |
if (enable) |
tmp |= LOAD_BALANCE_ENABLE; |
else |
tmp &= ~LOAD_BALANCE_ENABLE; |
WREG32(RLC_LB_CNTL, tmp); |
} |
static void cik_wait_for_rlc_serdes(struct radeon_device *rdev) |
{ |
u32 i, j, k; |
u32 mask; |
for (i = 0; i < rdev->config.cik.max_shader_engines; i++) { |
for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) { |
cik_select_se_sh(rdev, i, j); |
for (k = 0; k < rdev->usec_timeout; k++) { |
if (RREG32(RLC_SERDES_CU_MASTER_BUSY) == 0) |
break; |
udelay(1); |
} |
} |
} |
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
mask = SE_MASTER_BUSY_MASK | GC_MASTER_BUSY | TC0_MASTER_BUSY | TC1_MASTER_BUSY; |
for (k = 0; k < rdev->usec_timeout; k++) { |
if ((RREG32(RLC_SERDES_NONCU_MASTER_BUSY) & mask) == 0) |
break; |
udelay(1); |
} |
} |
static void cik_update_rlc(struct radeon_device *rdev, u32 rlc) |
{ |
u32 tmp; |
tmp = RREG32(RLC_CNTL); |
if (tmp != rlc) |
WREG32(RLC_CNTL, rlc); |
} |
static u32 cik_halt_rlc(struct radeon_device *rdev) |
{ |
u32 data, orig; |
orig = data = RREG32(RLC_CNTL); |
if (data & RLC_ENABLE) { |
u32 i; |
data &= ~RLC_ENABLE; |
WREG32(RLC_CNTL, data); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(RLC_GPM_STAT) & RLC_GPM_BUSY) == 0) |
break; |
udelay(1); |
} |
cik_wait_for_rlc_serdes(rdev); |
} |
return orig; |
} |
void cik_enter_rlc_safe_mode(struct radeon_device *rdev) |
{ |
u32 tmp, i, mask; |
tmp = REQ | MESSAGE(MSG_ENTER_RLC_SAFE_MODE); |
WREG32(RLC_GPR_REG2, tmp); |
mask = GFX_POWER_STATUS | GFX_CLOCK_STATUS; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(RLC_GPM_STAT) & mask) == mask) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(RLC_GPR_REG2) & REQ) == 0) |
break; |
udelay(1); |
} |
} |
void cik_exit_rlc_safe_mode(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = REQ | MESSAGE(MSG_EXIT_RLC_SAFE_MODE); |
WREG32(RLC_GPR_REG2, tmp); |
} |
/** |
* cik_rlc_stop - stop the RLC ME |
* |
* @rdev: radeon_device pointer |
* |
* Halt the RLC ME (MicroEngine) (CIK). |
*/ |
static void cik_rlc_stop(struct radeon_device *rdev) |
{ |
WREG32(RLC_CNTL, 0); |
cik_enable_gui_idle_interrupt(rdev, false); |
cik_wait_for_rlc_serdes(rdev); |
} |
/** |
* cik_rlc_start - start the RLC ME |
* |
* @rdev: radeon_device pointer |
* |
* Unhalt the RLC ME (MicroEngine) (CIK). |
*/ |
static void cik_rlc_start(struct radeon_device *rdev) |
{ |
WREG32(RLC_CNTL, RLC_ENABLE); |
cik_enable_gui_idle_interrupt(rdev, true); |
udelay(50); |
} |
/** |
* cik_rlc_resume - setup the RLC hw |
* |
* @rdev: radeon_device pointer |
* |
* Initialize the RLC registers, load the ucode, |
* and start the RLC (CIK). |
* Returns 0 for success, -EINVAL if the ucode is not available. |
*/ |
static int cik_rlc_resume(struct radeon_device *rdev) |
{ |
u32 i, size, tmp; |
if (!rdev->rlc_fw) |
return -EINVAL; |
cik_rlc_stop(rdev); |
/* disable CG */ |
tmp = RREG32(RLC_CGCG_CGLS_CTRL) & 0xfffffffc; |
WREG32(RLC_CGCG_CGLS_CTRL, tmp); |
si_rlc_reset(rdev); |
cik_init_pg(rdev); |
cik_init_cg(rdev); |
WREG32(RLC_LB_CNTR_INIT, 0); |
WREG32(RLC_LB_CNTR_MAX, 0x00008000); |
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff); |
WREG32(RLC_LB_PARAMS, 0x00600408); |
WREG32(RLC_LB_CNTL, 0x80000004); |
WREG32(RLC_MC_CNTL, 0); |
WREG32(RLC_UCODE_CNTL, 0); |
if (rdev->new_fw) { |
const struct rlc_firmware_header_v1_0 *hdr = |
(const struct rlc_firmware_header_v1_0 *)rdev->rlc_fw->data; |
const __le32 *fw_data = (const __le32 *) |
(rdev->rlc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
radeon_ucode_print_rlc_hdr(&hdr->header); |
size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; |
WREG32(RLC_GPM_UCODE_ADDR, 0); |
for (i = 0; i < size; i++) |
WREG32(RLC_GPM_UCODE_DATA, le32_to_cpup(fw_data++)); |
WREG32(RLC_GPM_UCODE_ADDR, 0); |
} else { |
const __be32 *fw_data; |
switch (rdev->family) { |
case CHIP_BONAIRE: |
case CHIP_HAWAII: |
default: |
size = BONAIRE_RLC_UCODE_SIZE; |
break; |
case CHIP_KAVERI: |
size = KV_RLC_UCODE_SIZE; |
break; |
case CHIP_KABINI: |
size = KB_RLC_UCODE_SIZE; |
break; |
case CHIP_MULLINS: |
size = ML_RLC_UCODE_SIZE; |
break; |
} |
fw_data = (const __be32 *)rdev->rlc_fw->data; |
WREG32(RLC_GPM_UCODE_ADDR, 0); |
for (i = 0; i < size; i++) |
WREG32(RLC_GPM_UCODE_DATA, be32_to_cpup(fw_data++)); |
WREG32(RLC_GPM_UCODE_ADDR, 0); |
} |
/* XXX - find out what chips support lbpw */ |
cik_enable_lbpw(rdev, false); |
if (rdev->family == CHIP_BONAIRE) |
WREG32(RLC_DRIVER_DMA_STATUS, 0); |
cik_rlc_start(rdev); |
return 0; |
} |
static void cik_enable_cgcg(struct radeon_device *rdev, bool enable) |
{ |
u32 data, orig, tmp, tmp2; |
orig = data = RREG32(RLC_CGCG_CGLS_CTRL); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_GFX_CGCG)) { |
cik_enable_gui_idle_interrupt(rdev, true); |
tmp = cik_halt_rlc(rdev); |
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff); |
WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff); |
tmp2 = BPM_ADDR_MASK | CGCG_OVERRIDE_0 | CGLS_ENABLE; |
WREG32(RLC_SERDES_WR_CTRL, tmp2); |
cik_update_rlc(rdev, tmp); |
data |= CGCG_EN | CGLS_EN; |
} else { |
cik_enable_gui_idle_interrupt(rdev, false); |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
data &= ~(CGCG_EN | CGLS_EN); |
} |
if (orig != data) |
WREG32(RLC_CGCG_CGLS_CTRL, data); |
} |
static void cik_enable_mgcg(struct radeon_device *rdev, bool enable) |
{ |
u32 data, orig, tmp = 0; |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_GFX_MGCG)) { |
if (rdev->cg_flags & RADEON_CG_SUPPORT_GFX_MGLS) { |
if (rdev->cg_flags & RADEON_CG_SUPPORT_GFX_CP_LS) { |
orig = data = RREG32(CP_MEM_SLP_CNTL); |
data |= CP_MEM_LS_EN; |
if (orig != data) |
WREG32(CP_MEM_SLP_CNTL, data); |
} |
} |
orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE); |
data &= 0xfffffffd; |
if (orig != data) |
WREG32(RLC_CGTT_MGCG_OVERRIDE, data); |
tmp = cik_halt_rlc(rdev); |
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff); |
WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff); |
data = BPM_ADDR_MASK | MGCG_OVERRIDE_0; |
WREG32(RLC_SERDES_WR_CTRL, data); |
cik_update_rlc(rdev, tmp); |
if (rdev->cg_flags & RADEON_CG_SUPPORT_GFX_CGTS) { |
orig = data = RREG32(CGTS_SM_CTRL_REG); |
data &= ~SM_MODE_MASK; |
data |= SM_MODE(0x2); |
data |= SM_MODE_ENABLE; |
data &= ~CGTS_OVERRIDE; |
if ((rdev->cg_flags & RADEON_CG_SUPPORT_GFX_MGLS) && |
(rdev->cg_flags & RADEON_CG_SUPPORT_GFX_CGTS_LS)) |
data &= ~CGTS_LS_OVERRIDE; |
data &= ~ON_MONITOR_ADD_MASK; |
data |= ON_MONITOR_ADD_EN; |
data |= ON_MONITOR_ADD(0x96); |
if (orig != data) |
WREG32(CGTS_SM_CTRL_REG, data); |
} |
} else { |
orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE); |
data |= 0x00000002; |
if (orig != data) |
WREG32(RLC_CGTT_MGCG_OVERRIDE, data); |
data = RREG32(RLC_MEM_SLP_CNTL); |
if (data & RLC_MEM_LS_EN) { |
data &= ~RLC_MEM_LS_EN; |
WREG32(RLC_MEM_SLP_CNTL, data); |
} |
data = RREG32(CP_MEM_SLP_CNTL); |
if (data & CP_MEM_LS_EN) { |
data &= ~CP_MEM_LS_EN; |
WREG32(CP_MEM_SLP_CNTL, data); |
} |
orig = data = RREG32(CGTS_SM_CTRL_REG); |
data |= CGTS_OVERRIDE | CGTS_LS_OVERRIDE; |
if (orig != data) |
WREG32(CGTS_SM_CTRL_REG, data); |
tmp = cik_halt_rlc(rdev); |
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff); |
WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff); |
data = BPM_ADDR_MASK | MGCG_OVERRIDE_1; |
WREG32(RLC_SERDES_WR_CTRL, data); |
cik_update_rlc(rdev, tmp); |
} |
} |
static const u32 mc_cg_registers[] = |
{ |
MC_HUB_MISC_HUB_CG, |
MC_HUB_MISC_SIP_CG, |
MC_HUB_MISC_VM_CG, |
MC_XPB_CLK_GAT, |
ATC_MISC_CG, |
MC_CITF_MISC_WR_CG, |
MC_CITF_MISC_RD_CG, |
MC_CITF_MISC_VM_CG, |
VM_L2_CG, |
}; |
static void cik_enable_mc_ls(struct radeon_device *rdev, |
bool enable) |
{ |
int i; |
u32 orig, data; |
for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) { |
orig = data = RREG32(mc_cg_registers[i]); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_MC_LS)) |
data |= MC_LS_ENABLE; |
else |
data &= ~MC_LS_ENABLE; |
if (data != orig) |
WREG32(mc_cg_registers[i], data); |
} |
} |
static void cik_enable_mc_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
int i; |
u32 orig, data; |
for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) { |
orig = data = RREG32(mc_cg_registers[i]); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_MC_MGCG)) |
data |= MC_CG_ENABLE; |
else |
data &= ~MC_CG_ENABLE; |
if (data != orig) |
WREG32(mc_cg_registers[i], data); |
} |
} |
static void cik_enable_sdma_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_SDMA_MGCG)) { |
WREG32(SDMA0_CLK_CTRL + SDMA0_REGISTER_OFFSET, 0x00000100); |
WREG32(SDMA0_CLK_CTRL + SDMA1_REGISTER_OFFSET, 0x00000100); |
} else { |
orig = data = RREG32(SDMA0_CLK_CTRL + SDMA0_REGISTER_OFFSET); |
data |= 0xff000000; |
if (data != orig) |
WREG32(SDMA0_CLK_CTRL + SDMA0_REGISTER_OFFSET, data); |
orig = data = RREG32(SDMA0_CLK_CTRL + SDMA1_REGISTER_OFFSET); |
data |= 0xff000000; |
if (data != orig) |
WREG32(SDMA0_CLK_CTRL + SDMA1_REGISTER_OFFSET, data); |
} |
} |
static void cik_enable_sdma_mgls(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_SDMA_LS)) { |
orig = data = RREG32(SDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET); |
data |= 0x100; |
if (orig != data) |
WREG32(SDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET, data); |
orig = data = RREG32(SDMA0_POWER_CNTL + SDMA1_REGISTER_OFFSET); |
data |= 0x100; |
if (orig != data) |
WREG32(SDMA0_POWER_CNTL + SDMA1_REGISTER_OFFSET, data); |
} else { |
orig = data = RREG32(SDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET); |
data &= ~0x100; |
if (orig != data) |
WREG32(SDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET, data); |
orig = data = RREG32(SDMA0_POWER_CNTL + SDMA1_REGISTER_OFFSET); |
data &= ~0x100; |
if (orig != data) |
WREG32(SDMA0_POWER_CNTL + SDMA1_REGISTER_OFFSET, data); |
} |
} |
static void cik_enable_uvd_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_UVD_MGCG)) { |
data = RREG32_UVD_CTX(UVD_CGC_MEM_CTRL); |
data = 0xfff; |
WREG32_UVD_CTX(UVD_CGC_MEM_CTRL, data); |
orig = data = RREG32(UVD_CGC_CTRL); |
data |= DCM; |
if (orig != data) |
WREG32(UVD_CGC_CTRL, data); |
} else { |
data = RREG32_UVD_CTX(UVD_CGC_MEM_CTRL); |
data &= ~0xfff; |
WREG32_UVD_CTX(UVD_CGC_MEM_CTRL, data); |
orig = data = RREG32(UVD_CGC_CTRL); |
data &= ~DCM; |
if (orig != data) |
WREG32(UVD_CGC_CTRL, data); |
} |
} |
static void cik_enable_bif_mgls(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
orig = data = RREG32_PCIE_PORT(PCIE_CNTL2); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_BIF_LS)) |
data |= SLV_MEM_LS_EN | MST_MEM_LS_EN | |
REPLAY_MEM_LS_EN | SLV_MEM_AGGRESSIVE_LS_EN; |
else |
data &= ~(SLV_MEM_LS_EN | MST_MEM_LS_EN | |
REPLAY_MEM_LS_EN | SLV_MEM_AGGRESSIVE_LS_EN); |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_CNTL2, data); |
} |
static void cik_enable_hdp_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
orig = data = RREG32(HDP_HOST_PATH_CNTL); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_HDP_MGCG)) |
data &= ~CLOCK_GATING_DIS; |
else |
data |= CLOCK_GATING_DIS; |
if (orig != data) |
WREG32(HDP_HOST_PATH_CNTL, data); |
} |
static void cik_enable_hdp_ls(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
orig = data = RREG32(HDP_MEM_POWER_LS); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_HDP_LS)) |
data |= HDP_LS_ENABLE; |
else |
data &= ~HDP_LS_ENABLE; |
if (orig != data) |
WREG32(HDP_MEM_POWER_LS, data); |
} |
void cik_update_cg(struct radeon_device *rdev, |
u32 block, bool enable) |
{ |
if (block & RADEON_CG_BLOCK_GFX) { |
cik_enable_gui_idle_interrupt(rdev, false); |
/* order matters! */ |
if (enable) { |
cik_enable_mgcg(rdev, true); |
cik_enable_cgcg(rdev, true); |
} else { |
cik_enable_cgcg(rdev, false); |
cik_enable_mgcg(rdev, false); |
} |
cik_enable_gui_idle_interrupt(rdev, true); |
} |
if (block & RADEON_CG_BLOCK_MC) { |
if (!(rdev->flags & RADEON_IS_IGP)) { |
cik_enable_mc_mgcg(rdev, enable); |
cik_enable_mc_ls(rdev, enable); |
} |
} |
if (block & RADEON_CG_BLOCK_SDMA) { |
cik_enable_sdma_mgcg(rdev, enable); |
cik_enable_sdma_mgls(rdev, enable); |
} |
if (block & RADEON_CG_BLOCK_BIF) { |
cik_enable_bif_mgls(rdev, enable); |
} |
if (block & RADEON_CG_BLOCK_UVD) { |
if (rdev->has_uvd) |
cik_enable_uvd_mgcg(rdev, enable); |
} |
if (block & RADEON_CG_BLOCK_HDP) { |
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) |
{ |
cik_update_cg(rdev, RADEON_CG_BLOCK_GFX, true); |
if (rdev->has_uvd) |
si_init_uvd_internal_cg(rdev); |
cik_update_cg(rdev, (RADEON_CG_BLOCK_MC | |
RADEON_CG_BLOCK_SDMA | |
RADEON_CG_BLOCK_BIF | |
RADEON_CG_BLOCK_UVD | |
RADEON_CG_BLOCK_HDP), true); |
} |
static void cik_fini_cg(struct radeon_device *rdev) |
{ |
cik_update_cg(rdev, (RADEON_CG_BLOCK_MC | |
RADEON_CG_BLOCK_SDMA | |
RADEON_CG_BLOCK_BIF | |
RADEON_CG_BLOCK_UVD | |
RADEON_CG_BLOCK_HDP), false); |
cik_update_cg(rdev, RADEON_CG_BLOCK_GFX, false); |
} |
static void cik_enable_sck_slowdown_on_pu(struct radeon_device *rdev, |
bool enable) |
{ |
u32 data, orig; |
orig = data = RREG32(RLC_PG_CNTL); |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_RLC_SMU_HS)) |
data |= SMU_CLK_SLOWDOWN_ON_PU_ENABLE; |
else |
data &= ~SMU_CLK_SLOWDOWN_ON_PU_ENABLE; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
} |
static void cik_enable_sck_slowdown_on_pd(struct radeon_device *rdev, |
bool enable) |
{ |
u32 data, orig; |
orig = data = RREG32(RLC_PG_CNTL); |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_RLC_SMU_HS)) |
data |= SMU_CLK_SLOWDOWN_ON_PD_ENABLE; |
else |
data &= ~SMU_CLK_SLOWDOWN_ON_PD_ENABLE; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
} |
static void cik_enable_cp_pg(struct radeon_device *rdev, bool enable) |
{ |
u32 data, orig; |
orig = data = RREG32(RLC_PG_CNTL); |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_CP)) |
data &= ~DISABLE_CP_PG; |
else |
data |= DISABLE_CP_PG; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
} |
static void cik_enable_gds_pg(struct radeon_device *rdev, bool enable) |
{ |
u32 data, orig; |
orig = data = RREG32(RLC_PG_CNTL); |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GDS)) |
data &= ~DISABLE_GDS_PG; |
else |
data |= DISABLE_GDS_PG; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
} |
#define CP_ME_TABLE_SIZE 96 |
#define CP_ME_TABLE_OFFSET 2048 |
#define CP_MEC_TABLE_OFFSET 4096 |
void cik_init_cp_pg_table(struct radeon_device *rdev) |
{ |
volatile u32 *dst_ptr; |
int me, i, max_me = 4; |
u32 bo_offset = 0; |
u32 table_offset, table_size; |
if (rdev->family == CHIP_KAVERI) |
max_me = 5; |
if (rdev->rlc.cp_table_ptr == NULL) |
return; |
/* write the cp table buffer */ |
dst_ptr = rdev->rlc.cp_table_ptr; |
for (me = 0; me < max_me; me++) { |
if (rdev->new_fw) { |
const __le32 *fw_data; |
const struct gfx_firmware_header_v1_0 *hdr; |
if (me == 0) { |
hdr = (const struct gfx_firmware_header_v1_0 *)rdev->ce_fw->data; |
fw_data = (const __le32 *) |
(rdev->ce_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
table_offset = le32_to_cpu(hdr->jt_offset); |
table_size = le32_to_cpu(hdr->jt_size); |
} else if (me == 1) { |
hdr = (const struct gfx_firmware_header_v1_0 *)rdev->pfp_fw->data; |
fw_data = (const __le32 *) |
(rdev->pfp_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
table_offset = le32_to_cpu(hdr->jt_offset); |
table_size = le32_to_cpu(hdr->jt_size); |
} else if (me == 2) { |
hdr = (const struct gfx_firmware_header_v1_0 *)rdev->me_fw->data; |
fw_data = (const __le32 *) |
(rdev->me_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
table_offset = le32_to_cpu(hdr->jt_offset); |
table_size = le32_to_cpu(hdr->jt_size); |
} else if (me == 3) { |
hdr = (const struct gfx_firmware_header_v1_0 *)rdev->mec_fw->data; |
fw_data = (const __le32 *) |
(rdev->mec_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
table_offset = le32_to_cpu(hdr->jt_offset); |
table_size = le32_to_cpu(hdr->jt_size); |
} else { |
hdr = (const struct gfx_firmware_header_v1_0 *)rdev->mec2_fw->data; |
fw_data = (const __le32 *) |
(rdev->mec2_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
table_offset = le32_to_cpu(hdr->jt_offset); |
table_size = le32_to_cpu(hdr->jt_size); |
} |
for (i = 0; i < table_size; i ++) { |
dst_ptr[bo_offset + i] = |
cpu_to_le32(le32_to_cpu(fw_data[table_offset + i])); |
} |
bo_offset += table_size; |
} else { |
const __be32 *fw_data; |
table_size = CP_ME_TABLE_SIZE; |
if (me == 0) { |
fw_data = (const __be32 *)rdev->ce_fw->data; |
table_offset = CP_ME_TABLE_OFFSET; |
} else if (me == 1) { |
fw_data = (const __be32 *)rdev->pfp_fw->data; |
table_offset = CP_ME_TABLE_OFFSET; |
} else if (me == 2) { |
fw_data = (const __be32 *)rdev->me_fw->data; |
table_offset = CP_ME_TABLE_OFFSET; |
} else { |
fw_data = (const __be32 *)rdev->mec_fw->data; |
table_offset = CP_MEC_TABLE_OFFSET; |
} |
for (i = 0; i < table_size; i ++) { |
dst_ptr[bo_offset + i] = |
cpu_to_le32(be32_to_cpu(fw_data[table_offset + i])); |
} |
bo_offset += table_size; |
} |
} |
} |
static void cik_enable_gfx_cgpg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 data, orig; |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG)) { |
orig = data = RREG32(RLC_PG_CNTL); |
data |= GFX_PG_ENABLE; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
orig = data = RREG32(RLC_AUTO_PG_CTRL); |
data |= AUTO_PG_EN; |
if (orig != data) |
WREG32(RLC_AUTO_PG_CTRL, data); |
} else { |
orig = data = RREG32(RLC_PG_CNTL); |
data &= ~GFX_PG_ENABLE; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
orig = data = RREG32(RLC_AUTO_PG_CTRL); |
data &= ~AUTO_PG_EN; |
if (orig != data) |
WREG32(RLC_AUTO_PG_CTRL, data); |
data = RREG32(DB_RENDER_CONTROL); |
} |
} |
static u32 cik_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh) |
{ |
u32 mask = 0, tmp, tmp1; |
int i; |
cik_select_se_sh(rdev, se, sh); |
tmp = RREG32(CC_GC_SHADER_ARRAY_CONFIG); |
tmp1 = RREG32(GC_USER_SHADER_ARRAY_CONFIG); |
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
tmp &= 0xffff0000; |
tmp |= tmp1; |
tmp >>= 16; |
for (i = 0; i < rdev->config.cik.max_cu_per_sh; i ++) { |
mask <<= 1; |
mask |= 1; |
} |
return (~tmp) & mask; |
} |
static void cik_init_ao_cu_mask(struct radeon_device *rdev) |
{ |
u32 i, j, k, active_cu_number = 0; |
u32 mask, counter, cu_bitmap; |
u32 tmp = 0; |
for (i = 0; i < rdev->config.cik.max_shader_engines; i++) { |
for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) { |
mask = 1; |
cu_bitmap = 0; |
counter = 0; |
for (k = 0; k < rdev->config.cik.max_cu_per_sh; k ++) { |
if (cik_get_cu_active_bitmap(rdev, i, j) & mask) { |
if (counter < 2) |
cu_bitmap |= mask; |
counter ++; |
} |
mask <<= 1; |
} |
active_cu_number += counter; |
tmp |= (cu_bitmap << (i * 16 + j * 8)); |
} |
} |
WREG32(RLC_PG_AO_CU_MASK, tmp); |
tmp = RREG32(RLC_MAX_PG_CU); |
tmp &= ~MAX_PU_CU_MASK; |
tmp |= MAX_PU_CU(active_cu_number); |
WREG32(RLC_MAX_PG_CU, tmp); |
} |
static void cik_enable_gfx_static_mgpg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 data, orig; |
orig = data = RREG32(RLC_PG_CNTL); |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_SMG)) |
data |= STATIC_PER_CU_PG_ENABLE; |
else |
data &= ~STATIC_PER_CU_PG_ENABLE; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
} |
static void cik_enable_gfx_dynamic_mgpg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 data, orig; |
orig = data = RREG32(RLC_PG_CNTL); |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_DMG)) |
data |= DYN_PER_CU_PG_ENABLE; |
else |
data &= ~DYN_PER_CU_PG_ENABLE; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
} |
#define RLC_SAVE_AND_RESTORE_STARTING_OFFSET 0x90 |
#define RLC_CLEAR_STATE_DESCRIPTOR_OFFSET 0x3D |
static void cik_init_gfx_cgpg(struct radeon_device *rdev) |
{ |
u32 data, orig; |
u32 i; |
if (rdev->rlc.cs_data) { |
WREG32(RLC_GPM_SCRATCH_ADDR, RLC_CLEAR_STATE_DESCRIPTOR_OFFSET); |
WREG32(RLC_GPM_SCRATCH_DATA, upper_32_bits(rdev->rlc.clear_state_gpu_addr)); |
WREG32(RLC_GPM_SCRATCH_DATA, lower_32_bits(rdev->rlc.clear_state_gpu_addr)); |
WREG32(RLC_GPM_SCRATCH_DATA, rdev->rlc.clear_state_size); |
} else { |
WREG32(RLC_GPM_SCRATCH_ADDR, RLC_CLEAR_STATE_DESCRIPTOR_OFFSET); |
for (i = 0; i < 3; i++) |
WREG32(RLC_GPM_SCRATCH_DATA, 0); |
} |
if (rdev->rlc.reg_list) { |
WREG32(RLC_GPM_SCRATCH_ADDR, RLC_SAVE_AND_RESTORE_STARTING_OFFSET); |
for (i = 0; i < rdev->rlc.reg_list_size; i++) |
WREG32(RLC_GPM_SCRATCH_DATA, rdev->rlc.reg_list[i]); |
} |
orig = data = RREG32(RLC_PG_CNTL); |
data |= GFX_PG_SRC; |
if (orig != data) |
WREG32(RLC_PG_CNTL, data); |
WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8); |
WREG32(RLC_CP_TABLE_RESTORE, rdev->rlc.cp_table_gpu_addr >> 8); |
data = RREG32(CP_RB_WPTR_POLL_CNTL); |
data &= ~IDLE_POLL_COUNT_MASK; |
data |= IDLE_POLL_COUNT(0x60); |
WREG32(CP_RB_WPTR_POLL_CNTL, data); |
data = 0x10101010; |
WREG32(RLC_PG_DELAY, data); |
data = RREG32(RLC_PG_DELAY_2); |
data &= ~0xff; |
data |= 0x3; |
WREG32(RLC_PG_DELAY_2, data); |
data = RREG32(RLC_AUTO_PG_CTRL); |
data &= ~GRBM_REG_SGIT_MASK; |
data |= GRBM_REG_SGIT(0x700); |
WREG32(RLC_AUTO_PG_CTRL, data); |
} |
static void cik_update_gfx_pg(struct radeon_device *rdev, bool enable) |
{ |
cik_enable_gfx_cgpg(rdev, enable); |
cik_enable_gfx_static_mgpg(rdev, enable); |
cik_enable_gfx_dynamic_mgpg(rdev, enable); |
} |
u32 cik_get_csb_size(struct radeon_device *rdev) |
{ |
u32 count = 0; |
const struct cs_section_def *sect = NULL; |
const struct cs_extent_def *ext = NULL; |
if (rdev->rlc.cs_data == NULL) |
return 0; |
/* begin clear state */ |
count += 2; |
/* context control state */ |
count += 3; |
for (sect = rdev->rlc.cs_data; sect->section != NULL; ++sect) { |
for (ext = sect->section; ext->extent != NULL; ++ext) { |
if (sect->id == SECT_CONTEXT) |
count += 2 + ext->reg_count; |
else |
return 0; |
} |
} |
/* pa_sc_raster_config/pa_sc_raster_config1 */ |
count += 4; |
/* end clear state */ |
count += 2; |
/* clear state */ |
count += 2; |
return count; |
} |
void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer) |
{ |
u32 count = 0, i; |
const struct cs_section_def *sect = NULL; |
const struct cs_extent_def *ext = NULL; |
if (rdev->rlc.cs_data == NULL) |
return; |
if (buffer == NULL) |
return; |
buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0)); |
buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_BEGIN_CLEAR_STATE); |
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++] = |
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++] = cpu_to_le32(ext->extent[i]); |
} else { |
return; |
} |
} |
} |
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++] = cpu_to_le32(0x16000012); |
buffer[count++] = cpu_to_le32(0x00000000); |
break; |
case CHIP_KAVERI: |
buffer[count++] = cpu_to_le32(0x00000000); /* XXX */ |
buffer[count++] = cpu_to_le32(0x00000000); |
break; |
case CHIP_KABINI: |
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++] = cpu_to_le32(0x00000000); |
buffer[count++] = cpu_to_le32(0x00000000); |
break; |
} |
buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0)); |
buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_END_CLEAR_STATE); |
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) |
{ |
if (rdev->pg_flags) { |
cik_enable_sck_slowdown_on_pu(rdev, true); |
cik_enable_sck_slowdown_on_pd(rdev, true); |
if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG) { |
cik_init_gfx_cgpg(rdev); |
cik_enable_cp_pg(rdev, true); |
cik_enable_gds_pg(rdev, true); |
} |
cik_init_ao_cu_mask(rdev); |
cik_update_gfx_pg(rdev, true); |
} |
} |
static void cik_fini_pg(struct radeon_device *rdev) |
{ |
if (rdev->pg_flags) { |
cik_update_gfx_pg(rdev, false); |
if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG) { |
cik_enable_cp_pg(rdev, false); |
cik_enable_gds_pg(rdev, false); |
} |
} |
} |
/* |
* Interrupts |
* Starting with r6xx, interrupts are handled via a ring buffer. |
* Ring buffers are areas of GPU accessible memory that the GPU |
* writes interrupt vectors into and the host reads vectors out of. |
* There is a rptr (read pointer) that determines where the |
* host is currently reading, and a wptr (write pointer) |
* which determines where the GPU has written. When the |
* pointers are equal, the ring is idle. When the GPU |
* writes vectors to the ring buffer, it increments the |
* wptr. When there is an interrupt, the host then starts |
* fetching commands and processing them until the pointers are |
* equal again at which point it updates the rptr. |
*/ |
/** |
* cik_enable_interrupts - Enable the interrupt ring buffer |
* |
* @rdev: radeon_device pointer |
* |
* Enable the interrupt ring buffer (CIK). |
*/ |
static void cik_enable_interrupts(struct radeon_device *rdev) |
{ |
u32 ih_cntl = RREG32(IH_CNTL); |
u32 ih_rb_cntl = RREG32(IH_RB_CNTL); |
ih_cntl |= ENABLE_INTR; |
ih_rb_cntl |= IH_RB_ENABLE; |
WREG32(IH_CNTL, ih_cntl); |
WREG32(IH_RB_CNTL, ih_rb_cntl); |
rdev->ih.enabled = true; |
} |
/** |
* cik_disable_interrupts - Disable the interrupt ring buffer |
* |
* @rdev: radeon_device pointer |
* |
* Disable the interrupt ring buffer (CIK). |
*/ |
static void cik_disable_interrupts(struct radeon_device *rdev) |
{ |
u32 ih_rb_cntl = RREG32(IH_RB_CNTL); |
u32 ih_cntl = RREG32(IH_CNTL); |
ih_rb_cntl &= ~IH_RB_ENABLE; |
ih_cntl &= ~ENABLE_INTR; |
WREG32(IH_RB_CNTL, ih_rb_cntl); |
WREG32(IH_CNTL, ih_cntl); |
/* set rptr, wptr to 0 */ |
WREG32(IH_RB_RPTR, 0); |
WREG32(IH_RB_WPTR, 0); |
rdev->ih.enabled = false; |
rdev->ih.rptr = 0; |
} |
/** |
* cik_disable_interrupt_state - Disable all interrupt sources |
* |
* @rdev: radeon_device pointer |
* |
* Clear all interrupt enable bits used by the driver (CIK). |
*/ |
static void cik_disable_interrupt_state(struct radeon_device *rdev) |
{ |
u32 tmp; |
/* gfx ring */ |
tmp = RREG32(CP_INT_CNTL_RING0) & |
(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
WREG32(CP_INT_CNTL_RING0, tmp); |
/* sdma */ |
tmp = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE; |
WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, tmp); |
tmp = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE; |
WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, tmp); |
/* compute queues */ |
WREG32(CP_ME1_PIPE0_INT_CNTL, 0); |
WREG32(CP_ME1_PIPE1_INT_CNTL, 0); |
WREG32(CP_ME1_PIPE2_INT_CNTL, 0); |
WREG32(CP_ME1_PIPE3_INT_CNTL, 0); |
WREG32(CP_ME2_PIPE0_INT_CNTL, 0); |
WREG32(CP_ME2_PIPE1_INT_CNTL, 0); |
WREG32(CP_ME2_PIPE2_INT_CNTL, 0); |
WREG32(CP_ME2_PIPE3_INT_CNTL, 0); |
/* grbm */ |
WREG32(GRBM_INT_CNTL, 0); |
/* vline/vblank, etc. */ |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); |
if (rdev->num_crtc >= 4) { |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); |
} |
if (rdev->num_crtc >= 6) { |
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); |
/* digital hotplug */ |
tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY; |
WREG32(DC_HPD1_INT_CONTROL, tmp); |
tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY; |
WREG32(DC_HPD2_INT_CONTROL, tmp); |
tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY; |
WREG32(DC_HPD3_INT_CONTROL, tmp); |
tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY; |
WREG32(DC_HPD4_INT_CONTROL, tmp); |
tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY; |
WREG32(DC_HPD5_INT_CONTROL, tmp); |
tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY; |
WREG32(DC_HPD6_INT_CONTROL, tmp); |
} |
/** |
* cik_irq_init - init and enable the interrupt ring |
* |
* @rdev: radeon_device pointer |
* |
* Allocate a ring buffer for the interrupt controller, |
* enable the RLC, disable interrupts, enable the IH |
* ring buffer and enable it (CIK). |
* Called at device load and reume. |
* Returns 0 for success, errors for failure. |
*/ |
static int cik_irq_init(struct radeon_device *rdev) |
{ |
int ret = 0; |
int rb_bufsz; |
u32 interrupt_cntl, ih_cntl, ih_rb_cntl; |
/* allocate ring */ |
ret = r600_ih_ring_alloc(rdev); |
if (ret) |
return ret; |
/* disable irqs */ |
cik_disable_interrupts(rdev); |
/* init rlc */ |
ret = cik_rlc_resume(rdev); |
if (ret) { |
r600_ih_ring_fini(rdev); |
return ret; |
} |
/* setup interrupt control */ |
/* XXX this should actually be a bus address, not an MC address. same on older asics */ |
WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8); |
interrupt_cntl = RREG32(INTERRUPT_CNTL); |
/* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi |
* IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN |
*/ |
interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE; |
/* IH_REQ_NONSNOOP_EN=1 if ring is in non-cacheable memory, e.g., vram */ |
interrupt_cntl &= ~IH_REQ_NONSNOOP_EN; |
WREG32(INTERRUPT_CNTL, interrupt_cntl); |
WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8); |
rb_bufsz = order_base_2(rdev->ih.ring_size / 4); |
ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE | |
IH_WPTR_OVERFLOW_CLEAR | |
(rb_bufsz << 1)); |
if (rdev->wb.enabled) |
ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE; |
/* set the writeback address whether it's enabled or not */ |
WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC); |
WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF); |
WREG32(IH_RB_CNTL, ih_rb_cntl); |
/* set rptr, wptr to 0 */ |
WREG32(IH_RB_RPTR, 0); |
WREG32(IH_RB_WPTR, 0); |
/* Default settings for IH_CNTL (disabled at first) */ |
ih_cntl = MC_WRREQ_CREDIT(0x10) | MC_WR_CLEAN_CNT(0x10) | MC_VMID(0); |
/* RPTR_REARM only works if msi's are enabled */ |
if (rdev->msi_enabled) |
ih_cntl |= RPTR_REARM; |
WREG32(IH_CNTL, ih_cntl); |
/* force the active interrupt state to all disabled */ |
cik_disable_interrupt_state(rdev); |
// pci_set_master(rdev->pdev); |
/* enable irqs */ |
cik_enable_interrupts(rdev); |
return ret; |
} |
/** |
* cik_irq_set - enable/disable interrupt sources |
* |
* @rdev: radeon_device pointer |
* |
* Enable interrupt sources on the GPU (vblanks, hpd, |
* etc.) (CIK). |
* Returns 0 for success, errors for failure. |
*/ |
int cik_irq_set(struct radeon_device *rdev) |
{ |
u32 cp_int_cntl; |
u32 cp_m1p0, cp_m1p1, cp_m1p2, cp_m1p3; |
u32 cp_m2p0, cp_m2p1, cp_m2p2, cp_m2p3; |
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 dma_cntl, dma_cntl1; |
u32 thermal_int; |
if (!rdev->irq.installed) { |
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
return -EINVAL; |
} |
/* don't enable anything if the ih is disabled */ |
if (!rdev->ih.enabled) { |
cik_disable_interrupts(rdev); |
/* force the active interrupt state to all disabled */ |
cik_disable_interrupt_state(rdev); |
return 0; |
} |
cp_int_cntl = RREG32(CP_INT_CNTL_RING0) & |
(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
cp_int_cntl |= PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE; |
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; |
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; |
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; |
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; |
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; |
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; |
dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE; |
dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE; |
cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
cp_m1p1 = RREG32(CP_ME1_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
cp_m1p2 = RREG32(CP_ME1_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
cp_m1p3 = RREG32(CP_ME1_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
cp_m2p0 = RREG32(CP_ME2_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
cp_m2p1 = RREG32(CP_ME2_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; |
if (rdev->flags & RADEON_IS_IGP) |
thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL) & |
~(THERM_INTH_MASK | THERM_INTL_MASK); |
else |
thermal_int = RREG32_SMC(CG_THERMAL_INT) & |
~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); |
/* enable CP interrupts on all rings */ |
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { |
DRM_DEBUG("cik_irq_set: sw int gfx\n"); |
cp_int_cntl |= TIME_STAMP_INT_ENABLE; |
} |
if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP1_INDEX])) { |
struct radeon_ring *ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; |
DRM_DEBUG("si_irq_set: sw int cp1\n"); |
if (ring->me == 1) { |
switch (ring->pipe) { |
case 0: |
cp_m1p0 |= TIME_STAMP_INT_ENABLE; |
break; |
case 1: |
cp_m1p1 |= TIME_STAMP_INT_ENABLE; |
break; |
case 2: |
cp_m1p2 |= TIME_STAMP_INT_ENABLE; |
break; |
case 3: |
cp_m1p2 |= TIME_STAMP_INT_ENABLE; |
break; |
default: |
DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe); |
break; |
} |
} else if (ring->me == 2) { |
switch (ring->pipe) { |
case 0: |
cp_m2p0 |= TIME_STAMP_INT_ENABLE; |
break; |
case 1: |
cp_m2p1 |= TIME_STAMP_INT_ENABLE; |
break; |
case 2: |
cp_m2p2 |= TIME_STAMP_INT_ENABLE; |
break; |
case 3: |
cp_m2p2 |= TIME_STAMP_INT_ENABLE; |
break; |
default: |
DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe); |
break; |
} |
} else { |
DRM_DEBUG("si_irq_set: sw int cp1 invalid me %d\n", ring->me); |
} |
} |
if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP2_INDEX])) { |
struct radeon_ring *ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; |
DRM_DEBUG("si_irq_set: sw int cp2\n"); |
if (ring->me == 1) { |
switch (ring->pipe) { |
case 0: |
cp_m1p0 |= TIME_STAMP_INT_ENABLE; |
break; |
case 1: |
cp_m1p1 |= TIME_STAMP_INT_ENABLE; |
break; |
case 2: |
cp_m1p2 |= TIME_STAMP_INT_ENABLE; |
break; |
case 3: |
cp_m1p2 |= TIME_STAMP_INT_ENABLE; |
break; |
default: |
DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe); |
break; |
} |
} else if (ring->me == 2) { |
switch (ring->pipe) { |
case 0: |
cp_m2p0 |= TIME_STAMP_INT_ENABLE; |
break; |
case 1: |
cp_m2p1 |= TIME_STAMP_INT_ENABLE; |
break; |
case 2: |
cp_m2p2 |= TIME_STAMP_INT_ENABLE; |
break; |
case 3: |
cp_m2p2 |= TIME_STAMP_INT_ENABLE; |
break; |
default: |
DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe); |
break; |
} |
} else { |
DRM_DEBUG("si_irq_set: sw int cp2 invalid me %d\n", ring->me); |
} |
} |
if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) { |
DRM_DEBUG("cik_irq_set: sw int dma\n"); |
dma_cntl |= TRAP_ENABLE; |
} |
if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_DMA1_INDEX])) { |
DRM_DEBUG("cik_irq_set: sw int dma1\n"); |
dma_cntl1 |= TRAP_ENABLE; |
} |
if (rdev->irq.crtc_vblank_int[0] || |
atomic_read(&rdev->irq.pflip[0])) { |
DRM_DEBUG("cik_irq_set: vblank 0\n"); |
crtc1 |= VBLANK_INTERRUPT_MASK; |
} |
if (rdev->irq.crtc_vblank_int[1] || |
atomic_read(&rdev->irq.pflip[1])) { |
DRM_DEBUG("cik_irq_set: vblank 1\n"); |
crtc2 |= VBLANK_INTERRUPT_MASK; |
} |
if (rdev->irq.crtc_vblank_int[2] || |
atomic_read(&rdev->irq.pflip[2])) { |
DRM_DEBUG("cik_irq_set: vblank 2\n"); |
crtc3 |= VBLANK_INTERRUPT_MASK; |
} |
if (rdev->irq.crtc_vblank_int[3] || |
atomic_read(&rdev->irq.pflip[3])) { |
DRM_DEBUG("cik_irq_set: vblank 3\n"); |
crtc4 |= VBLANK_INTERRUPT_MASK; |
} |
if (rdev->irq.crtc_vblank_int[4] || |
atomic_read(&rdev->irq.pflip[4])) { |
DRM_DEBUG("cik_irq_set: vblank 4\n"); |
crtc5 |= VBLANK_INTERRUPT_MASK; |
} |
if (rdev->irq.crtc_vblank_int[5] || |
atomic_read(&rdev->irq.pflip[5])) { |
DRM_DEBUG("cik_irq_set: vblank 5\n"); |
crtc6 |= VBLANK_INTERRUPT_MASK; |
} |
if (rdev->irq.hpd[0]) { |
DRM_DEBUG("cik_irq_set: hpd 1\n"); |
hpd1 |= DC_HPDx_INT_EN; |
} |
if (rdev->irq.hpd[1]) { |
DRM_DEBUG("cik_irq_set: hpd 2\n"); |
hpd2 |= DC_HPDx_INT_EN; |
} |
if (rdev->irq.hpd[2]) { |
DRM_DEBUG("cik_irq_set: hpd 3\n"); |
hpd3 |= DC_HPDx_INT_EN; |
} |
if (rdev->irq.hpd[3]) { |
DRM_DEBUG("cik_irq_set: hpd 4\n"); |
hpd4 |= DC_HPDx_INT_EN; |
} |
if (rdev->irq.hpd[4]) { |
DRM_DEBUG("cik_irq_set: hpd 5\n"); |
hpd5 |= DC_HPDx_INT_EN; |
} |
if (rdev->irq.hpd[5]) { |
DRM_DEBUG("cik_irq_set: hpd 6\n"); |
hpd6 |= DC_HPDx_INT_EN; |
} |
if (rdev->irq.dpm_thermal) { |
DRM_DEBUG("dpm thermal\n"); |
if (rdev->flags & RADEON_IS_IGP) |
thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK; |
else |
thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; |
} |
WREG32(CP_INT_CNTL_RING0, cp_int_cntl); |
WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl); |
WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, dma_cntl1); |
WREG32(CP_ME1_PIPE0_INT_CNTL, cp_m1p0); |
WREG32(CP_ME1_PIPE1_INT_CNTL, cp_m1p1); |
WREG32(CP_ME1_PIPE2_INT_CNTL, cp_m1p2); |
WREG32(CP_ME1_PIPE3_INT_CNTL, cp_m1p3); |
WREG32(CP_ME2_PIPE0_INT_CNTL, cp_m2p0); |
WREG32(CP_ME2_PIPE1_INT_CNTL, cp_m2p1); |
WREG32(CP_ME2_PIPE2_INT_CNTL, cp_m2p2); |
WREG32(CP_ME2_PIPE3_INT_CNTL, cp_m2p3); |
WREG32(GRBM_INT_CNTL, grbm_int_cntl); |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); |
if (rdev->num_crtc >= 4) { |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); |
} |
if (rdev->num_crtc >= 6) { |
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); |
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); |
WREG32(DC_HPD4_INT_CONTROL, hpd4); |
WREG32(DC_HPD5_INT_CONTROL, hpd5); |
WREG32(DC_HPD6_INT_CONTROL, hpd6); |
if (rdev->flags & RADEON_IS_IGP) |
WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int); |
else |
WREG32_SMC(CG_THERMAL_INT, thermal_int); |
return 0; |
} |
/** |
* cik_irq_ack - ack interrupt sources |
* |
* @rdev: radeon_device pointer |
* |
* Ack interrupt sources on the GPU (vblanks, hpd, |
* etc.) (CIK). Certain interrupts sources are sw |
* generated and do not require an explicit ack. |
*/ |
static inline void cik_irq_ack(struct radeon_device *rdev) |
{ |
u32 tmp; |
rdev->irq.stat_regs.cik.disp_int = RREG32(DISP_INTERRUPT_STATUS); |
rdev->irq.stat_regs.cik.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); |
rdev->irq.stat_regs.cik.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2); |
rdev->irq.stat_regs.cik.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3); |
rdev->irq.stat_regs.cik.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4); |
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) |
WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK); |
if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) |
WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK); |
if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) |
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) |
WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK); |
if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) |
WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK); |
if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) |
WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK); |
} |
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) |
WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK); |
if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) |
WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK); |
if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) |
WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK); |
} |
if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) { |
tmp = RREG32(DC_HPD1_INT_CONTROL); |
tmp |= DC_HPDx_INT_ACK; |
WREG32(DC_HPD1_INT_CONTROL, tmp); |
} |
if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) { |
tmp = RREG32(DC_HPD2_INT_CONTROL); |
tmp |= DC_HPDx_INT_ACK; |
WREG32(DC_HPD2_INT_CONTROL, tmp); |
} |
if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) { |
tmp = RREG32(DC_HPD3_INT_CONTROL); |
tmp |= DC_HPDx_INT_ACK; |
WREG32(DC_HPD3_INT_CONTROL, tmp); |
} |
if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) { |
tmp = RREG32(DC_HPD4_INT_CONTROL); |
tmp |= DC_HPDx_INT_ACK; |
WREG32(DC_HPD4_INT_CONTROL, tmp); |
} |
if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) { |
tmp = RREG32(DC_HPD5_INT_CONTROL); |
tmp |= DC_HPDx_INT_ACK; |
WREG32(DC_HPD5_INT_CONTROL, tmp); |
} |
if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) { |
tmp = RREG32(DC_HPD5_INT_CONTROL); |
tmp |= DC_HPDx_INT_ACK; |
WREG32(DC_HPD6_INT_CONTROL, tmp); |
} |
} |
/** |
* cik_irq_disable - disable interrupts |
* |
* @rdev: radeon_device pointer |
* |
* Disable interrupts on the hw (CIK). |
*/ |
static void cik_irq_disable(struct radeon_device *rdev) |
{ |
cik_disable_interrupts(rdev); |
/* Wait and acknowledge irq */ |
mdelay(1); |
cik_irq_ack(rdev); |
cik_disable_interrupt_state(rdev); |
} |
/** |
* cik_irq_disable - disable interrupts for suspend |
* |
* @rdev: radeon_device pointer |
* |
* Disable interrupts and stop the RLC (CIK). |
* Used for suspend. |
*/ |
static void cik_irq_suspend(struct radeon_device *rdev) |
{ |
cik_irq_disable(rdev); |
cik_rlc_stop(rdev); |
} |
/** |
* cik_irq_fini - tear down interrupt support |
* |
* @rdev: radeon_device pointer |
* |
* Disable interrupts on the hw and free the IH ring |
* buffer (CIK). |
* Used for driver unload. |
*/ |
static void cik_irq_fini(struct radeon_device *rdev) |
{ |
cik_irq_suspend(rdev); |
r600_ih_ring_fini(rdev); |
} |
/** |
* cik_get_ih_wptr - get the IH ring buffer wptr |
* |
* @rdev: radeon_device pointer |
* |
* Get the IH ring buffer wptr from either the register |
* or the writeback memory buffer (CIK). Also check for |
* ring buffer overflow and deal with it. |
* Used by cik_irq_process(). |
* Returns the value of the wptr. |
*/ |
static inline u32 cik_get_ih_wptr(struct radeon_device *rdev) |
{ |
u32 wptr, tmp; |
if (rdev->wb.enabled) |
wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]); |
else |
wptr = RREG32(IH_RB_WPTR); |
if (wptr & RB_OVERFLOW) { |
/* When a ring buffer overflow happen start parsing interrupt |
* from the last not overwritten vector (wptr + 16). Hopefully |
* this should allow us to catchup. |
*/ |
dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", |
wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); |
rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; |
tmp = RREG32(IH_RB_CNTL); |
tmp |= IH_WPTR_OVERFLOW_CLEAR; |
WREG32(IH_RB_CNTL, tmp); |
wptr &= ~RB_OVERFLOW; |
} |
return (wptr & rdev->ih.ptr_mask); |
} |
/* CIK IV Ring |
* Each IV ring entry is 128 bits: |
* [7:0] - interrupt source id |
* [31:8] - reserved |
* [59:32] - interrupt source data |
* [63:60] - reserved |
* [71:64] - RINGID |
* CP: |
* ME_ID [1:0], PIPE_ID[1:0], QUEUE_ID[2:0] |
* QUEUE_ID - for compute, which of the 8 queues owned by the dispatcher |
* - for gfx, hw shader state (0=PS...5=LS, 6=CS) |
* ME_ID - 0 = gfx, 1 = first 4 CS pipes, 2 = second 4 CS pipes |
* PIPE_ID - ME0 0=3D |
* - ME1&2 compute dispatcher (4 pipes each) |
* SDMA: |
* INSTANCE_ID [1:0], QUEUE_ID[1:0] |
* INSTANCE_ID - 0 = sdma0, 1 = sdma1 |
* QUEUE_ID - 0 = gfx, 1 = rlc0, 2 = rlc1 |
* [79:72] - VMID |
* [95:80] - PASID |
* [127:96] - reserved |
*/ |
/** |
* cik_irq_process - interrupt handler |
* |
* @rdev: radeon_device pointer |
* |
* Interrupt hander (CIK). Walk the IH ring, |
* ack interrupts and schedule work to handle |
* interrupt events. |
* Returns irq process return code. |
*/ |
int cik_irq_process(struct radeon_device *rdev) |
{ |
struct radeon_ring *cp1_ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; |
struct radeon_ring *cp2_ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; |
u32 wptr; |
u32 rptr; |
u32 src_id, src_data, ring_id; |
u8 me_id, pipe_id, queue_id; |
u32 ring_index; |
bool queue_hotplug = false; |
bool queue_reset = false; |
u32 addr, status, mc_client; |
bool queue_thermal = false; |
if (!rdev->ih.enabled || rdev->shutdown) |
return IRQ_NONE; |
wptr = cik_get_ih_wptr(rdev); |
restart_ih: |
/* is somebody else already processing irqs? */ |
if (atomic_xchg(&rdev->ih.lock, 1)) |
return IRQ_NONE; |
rptr = rdev->ih.rptr; |
DRM_DEBUG("cik_irq_process start: rptr %d, wptr %d\n", rptr, wptr); |
/* Order reading of wptr vs. reading of IH ring data */ |
rmb(); |
/* display interrupts */ |
cik_irq_ack(rdev); |
while (rptr != wptr) { |
/* wptr/rptr are in bytes! */ |
ring_index = rptr / 4; |
src_id = le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff; |
src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff; |
ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff; |
switch (src_id) { |
case 1: /* D1 vblank/vline */ |
switch (src_data) { |
case 0: /* D1 vblank */ |
if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT) { |
if (rdev->irq.crtc_vblank_int[0]) { |
rdev->pm.vblank_sync = true; |
} |
rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT; |
DRM_DEBUG("IH: D1 vblank\n"); |
} |
break; |
case 1: /* D1 vline */ |
if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT; |
DRM_DEBUG("IH: D1 vline\n"); |
} |
break; |
default: |
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
break; |
} |
break; |
case 2: /* D2 vblank/vline */ |
switch (src_data) { |
case 0: /* D2 vblank */ |
if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { |
if (rdev->irq.crtc_vblank_int[1]) { |
rdev->pm.vblank_sync = true; |
} |
rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; |
DRM_DEBUG("IH: D2 vblank\n"); |
} |
break; |
case 1: /* D2 vline */ |
if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; |
DRM_DEBUG("IH: D2 vline\n"); |
} |
break; |
default: |
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
break; |
} |
break; |
case 3: /* D3 vblank/vline */ |
switch (src_data) { |
case 0: /* D3 vblank */ |
if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { |
if (rdev->irq.crtc_vblank_int[2]) { |
rdev->pm.vblank_sync = true; |
} |
rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; |
DRM_DEBUG("IH: D3 vblank\n"); |
} |
break; |
case 1: /* D3 vline */ |
if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; |
DRM_DEBUG("IH: D3 vline\n"); |
} |
break; |
default: |
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
break; |
} |
break; |
case 4: /* D4 vblank/vline */ |
switch (src_data) { |
case 0: /* D4 vblank */ |
if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { |
if (rdev->irq.crtc_vblank_int[3]) { |
rdev->pm.vblank_sync = true; |
} |
rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; |
DRM_DEBUG("IH: D4 vblank\n"); |
} |
break; |
case 1: /* D4 vline */ |
if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; |
DRM_DEBUG("IH: D4 vline\n"); |
} |
break; |
default: |
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
break; |
} |
break; |
case 5: /* D5 vblank/vline */ |
switch (src_data) { |
case 0: /* D5 vblank */ |
if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { |
if (rdev->irq.crtc_vblank_int[4]) { |
rdev->pm.vblank_sync = true; |
} |
rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; |
DRM_DEBUG("IH: D5 vblank\n"); |
} |
break; |
case 1: /* D5 vline */ |
if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; |
DRM_DEBUG("IH: D5 vline\n"); |
} |
break; |
default: |
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
break; |
} |
break; |
case 6: /* D6 vblank/vline */ |
switch (src_data) { |
case 0: /* D6 vblank */ |
if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { |
if (rdev->irq.crtc_vblank_int[5]) { |
rdev->pm.vblank_sync = true; |
} |
rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; |
DRM_DEBUG("IH: D6 vblank\n"); |
} |
break; |
case 1: /* D6 vline */ |
if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; |
DRM_DEBUG("IH: D6 vline\n"); |
} |
break; |
default: |
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
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); |
break; |
case 42: /* HPD hotplug */ |
switch (src_data) { |
case 0: |
if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT; |
queue_hotplug = true; |
DRM_DEBUG("IH: HPD1\n"); |
} |
break; |
case 1: |
if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT; |
queue_hotplug = true; |
DRM_DEBUG("IH: HPD2\n"); |
} |
break; |
case 2: |
if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; |
queue_hotplug = true; |
DRM_DEBUG("IH: HPD3\n"); |
} |
break; |
case 3: |
if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; |
queue_hotplug = true; |
DRM_DEBUG("IH: HPD4\n"); |
} |
break; |
case 4: |
if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; |
queue_hotplug = true; |
DRM_DEBUG("IH: HPD5\n"); |
} |
break; |
case 5: |
if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) { |
rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; |
queue_hotplug = true; |
DRM_DEBUG("IH: HPD6\n"); |
} |
break; |
default: |
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
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); |
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); |
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 */ |
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); |
break; |
case 181: /* CP EOP event */ |
DRM_DEBUG("IH: CP EOP\n"); |
/* XXX check the bitfield order! */ |
me_id = (ring_id & 0x60) >> 5; |
pipe_id = (ring_id & 0x18) >> 3; |
queue_id = (ring_id & 0x7) >> 0; |
switch (me_id) { |
case 0: |
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); |
break; |
case 1: |
case 2: |
if ((cp1_ring->me == me_id) & (cp1_ring->pipe == pipe_id)) |
radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP1_INDEX); |
if ((cp2_ring->me == me_id) & (cp2_ring->pipe == pipe_id)) |
radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP2_INDEX); |
break; |
} |
break; |
case 184: /* CP Privileged reg access */ |
DRM_ERROR("Illegal register access in command stream\n"); |
/* XXX check the bitfield order! */ |
me_id = (ring_id & 0x60) >> 5; |
pipe_id = (ring_id & 0x18) >> 3; |
queue_id = (ring_id & 0x7) >> 0; |
switch (me_id) { |
case 0: |
/* This results in a full GPU reset, but all we need to do is soft |
* reset the CP for gfx |
*/ |
queue_reset = true; |
break; |
case 1: |
/* XXX compute */ |
queue_reset = true; |
break; |
case 2: |
/* XXX compute */ |
queue_reset = true; |
break; |
} |
break; |
case 185: /* CP Privileged inst */ |
DRM_ERROR("Illegal instruction in command stream\n"); |
/* XXX check the bitfield order! */ |
me_id = (ring_id & 0x60) >> 5; |
pipe_id = (ring_id & 0x18) >> 3; |
queue_id = (ring_id & 0x7) >> 0; |
switch (me_id) { |
case 0: |
/* This results in a full GPU reset, but all we need to do is soft |
* reset the CP for gfx |
*/ |
queue_reset = true; |
break; |
case 1: |
/* XXX compute */ |
queue_reset = true; |
break; |
case 2: |
/* XXX compute */ |
queue_reset = true; |
break; |
} |
break; |
case 224: /* SDMA trap event */ |
/* XXX check the bitfield order! */ |
me_id = (ring_id & 0x3) >> 0; |
queue_id = (ring_id & 0xc) >> 2; |
DRM_DEBUG("IH: SDMA trap\n"); |
switch (me_id) { |
case 0: |
switch (queue_id) { |
case 0: |
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX); |
break; |
case 1: |
/* XXX compute */ |
break; |
case 2: |
/* XXX compute */ |
break; |
} |
break; |
case 1: |
switch (queue_id) { |
case 0: |
radeon_fence_process(rdev, CAYMAN_RING_TYPE_DMA1_INDEX); |
break; |
case 1: |
/* XXX compute */ |
break; |
case 2: |
/* XXX compute */ |
break; |
} |
break; |
} |
break; |
case 230: /* thermal low to high */ |
DRM_DEBUG("IH: thermal low to high\n"); |
rdev->pm.dpm.thermal.high_to_low = false; |
queue_thermal = true; |
break; |
case 231: /* thermal high to low */ |
DRM_DEBUG("IH: thermal high to low\n"); |
rdev->pm.dpm.thermal.high_to_low = true; |
queue_thermal = true; |
break; |
case 233: /* GUI IDLE */ |
DRM_DEBUG("IH: GUI idle\n"); |
break; |
case 241: /* SDMA Privileged inst */ |
case 247: /* SDMA Privileged inst */ |
DRM_ERROR("Illegal instruction in SDMA command stream\n"); |
/* XXX check the bitfield order! */ |
me_id = (ring_id & 0x3) >> 0; |
queue_id = (ring_id & 0xc) >> 2; |
switch (me_id) { |
case 0: |
switch (queue_id) { |
case 0: |
queue_reset = true; |
break; |
case 1: |
/* XXX compute */ |
queue_reset = true; |
break; |
case 2: |
/* XXX compute */ |
queue_reset = true; |
break; |
} |
break; |
case 1: |
switch (queue_id) { |
case 0: |
queue_reset = true; |
break; |
case 1: |
/* XXX compute */ |
queue_reset = true; |
break; |
case 2: |
/* XXX compute */ |
queue_reset = true; |
break; |
} |
break; |
} |
break; |
default: |
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); |
break; |
} |
/* wptr/rptr are in bytes! */ |
rptr += 16; |
rptr &= rdev->ih.ptr_mask; |
} |
rdev->ih.rptr = rptr; |
WREG32(IH_RB_RPTR, rdev->ih.rptr); |
atomic_set(&rdev->ih.lock, 0); |
/* make sure wptr hasn't changed while processing */ |
wptr = cik_get_ih_wptr(rdev); |
if (wptr != rptr) |
goto restart_ih; |
return IRQ_HANDLED; |
} |
/* |
* startup/shutdown callbacks |
*/ |
/** |
* cik_startup - program the asic to a functional state |
* |
* @rdev: radeon_device pointer |
* |
* Programs the asic to a functional state (CIK). |
* Called by cik_init() and cik_resume(). |
* Returns 0 for success, error for failure. |
*/ |
static int cik_startup(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring; |
u32 nop; |
int r; |
/* enable pcie gen2/3 link */ |
cik_pcie_gen3_enable(rdev); |
/* enable aspm */ |
cik_program_aspm(rdev); |
/* scratch needs to be initialized before MC */ |
r = r600_vram_scratch_init(rdev); |
if (r) |
return r; |
cik_mc_program(rdev); |
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"); |
return r; |
} |
} |
r = cik_pcie_gart_enable(rdev); |
if (r) |
return r; |
cik_gpu_init(rdev); |
/* allocate rlc buffers */ |
if (rdev->flags & RADEON_IS_IGP) { |
if (rdev->family == CHIP_KAVERI) { |
rdev->rlc.reg_list = spectre_rlc_save_restore_register_list; |
rdev->rlc.reg_list_size = |
(u32)ARRAY_SIZE(spectre_rlc_save_restore_register_list); |
} else { |
rdev->rlc.reg_list = kalindi_rlc_save_restore_register_list; |
rdev->rlc.reg_list_size = |
(u32)ARRAY_SIZE(kalindi_rlc_save_restore_register_list); |
} |
} |
rdev->rlc.cs_data = ci_cs_data; |
rdev->rlc.cp_table_size = CP_ME_TABLE_SIZE * 5 * 4; |
r = sumo_rlc_init(rdev); |
if (r) { |
DRM_ERROR("Failed to init rlc BOs!\n"); |
return r; |
} |
/* allocate wb buffer */ |
r = radeon_wb_init(rdev); |
if (r) |
return r; |
/* allocate mec buffers */ |
r = cik_mec_init(rdev); |
if (r) { |
DRM_ERROR("Failed to init MEC BOs!\n"); |
return r; |
} |
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX); |
if (r) { |
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); |
return r; |
} |
r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX); |
if (r) { |
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); |
return r; |
} |
r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP2_INDEX); |
if (r) { |
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); |
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; |
} |
r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX); |
if (r) { |
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r); |
return r; |
} |
r = radeon_uvd_resume(rdev); |
if (!r) { |
r = uvd_v4_2_resume(rdev); |
if (!r) { |
r = radeon_fence_driver_start_ring(rdev, |
R600_RING_TYPE_UVD_INDEX); |
if (r) |
dev_err(rdev->dev, "UVD fences init error (%d).\n", r); |
} |
} |
if (r) |
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; |
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); |
if (r) |
return r; |
} |
r = cik_irq_init(rdev); |
if (r) { |
DRM_ERROR("radeon: IH init failed (%d).\n", r); |
// radeon_irq_kms_fini(rdev); |
return r; |
} |
cik_irq_set(rdev); |
if (rdev->family == CHIP_HAWAII) { |
if (rdev->new_fw) |
nop = PACKET3(PACKET3_NOP, 0x3FFF); |
else |
nop = RADEON_CP_PACKET2; |
} else { |
nop = PACKET3(PACKET3_NOP, 0x3FFF); |
} |
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, |
nop); |
if (r) |
return r; |
/* set up the compute queues */ |
/* 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, |
nop); |
if (r) |
return r; |
ring->me = 1; /* first MEC */ |
ring->pipe = 0; /* first pipe */ |
ring->queue = 0; /* first queue */ |
ring->wptr_offs = CIK_WB_CP1_WPTR_OFFSET; |
/* 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, |
nop); |
if (r) |
return r; |
/* dGPU only have 1 MEC */ |
ring->me = 1; /* first MEC */ |
ring->pipe = 0; /* first pipe */ |
ring->queue = 1; /* second queue */ |
ring->wptr_offs = CIK_WB_CP2_WPTR_OFFSET; |
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; |
r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_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, |
SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0)); |
if (r) |
return r; |
r = cik_cp_resume(rdev); |
if (r) |
return r; |
r = cik_sdma_resume(rdev); |
if (r) |
return r; |
ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
if (ring->ring_size) { |
r = radeon_ring_init(rdev, ring, ring->ring_size, 0, |
RADEON_CP_PACKET2); |
if (!r) |
r = uvd_v1_0_init(rdev); |
if (r) |
DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); |
} |
r = radeon_ib_pool_init(rdev); |
if (r) { |
dev_err(rdev->dev, "IB initialization failed (%d).\n", r); |
return r; |
} |
r = radeon_vm_manager_init(rdev); |
if (r) { |
dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r); |
return r; |
} |
return 0; |
} |
/* Plan is to move initialization in that function and use |
* helper function so that radeon_device_init pretty much |
* do nothing more than calling asic specific function. This |
* should also allow to remove a bunch of callback function |
* like vram_info. |
*/ |
/** |
* cik_init - asic specific driver and hw init |
* |
* @rdev: radeon_device pointer |
* |
* Setup asic specific driver variables and program the hw |
* to a functional state (CIK). |
* Called at driver startup. |
* Returns 0 for success, errors for failure. |
*/ |
int cik_init(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring; |
int r; |
/* Read BIOS */ |
if (!radeon_get_bios(rdev)) { |
if (ASIC_IS_AVIVO(rdev)) |
return -EINVAL; |
} |
/* Must be an ATOMBIOS */ |
if (!rdev->is_atom_bios) { |
dev_err(rdev->dev, "Expecting atombios for cayman GPU\n"); |
return -EINVAL; |
} |
r = radeon_atombios_init(rdev); |
if (r) |
return r; |
/* Post card if necessary */ |
if (!radeon_card_posted(rdev)) { |
if (!rdev->bios) { |
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); |
return -EINVAL; |
} |
DRM_INFO("GPU not posted. posting now...\n"); |
atom_asic_init(rdev->mode_info.atom_context); |
} |
/* init golden registers */ |
cik_init_golden_registers(rdev); |
/* Initialize scratch registers */ |
cik_scratch_init(rdev); |
/* Initialize surface registers */ |
radeon_surface_init(rdev); |
/* Initialize clocks */ |
radeon_get_clock_info(rdev->ddev); |
/* Fence driver */ |
r = radeon_fence_driver_init(rdev); |
if (r) |
return r; |
/* initialize memory controller */ |
r = cik_mc_init(rdev); |
if (r) |
return r; |
/* Memory manager */ |
r = radeon_bo_init(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); |
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_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_index); |
if (r) |
return r; |
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; |
ring->ring_obj = NULL; |
r600_ring_init(rdev, ring, 256 * 1024); |
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]; |
ring->ring_obj = NULL; |
r600_ring_init(rdev, ring, 256 * 1024); |
r = radeon_uvd_init(rdev); |
if (!r) { |
ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
ring->ring_obj = NULL; |
r600_ring_init(rdev, ring, 4096); |
} |
rdev->ih.ring_obj = NULL; |
r600_ih_ring_init(rdev, 64 * 1024); |
r = r600_pcie_gart_init(rdev); |
if (r) |
return r; |
rdev->accel_working = true; |
r = cik_startup(rdev); |
if (r) { |
dev_err(rdev->dev, "disabling GPU acceleration\n"); |
rdev->accel_working = false; |
} |
/* Don't start up if the MC ucode is missing. |
* The default clocks and voltages before the MC ucode |
* is loaded are not suffient for advanced operations. |
*/ |
if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) { |
DRM_ERROR("radeon: MC ucode required for NI+.\n"); |
return -EINVAL; |
} |
return 0; |
} |
/** |
* cik_fini - asic specific driver and hw fini |
* |
* @rdev: radeon_device pointer |
* |
* Tear down the asic specific driver variables and program the hw |
* to an idle state (CIK). |
* Called at driver unload. |
*/ |
void cik_fini(struct radeon_device *rdev) |
{ |
kfree(rdev->bios); |
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 |
* |
* @rdev: radeon_device pointer |
* @radeon_crtc: the selected display controller |
* @mode: the current display mode on the selected display |
* controller |
* |
* Setup up the line buffer allocation for |
* the selected display controller (CIK). |
* Returns the line buffer size in pixels. |
*/ |
static u32 dce8_line_buffer_adjust(struct radeon_device *rdev, |
struct radeon_crtc *radeon_crtc, |
struct drm_display_mode *mode) |
{ |
u32 tmp, buffer_alloc, i; |
u32 pipe_offset = radeon_crtc->crtc_id * 0x20; |
/* |
* Line Buffer Setup |
* There are 6 line buffers, one for each display controllers. |
* There are 3 partitions per LB. Select the number of partitions |
* to enable based on the display width. For display widths larger |
* than 4096, you need use to use 2 display controllers and combine |
* them using the stereo blender. |
*/ |
if (radeon_crtc->base.enabled && mode) { |
if (mode->crtc_hdisplay < 1920) { |
tmp = 1; |
buffer_alloc = 2; |
} else if (mode->crtc_hdisplay < 2560) { |
tmp = 2; |
buffer_alloc = 2; |
} else if (mode->crtc_hdisplay < 4096) { |
tmp = 0; |
buffer_alloc = (rdev->flags & RADEON_IS_IGP) ? 2 : 4; |
} else { |
DRM_DEBUG_KMS("Mode too big for LB!\n"); |
tmp = 0; |
buffer_alloc = (rdev->flags & RADEON_IS_IGP) ? 2 : 4; |
} |
} else { |
tmp = 1; |
buffer_alloc = 0; |
} |
WREG32(LB_MEMORY_CTRL + radeon_crtc->crtc_offset, |
LB_MEMORY_CONFIG(tmp) | LB_MEMORY_SIZE(0x6B0)); |
WREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset, |
DMIF_BUFFERS_ALLOCATED(buffer_alloc)); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset) & |
DMIF_BUFFERS_ALLOCATED_COMPLETED) |
break; |
udelay(1); |
} |
if (radeon_crtc->base.enabled && mode) { |
switch (tmp) { |
case 0: |
default: |
return 4096 * 2; |
case 1: |
return 1920 * 2; |
case 2: |
return 2560 * 2; |
} |
} |
/* controller not enabled, so no lb used */ |
return 0; |
} |
/** |
* cik_get_number_of_dram_channels - get the number of dram channels |
* |
* @rdev: radeon_device pointer |
* |
* Look up the number of video ram channels (CIK). |
* Used for display watermark bandwidth calculations |
* Returns the number of dram channels |
*/ |
static u32 cik_get_number_of_dram_channels(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32(MC_SHARED_CHMAP); |
switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { |
case 0: |
default: |
return 1; |
case 1: |
return 2; |
case 2: |
return 4; |
case 3: |
return 8; |
case 4: |
return 3; |
case 5: |
return 6; |
case 6: |
return 10; |
case 7: |
return 12; |
case 8: |
return 16; |
} |
} |
struct dce8_wm_params { |
u32 dram_channels; /* number of dram channels */ |
u32 yclk; /* bandwidth per dram data pin in kHz */ |
u32 sclk; /* engine clock in kHz */ |
u32 disp_clk; /* display clock in kHz */ |
u32 src_width; /* viewport width */ |
u32 active_time; /* active display time in ns */ |
u32 blank_time; /* blank time in ns */ |
bool interlaced; /* mode is interlaced */ |
fixed20_12 vsc; /* vertical scale ratio */ |
u32 num_heads; /* number of active crtcs */ |
u32 bytes_per_pixel; /* bytes per pixel display + overlay */ |
u32 lb_size; /* line buffer allocated to pipe */ |
u32 vtaps; /* vertical scaler taps */ |
}; |
/** |
* dce8_dram_bandwidth - get the dram bandwidth |
* |
* @wm: watermark calculation data |
* |
* Calculate the raw dram bandwidth (CIK). |
* Used for display watermark bandwidth calculations |
* Returns the dram bandwidth in MBytes/s |
*/ |
static u32 dce8_dram_bandwidth(struct dce8_wm_params *wm) |
{ |
/* Calculate raw DRAM Bandwidth */ |
fixed20_12 dram_efficiency; /* 0.7 */ |
fixed20_12 yclk, dram_channels, bandwidth; |
fixed20_12 a; |
a.full = dfixed_const(1000); |
yclk.full = dfixed_const(wm->yclk); |
yclk.full = dfixed_div(yclk, a); |
dram_channels.full = dfixed_const(wm->dram_channels * 4); |
a.full = dfixed_const(10); |
dram_efficiency.full = dfixed_const(7); |
dram_efficiency.full = dfixed_div(dram_efficiency, a); |
bandwidth.full = dfixed_mul(dram_channels, yclk); |
bandwidth.full = dfixed_mul(bandwidth, dram_efficiency); |
return dfixed_trunc(bandwidth); |
} |
/** |
* dce8_dram_bandwidth_for_display - get the dram bandwidth for display |
* |
* @wm: watermark calculation data |
* |
* Calculate the dram bandwidth used for display (CIK). |
* Used for display watermark bandwidth calculations |
* Returns the dram bandwidth for display in MBytes/s |
*/ |
static u32 dce8_dram_bandwidth_for_display(struct dce8_wm_params *wm) |
{ |
/* Calculate DRAM Bandwidth and the part allocated to display. */ |
fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */ |
fixed20_12 yclk, dram_channels, bandwidth; |
fixed20_12 a; |
a.full = dfixed_const(1000); |
yclk.full = dfixed_const(wm->yclk); |
yclk.full = dfixed_div(yclk, a); |
dram_channels.full = dfixed_const(wm->dram_channels * 4); |
a.full = dfixed_const(10); |
disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */ |
disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a); |
bandwidth.full = dfixed_mul(dram_channels, yclk); |
bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation); |
return dfixed_trunc(bandwidth); |
} |
/** |
* dce8_data_return_bandwidth - get the data return bandwidth |
* |
* @wm: watermark calculation data |
* |
* Calculate the data return bandwidth used for display (CIK). |
* Used for display watermark bandwidth calculations |
* Returns the data return bandwidth in MBytes/s |
*/ |
static u32 dce8_data_return_bandwidth(struct dce8_wm_params *wm) |
{ |
/* Calculate the display Data return Bandwidth */ |
fixed20_12 return_efficiency; /* 0.8 */ |
fixed20_12 sclk, bandwidth; |
fixed20_12 a; |
a.full = dfixed_const(1000); |
sclk.full = dfixed_const(wm->sclk); |
sclk.full = dfixed_div(sclk, a); |
a.full = dfixed_const(10); |
return_efficiency.full = dfixed_const(8); |
return_efficiency.full = dfixed_div(return_efficiency, a); |
a.full = dfixed_const(32); |
bandwidth.full = dfixed_mul(a, sclk); |
bandwidth.full = dfixed_mul(bandwidth, return_efficiency); |
return dfixed_trunc(bandwidth); |
} |
/** |
* dce8_dmif_request_bandwidth - get the dmif bandwidth |
* |
* @wm: watermark calculation data |
* |
* Calculate the dmif bandwidth used for display (CIK). |
* Used for display watermark bandwidth calculations |
* Returns the dmif bandwidth in MBytes/s |
*/ |
static u32 dce8_dmif_request_bandwidth(struct dce8_wm_params *wm) |
{ |
/* Calculate the DMIF Request Bandwidth */ |
fixed20_12 disp_clk_request_efficiency; /* 0.8 */ |
fixed20_12 disp_clk, bandwidth; |
fixed20_12 a, b; |
a.full = dfixed_const(1000); |
disp_clk.full = dfixed_const(wm->disp_clk); |
disp_clk.full = dfixed_div(disp_clk, a); |
a.full = dfixed_const(32); |
b.full = dfixed_mul(a, disp_clk); |
a.full = dfixed_const(10); |
disp_clk_request_efficiency.full = dfixed_const(8); |
disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a); |
bandwidth.full = dfixed_mul(b, disp_clk_request_efficiency); |
return dfixed_trunc(bandwidth); |
} |
/** |
* dce8_available_bandwidth - get the min available bandwidth |
* |
* @wm: watermark calculation data |
* |
* Calculate the min available bandwidth used for display (CIK). |
* Used for display watermark bandwidth calculations |
* Returns the min available bandwidth in MBytes/s |
*/ |
static u32 dce8_available_bandwidth(struct dce8_wm_params *wm) |
{ |
/* Calculate the Available bandwidth. Display can use this temporarily but not in average. */ |
u32 dram_bandwidth = dce8_dram_bandwidth(wm); |
u32 data_return_bandwidth = dce8_data_return_bandwidth(wm); |
u32 dmif_req_bandwidth = dce8_dmif_request_bandwidth(wm); |
return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth)); |
} |
/** |
* dce8_average_bandwidth - get the average available bandwidth |
* |
* @wm: watermark calculation data |
* |
* Calculate the average available bandwidth used for display (CIK). |
* Used for display watermark bandwidth calculations |
* Returns the average available bandwidth in MBytes/s |
*/ |
static u32 dce8_average_bandwidth(struct dce8_wm_params *wm) |
{ |
/* Calculate the display mode Average Bandwidth |
* DisplayMode should contain the source and destination dimensions, |
* timing, etc. |
*/ |
fixed20_12 bpp; |
fixed20_12 line_time; |
fixed20_12 src_width; |
fixed20_12 bandwidth; |
fixed20_12 a; |
a.full = dfixed_const(1000); |
line_time.full = dfixed_const(wm->active_time + wm->blank_time); |
line_time.full = dfixed_div(line_time, a); |
bpp.full = dfixed_const(wm->bytes_per_pixel); |
src_width.full = dfixed_const(wm->src_width); |
bandwidth.full = dfixed_mul(src_width, bpp); |
bandwidth.full = dfixed_mul(bandwidth, wm->vsc); |
bandwidth.full = dfixed_div(bandwidth, line_time); |
return dfixed_trunc(bandwidth); |
} |
/** |
* dce8_latency_watermark - get the latency watermark |
* |
* @wm: watermark calculation data |
* |
* Calculate the latency watermark (CIK). |
* Used for display watermark bandwidth calculations |
* Returns the latency watermark in ns |
*/ |
static u32 dce8_latency_watermark(struct dce8_wm_params *wm) |
{ |
/* First calculate the latency in ns */ |
u32 mc_latency = 2000; /* 2000 ns. */ |
u32 available_bandwidth = dce8_available_bandwidth(wm); |
u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth; |
u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth; |
u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */ |
u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) + |
(wm->num_heads * cursor_line_pair_return_time); |
u32 latency = mc_latency + other_heads_data_return_time + dc_latency; |
u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time; |
u32 tmp, dmif_size = 12288; |
fixed20_12 a, b, c; |
if (wm->num_heads == 0) |
return 0; |
a.full = dfixed_const(2); |
b.full = dfixed_const(1); |
if ((wm->vsc.full > a.full) || |
((wm->vsc.full > b.full) && (wm->vtaps >= 3)) || |
(wm->vtaps >= 5) || |
((wm->vsc.full >= a.full) && wm->interlaced)) |
max_src_lines_per_dst_line = 4; |
else |
max_src_lines_per_dst_line = 2; |
a.full = dfixed_const(available_bandwidth); |
b.full = dfixed_const(wm->num_heads); |
a.full = dfixed_div(a, b); |
b.full = dfixed_const(mc_latency + 512); |
c.full = dfixed_const(wm->disp_clk); |
b.full = dfixed_div(b, c); |
c.full = dfixed_const(dmif_size); |
b.full = dfixed_div(c, b); |
tmp = min(dfixed_trunc(a), dfixed_trunc(b)); |
b.full = dfixed_const(1000); |
c.full = dfixed_const(wm->disp_clk); |
b.full = dfixed_div(c, b); |
c.full = dfixed_const(wm->bytes_per_pixel); |
b.full = dfixed_mul(b, c); |
lb_fill_bw = min(tmp, dfixed_trunc(b)); |
a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel); |
b.full = dfixed_const(1000); |
c.full = dfixed_const(lb_fill_bw); |
b.full = dfixed_div(c, b); |
a.full = dfixed_div(a, b); |
line_fill_time = dfixed_trunc(a); |
if (line_fill_time < wm->active_time) |
return latency; |
else |
return latency + (line_fill_time - wm->active_time); |
} |
/** |
* dce8_average_bandwidth_vs_dram_bandwidth_for_display - check |
* average and available dram bandwidth |
* |
* @wm: watermark calculation data |
* |
* Check if the display average bandwidth fits in the display |
* dram bandwidth (CIK). |
* Used for display watermark bandwidth calculations |
* Returns true if the display fits, false if not. |
*/ |
static bool dce8_average_bandwidth_vs_dram_bandwidth_for_display(struct dce8_wm_params *wm) |
{ |
if (dce8_average_bandwidth(wm) <= |
(dce8_dram_bandwidth_for_display(wm) / wm->num_heads)) |
return true; |
else |
return false; |
} |
/** |
* dce8_average_bandwidth_vs_available_bandwidth - check |
* average and available bandwidth |
* |
* @wm: watermark calculation data |
* |
* Check if the display average bandwidth fits in the display |
* available bandwidth (CIK). |
* Used for display watermark bandwidth calculations |
* Returns true if the display fits, false if not. |
*/ |
static bool dce8_average_bandwidth_vs_available_bandwidth(struct dce8_wm_params *wm) |
{ |
if (dce8_average_bandwidth(wm) <= |
(dce8_available_bandwidth(wm) / wm->num_heads)) |
return true; |
else |
return false; |
} |
/** |
* dce8_check_latency_hiding - check latency hiding |
* |
* @wm: watermark calculation data |
* |
* Check latency hiding (CIK). |
* Used for display watermark bandwidth calculations |
* Returns true if the display fits, false if not. |
*/ |
static bool dce8_check_latency_hiding(struct dce8_wm_params *wm) |
{ |
u32 lb_partitions = wm->lb_size / wm->src_width; |
u32 line_time = wm->active_time + wm->blank_time; |
u32 latency_tolerant_lines; |
u32 latency_hiding; |
fixed20_12 a; |
a.full = dfixed_const(1); |
if (wm->vsc.full > a.full) |
latency_tolerant_lines = 1; |
else { |
if (lb_partitions <= (wm->vtaps + 1)) |
latency_tolerant_lines = 1; |
else |
latency_tolerant_lines = 2; |
} |
latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time); |
if (dce8_latency_watermark(wm) <= latency_hiding) |
return true; |
else |
return false; |
} |
/** |
* dce8_program_watermarks - program display watermarks |
* |
* @rdev: radeon_device pointer |
* @radeon_crtc: the selected display controller |
* @lb_size: line buffer size |
* @num_heads: number of display controllers in use |
* |
* Calculate and program the display watermarks for the |
* selected display controller (CIK). |
*/ |
static void dce8_program_watermarks(struct radeon_device *rdev, |
struct radeon_crtc *radeon_crtc, |
u32 lb_size, u32 num_heads) |
{ |
struct drm_display_mode *mode = &radeon_crtc->base.mode; |
struct dce8_wm_params wm_low, wm_high; |
u32 pixel_period; |
u32 line_time = 0; |
u32 latency_watermark_a = 0, latency_watermark_b = 0; |
u32 tmp, wm_mask; |
if (radeon_crtc->base.enabled && num_heads && mode) { |
pixel_period = 1000000 / (u32)mode->clock; |
line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535); |
/* watermark for high clocks */ |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && |
rdev->pm.dpm_enabled) { |
wm_high.yclk = |
radeon_dpm_get_mclk(rdev, false) * 10; |
wm_high.sclk = |
radeon_dpm_get_sclk(rdev, false) * 10; |
} else { |
wm_high.yclk = rdev->pm.current_mclk * 10; |
wm_high.sclk = rdev->pm.current_sclk * 10; |
} |
wm_high.disp_clk = mode->clock; |
wm_high.src_width = mode->crtc_hdisplay; |
wm_high.active_time = mode->crtc_hdisplay * pixel_period; |
wm_high.blank_time = line_time - wm_high.active_time; |
wm_high.interlaced = false; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
wm_high.interlaced = true; |
wm_high.vsc = radeon_crtc->vsc; |
wm_high.vtaps = 1; |
if (radeon_crtc->rmx_type != RMX_OFF) |
wm_high.vtaps = 2; |
wm_high.bytes_per_pixel = 4; /* XXX: get this from fb config */ |
wm_high.lb_size = lb_size; |
wm_high.dram_channels = cik_get_number_of_dram_channels(rdev); |
wm_high.num_heads = num_heads; |
/* set for high clocks */ |
latency_watermark_a = min(dce8_latency_watermark(&wm_high), (u32)65535); |
/* possibly force display priority to high */ |
/* should really do this at mode validation time... */ |
if (!dce8_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) || |
!dce8_average_bandwidth_vs_available_bandwidth(&wm_high) || |
!dce8_check_latency_hiding(&wm_high) || |
(rdev->disp_priority == 2)) { |
DRM_DEBUG_KMS("force priority to high\n"); |
} |
/* watermark for low clocks */ |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && |
rdev->pm.dpm_enabled) { |
wm_low.yclk = |
radeon_dpm_get_mclk(rdev, true) * 10; |
wm_low.sclk = |
radeon_dpm_get_sclk(rdev, true) * 10; |
} else { |
wm_low.yclk = rdev->pm.current_mclk * 10; |
wm_low.sclk = rdev->pm.current_sclk * 10; |
} |
wm_low.disp_clk = mode->clock; |
wm_low.src_width = mode->crtc_hdisplay; |
wm_low.active_time = mode->crtc_hdisplay * pixel_period; |
wm_low.blank_time = line_time - wm_low.active_time; |
wm_low.interlaced = false; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
wm_low.interlaced = true; |
wm_low.vsc = radeon_crtc->vsc; |
wm_low.vtaps = 1; |
if (radeon_crtc->rmx_type != RMX_OFF) |
wm_low.vtaps = 2; |
wm_low.bytes_per_pixel = 4; /* XXX: get this from fb config */ |
wm_low.lb_size = lb_size; |
wm_low.dram_channels = cik_get_number_of_dram_channels(rdev); |
wm_low.num_heads = num_heads; |
/* set for low clocks */ |
latency_watermark_b = min(dce8_latency_watermark(&wm_low), (u32)65535); |
/* possibly force display priority to high */ |
/* should really do this at mode validation time... */ |
if (!dce8_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) || |
!dce8_average_bandwidth_vs_available_bandwidth(&wm_low) || |
!dce8_check_latency_hiding(&wm_low) || |
(rdev->disp_priority == 2)) { |
DRM_DEBUG_KMS("force priority to high\n"); |
} |
} |
/* select wm A */ |
wm_mask = RREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset); |
tmp = wm_mask; |
tmp &= ~LATENCY_WATERMARK_MASK(3); |
tmp |= LATENCY_WATERMARK_MASK(1); |
WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, tmp); |
WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset, |
(LATENCY_LOW_WATERMARK(latency_watermark_a) | |
LATENCY_HIGH_WATERMARK(line_time))); |
/* select wm B */ |
tmp = RREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset); |
tmp &= ~LATENCY_WATERMARK_MASK(3); |
tmp |= LATENCY_WATERMARK_MASK(2); |
WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, tmp); |
WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset, |
(LATENCY_LOW_WATERMARK(latency_watermark_b) | |
LATENCY_HIGH_WATERMARK(line_time))); |
/* restore original selection */ |
WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, wm_mask); |
/* save values for DPM */ |
radeon_crtc->line_time = line_time; |
radeon_crtc->wm_high = latency_watermark_a; |
radeon_crtc->wm_low = latency_watermark_b; |
} |
/** |
* dce8_bandwidth_update - program display watermarks |
* |
* @rdev: radeon_device pointer |
* |
* Calculate and program the display watermarks and line |
* buffer allocation (CIK). |
*/ |
void dce8_bandwidth_update(struct radeon_device *rdev) |
{ |
struct drm_display_mode *mode = NULL; |
u32 num_heads = 0, lb_size; |
int i; |
radeon_update_display_priority(rdev); |
for (i = 0; i < rdev->num_crtc; i++) { |
if (rdev->mode_info.crtcs[i]->base.enabled) |
num_heads++; |
} |
for (i = 0; i < rdev->num_crtc; i++) { |
mode = &rdev->mode_info.crtcs[i]->base.mode; |
lb_size = dce8_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode); |
dce8_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads); |
} |
} |
/** |
* cik_get_gpu_clock_counter - return GPU clock counter snapshot |
* |
* @rdev: radeon_device pointer |
* |
* Fetches a GPU clock counter snapshot (SI). |
* Returns the 64 bit clock counter snapshot. |
*/ |
uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev) |
{ |
uint64_t clock; |
mutex_lock(&rdev->gpu_clock_mutex); |
WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1); |
clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) | |
((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL); |
mutex_unlock(&rdev->gpu_clock_mutex); |
return clock; |
} |
static int cik_set_uvd_clock(struct radeon_device *rdev, u32 clock, |
u32 cntl_reg, u32 status_reg) |
{ |
int r, i; |
struct atom_clock_dividers dividers; |
uint32_t tmp; |
r = radeon_atom_get_clock_dividers(rdev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, |
clock, false, ÷rs); |
if (r) |
return r; |
tmp = RREG32_SMC(cntl_reg); |
tmp &= ~(DCLK_DIR_CNTL_EN|DCLK_DIVIDER_MASK); |
tmp |= dividers.post_divider; |
WREG32_SMC(cntl_reg, tmp); |
for (i = 0; i < 100; i++) { |
if (RREG32_SMC(status_reg) & DCLK_STATUS) |
break; |
mdelay(10); |
} |
if (i == 100) |
return -ETIMEDOUT; |
return 0; |
} |
int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) |
{ |
int r = 0; |
r = cik_set_uvd_clock(rdev, vclk, CG_VCLK_CNTL, CG_VCLK_STATUS); |
if (r) |
return r; |
r = cik_set_uvd_clock(rdev, dclk, CG_DCLK_CNTL, CG_DCLK_STATUS); |
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; |
int bridge_pos, gpu_pos; |
u32 speed_cntl, mask, current_data_rate; |
int ret, i; |
u16 tmp16; |
if (radeon_pcie_gen2 == 0) |
return; |
if (rdev->flags & RADEON_IS_IGP) |
return; |
if (!(rdev->flags & RADEON_IS_PCIE)) |
return; |
ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); |
if (ret != 0) |
return; |
if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) |
return; |
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> |
LC_CURRENT_DATA_RATE_SHIFT; |
if (mask & DRM_PCIE_SPEED_80) { |
if (current_data_rate == 2) { |
DRM_INFO("PCIE gen 3 link speeds already enabled\n"); |
return; |
} |
DRM_INFO("enabling PCIE gen 3 link speeds, disable with radeon.pcie_gen2=0\n"); |
} else if (mask & DRM_PCIE_SPEED_50) { |
if (current_data_rate == 1) { |
DRM_INFO("PCIE gen 2 link speeds already enabled\n"); |
return; |
} |
DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n"); |
} |
bridge_pos = pci_pcie_cap(root); |
if (!bridge_pos) |
return; |
gpu_pos = pci_pcie_cap(rdev->pdev); |
if (!gpu_pos) |
return; |
if (mask & DRM_PCIE_SPEED_80) { |
/* re-try equalization if gen3 is not already enabled */ |
if (current_data_rate != 2) { |
u16 bridge_cfg, gpu_cfg; |
u16 bridge_cfg2, gpu_cfg2; |
u32 max_lw, current_lw, tmp; |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg); |
tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; |
pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16); |
tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; |
pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16); |
tmp = RREG32_PCIE_PORT(PCIE_LC_STATUS1); |
max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT; |
current_lw = (tmp & LC_OPERATING_LINK_WIDTH_MASK) >> LC_OPERATING_LINK_WIDTH_SHIFT; |
if (current_lw < max_lw) { |
tmp = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL); |
if (tmp & LC_RENEGOTIATION_SUPPORT) { |
tmp &= ~(LC_LINK_WIDTH_MASK | LC_UPCONFIGURE_DIS); |
tmp |= (max_lw << LC_LINK_WIDTH_SHIFT); |
tmp |= LC_UPCONFIGURE_SUPPORT | LC_RENEGOTIATE_EN | LC_RECONFIG_NOW; |
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, tmp); |
} |
} |
for (i = 0; i < 10; i++) { |
/* check status */ |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16); |
if (tmp16 & PCI_EXP_DEVSTA_TRPND) |
break; |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg); |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2); |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4); |
tmp |= LC_SET_QUIESCE; |
WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp); |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4); |
tmp |= LC_REDO_EQ; |
WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp); |
mdelay(100); |
/* linkctl */ |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16); |
tmp16 &= ~PCI_EXP_LNKCTL_HAWD; |
tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); |
pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16); |
tmp16 &= ~PCI_EXP_LNKCTL_HAWD; |
tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); |
pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16); |
/* linkctl2 */ |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16); |
tmp16 &= ~((1 << 4) | (7 << 9)); |
tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9))); |
pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); |
tmp16 &= ~((1 << 4) | (7 << 9)); |
tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9))); |
pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16); |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4); |
tmp &= ~LC_SET_QUIESCE; |
WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp); |
} |
} |
} |
/* set the link speed */ |
speed_cntl |= LC_FORCE_EN_SW_SPEED_CHANGE | LC_FORCE_DIS_HW_SPEED_CHANGE; |
speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); |
tmp16 &= ~0xf; |
if (mask & DRM_PCIE_SPEED_80) |
tmp16 |= 3; /* gen3 */ |
else if (mask & DRM_PCIE_SPEED_50) |
tmp16 |= 2; /* gen2 */ |
else |
tmp16 |= 1; /* gen1 */ |
pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16); |
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl); |
for (i = 0; i < rdev->usec_timeout; i++) { |
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if ((speed_cntl & LC_INITIATE_LINK_SPEED_CHANGE) == 0) |
break; |
udelay(1); |
} |
} |
static void cik_program_aspm(struct radeon_device *rdev) |
{ |
u32 data, orig; |
bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false; |
bool disable_clkreq = false; |
if (radeon_aspm == 0) |
return; |
/* XXX double check IGPs */ |
if (rdev->flags & RADEON_IS_IGP) |
return; |
if (!(rdev->flags & RADEON_IS_PCIE)) |
return; |
orig = data = RREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL); |
data &= ~LC_XMIT_N_FTS_MASK; |
data |= LC_XMIT_N_FTS(0x24) | LC_XMIT_N_FTS_OVERRIDE_EN; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL, data); |
orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL3); |
data |= LC_GO_TO_RECOVERY; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL3, data); |
orig = data = RREG32_PCIE_PORT(PCIE_P_CNTL); |
data |= P_IGNORE_EDB_ERR; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_P_CNTL, data); |
orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL); |
data &= ~(LC_L0S_INACTIVITY_MASK | LC_L1_INACTIVITY_MASK); |
data |= LC_PMI_TO_L1_DIS; |
if (!disable_l0s) |
data |= LC_L0S_INACTIVITY(7); |
if (!disable_l1) { |
data |= LC_L1_INACTIVITY(7); |
data &= ~LC_PMI_TO_L1_DIS; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL, data); |
if (!disable_plloff_in_l1) { |
bool clk_req_support; |
orig = data = RREG32_PCIE_PORT(PB0_PIF_PWRDOWN_0); |
data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK); |
data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7); |
if (orig != data) |
WREG32_PCIE_PORT(PB0_PIF_PWRDOWN_0, data); |
orig = data = RREG32_PCIE_PORT(PB0_PIF_PWRDOWN_1); |
data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK); |
data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7); |
if (orig != data) |
WREG32_PCIE_PORT(PB0_PIF_PWRDOWN_1, data); |
orig = data = RREG32_PCIE_PORT(PB1_PIF_PWRDOWN_0); |
data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK); |
data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7); |
if (orig != data) |
WREG32_PCIE_PORT(PB1_PIF_PWRDOWN_0, data); |
orig = data = RREG32_PCIE_PORT(PB1_PIF_PWRDOWN_1); |
data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK); |
data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7); |
if (orig != data) |
WREG32_PCIE_PORT(PB1_PIF_PWRDOWN_1, data); |
orig = data = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL); |
data &= ~LC_DYN_LANES_PWR_STATE_MASK; |
data |= LC_DYN_LANES_PWR_STATE(3); |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data); |
if (!disable_clkreq) { |
struct pci_dev *root = rdev->pdev->bus->self; |
u32 lnkcap; |
clk_req_support = false; |
pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap); |
if (lnkcap & PCI_EXP_LNKCAP_CLKPM) |
clk_req_support = true; |
} else { |
clk_req_support = false; |
} |
if (clk_req_support) { |
orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL2); |
data |= LC_ALLOW_PDWN_IN_L1 | LC_ALLOW_PDWN_IN_L23; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL2, data); |
orig = data = RREG32_SMC(THM_CLK_CNTL); |
data &= ~(CMON_CLK_SEL_MASK | TMON_CLK_SEL_MASK); |
data |= CMON_CLK_SEL(1) | TMON_CLK_SEL(1); |
if (orig != data) |
WREG32_SMC(THM_CLK_CNTL, data); |
orig = data = RREG32_SMC(MISC_CLK_CTRL); |
data &= ~(DEEP_SLEEP_CLK_SEL_MASK | ZCLK_SEL_MASK); |
data |= DEEP_SLEEP_CLK_SEL(1) | ZCLK_SEL(1); |
if (orig != data) |
WREG32_SMC(MISC_CLK_CTRL, data); |
orig = data = RREG32_SMC(CG_CLKPIN_CNTL); |
data &= ~BCLK_AS_XCLK; |
if (orig != data) |
WREG32_SMC(CG_CLKPIN_CNTL, data); |
orig = data = RREG32_SMC(CG_CLKPIN_CNTL_2); |
data &= ~FORCE_BIF_REFCLK_EN; |
if (orig != data) |
WREG32_SMC(CG_CLKPIN_CNTL_2, data); |
orig = data = RREG32_SMC(MPLL_BYPASSCLK_SEL); |
data &= ~MPLL_CLKOUT_SEL_MASK; |
data |= MPLL_CLKOUT_SEL(4); |
if (orig != data) |
WREG32_SMC(MPLL_BYPASSCLK_SEL, data); |
} |
} |
} else { |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL, data); |
} |
orig = data = RREG32_PCIE_PORT(PCIE_CNTL2); |
data |= SLV_MEM_LS_EN | MST_MEM_LS_EN | REPLAY_MEM_LS_EN; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_CNTL2, data); |
if (!disable_l0s) { |
data = RREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL); |
if((data & LC_N_FTS_MASK) == LC_N_FTS_MASK) { |
data = RREG32_PCIE_PORT(PCIE_LC_STATUS1); |
if ((data & LC_REVERSE_XMIT) && (data & LC_REVERSE_RCVR)) { |
orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL); |
data &= ~LC_L0S_INACTIVITY_MASK; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL, data); |
} |
} |
} |
} |
/drivers/video/drm/radeon/cik_blit_shaders.c |
---|
0,0 → 1,246 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice (including the next |
* paragraph) 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) 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. |
* |
* Authors: |
* Alex Deucher <alexander.deucher@amd.com> |
*/ |
#include <linux/types.h> |
#include <linux/bug.h> |
#include <linux/kernel.h> |
const u32 cik_default_state[] = |
{ |
0xc0066900, |
0x00000000, |
0x00000060, /* DB_RENDER_CONTROL */ |
0x00000000, /* DB_COUNT_CONTROL */ |
0x00000000, /* DB_DEPTH_VIEW */ |
0x0000002a, /* DB_RENDER_OVERRIDE */ |
0x00000000, /* DB_RENDER_OVERRIDE2 */ |
0x00000000, /* DB_HTILE_DATA_BASE */ |
0xc0046900, |
0x00000008, |
0x00000000, /* DB_DEPTH_BOUNDS_MIN */ |
0x00000000, /* DB_DEPTH_BOUNDS_MAX */ |
0x00000000, /* DB_STENCIL_CLEAR */ |
0x00000000, /* DB_DEPTH_CLEAR */ |
0xc0036900, |
0x0000000f, |
0x00000000, /* DB_DEPTH_INFO */ |
0x00000000, /* DB_Z_INFO */ |
0x00000000, /* DB_STENCIL_INFO */ |
0xc0016900, |
0x00000080, |
0x00000000, /* PA_SC_WINDOW_OFFSET */ |
0xc00d6900, |
0x00000083, |
0x0000ffff, /* PA_SC_CLIPRECT_RULE */ |
0x00000000, /* PA_SC_CLIPRECT_0_TL */ |
0x20002000, /* PA_SC_CLIPRECT_0_BR */ |
0x00000000, |
0x20002000, |
0x00000000, |
0x20002000, |
0x00000000, |
0x20002000, |
0xaaaaaaaa, /* PA_SC_EDGERULE */ |
0x00000000, /* PA_SU_HARDWARE_SCREEN_OFFSET */ |
0x0000000f, /* CB_TARGET_MASK */ |
0x0000000f, /* CB_SHADER_MASK */ |
0xc0226900, |
0x00000094, |
0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */ |
0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */ |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x80000000, |
0x20002000, |
0x00000000, /* PA_SC_VPORT_ZMIN_0 */ |
0x3f800000, /* PA_SC_VPORT_ZMAX_0 */ |
0xc0046900, |
0x00000100, |
0xffffffff, /* VGT_MAX_VTX_INDX */ |
0x00000000, /* VGT_MIN_VTX_INDX */ |
0x00000000, /* VGT_INDX_OFFSET */ |
0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */ |
0xc0046900, |
0x00000105, |
0x00000000, /* CB_BLEND_RED */ |
0x00000000, /* CB_BLEND_GREEN */ |
0x00000000, /* CB_BLEND_BLUE */ |
0x00000000, /* CB_BLEND_ALPHA */ |
0xc0016900, |
0x000001e0, |
0x00000000, /* CB_BLEND0_CONTROL */ |
0xc00c6900, |
0x00000200, |
0x00000000, /* DB_DEPTH_CONTROL */ |
0x00000000, /* DB_EQAA */ |
0x00cc0010, /* CB_COLOR_CONTROL */ |
0x00000210, /* DB_SHADER_CONTROL */ |
0x00010000, /* PA_CL_CLIP_CNTL */ |
0x00000004, /* PA_SU_SC_MODE_CNTL */ |
0x00000100, /* PA_CL_VTE_CNTL */ |
0x00000000, /* PA_CL_VS_OUT_CNTL */ |
0x00000000, /* PA_CL_NANINF_CNTL */ |
0x00000000, /* PA_SU_LINE_STIPPLE_CNTL */ |
0x00000000, /* PA_SU_LINE_STIPPLE_SCALE */ |
0x00000000, /* PA_SU_PRIM_FILTER_CNTL */ |
0xc0116900, |
0x00000280, |
0x00000000, /* PA_SU_POINT_SIZE */ |
0x00000000, /* PA_SU_POINT_MINMAX */ |
0x00000008, /* PA_SU_LINE_CNTL */ |
0x00000000, /* PA_SC_LINE_STIPPLE */ |
0x00000000, /* VGT_OUTPUT_PATH_CNTL */ |
0x00000000, /* VGT_HOS_CNTL */ |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, /* VGT_GS_MODE */ |
0xc0026900, |
0x00000292, |
0x00000000, /* PA_SC_MODE_CNTL_0 */ |
0x00000000, /* PA_SC_MODE_CNTL_1 */ |
0xc0016900, |
0x000002a1, |
0x00000000, /* VGT_PRIMITIVEID_EN */ |
0xc0016900, |
0x000002a5, |
0x00000000, /* VGT_MULTI_PRIM_IB_RESET_EN */ |
0xc0026900, |
0x000002a8, |
0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */ |
0x00000000, |
0xc0026900, |
0x000002ad, |
0x00000000, /* VGT_REUSE_OFF */ |
0x00000000, |
0xc0016900, |
0x000002d5, |
0x00000000, /* VGT_SHADER_STAGES_EN */ |
0xc0016900, |
0x000002dc, |
0x0000aa00, /* DB_ALPHA_TO_MASK */ |
0xc0066900, |
0x000002de, |
0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */ |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0xc0026900, |
0x000002e5, |
0x00000000, /* VGT_STRMOUT_CONFIG */ |
0x00000000, |
0xc01b6900, |
0x000002f5, |
0x76543210, /* PA_SC_CENTROID_PRIORITY_0 */ |
0xfedcba98, /* PA_SC_CENTROID_PRIORITY_1 */ |
0x00000000, /* PA_SC_LINE_CNTL */ |
0x00000000, /* PA_SC_AA_CONFIG */ |
0x00000005, /* PA_SU_VTX_CNTL */ |
0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */ |
0x3f800000, /* PA_CL_GB_VERT_DISC_ADJ */ |
0x3f800000, /* PA_CL_GB_HORZ_CLIP_ADJ */ |
0x3f800000, /* PA_CL_GB_HORZ_DISC_ADJ */ |
0x00000000, /* PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 */ |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0x00000000, |
0xffffffff, /* PA_SC_AA_MASK_X0Y0_X1Y0 */ |
0xffffffff, |
0xc0026900, |
0x00000316, |
0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */ |
0x00000010, /* */ |
}; |
const u32 cik_default_size = ARRAY_SIZE(cik_default_state); |
/drivers/video/drm/radeon/cik_blit_shaders.h |
---|
0,0 → 1,32 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice (including the next |
* paragraph) 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) 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. |
* |
*/ |
#ifndef CIK_BLIT_SHADERS_H |
#define CIK_BLIT_SHADERS_H |
extern const u32 cik_default_state[]; |
extern const u32 cik_default_size; |
#endif |
/drivers/video/drm/radeon/cik_reg.h |
---|
0,0 → 1,150 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#ifndef __CIK_REG_H__ |
#define __CIK_REG_H__ |
#define CIK_DIDT_IND_INDEX 0xca00 |
#define CIK_DIDT_IND_DATA 0xca04 |
#define CIK_DC_GPIO_HPD_MASK 0x65b0 |
#define CIK_DC_GPIO_HPD_A 0x65b4 |
#define CIK_DC_GPIO_HPD_EN 0x65b8 |
#define CIK_DC_GPIO_HPD_Y 0x65bc |
#define CIK_GRPH_CONTROL 0x6804 |
# define CIK_GRPH_DEPTH(x) (((x) & 0x3) << 0) |
# define CIK_GRPH_DEPTH_8BPP 0 |
# define CIK_GRPH_DEPTH_16BPP 1 |
# define CIK_GRPH_DEPTH_32BPP 2 |
# define CIK_GRPH_NUM_BANKS(x) (((x) & 0x3) << 2) |
# define CIK_ADDR_SURF_2_BANK 0 |
# define CIK_ADDR_SURF_4_BANK 1 |
# define CIK_ADDR_SURF_8_BANK 2 |
# define CIK_ADDR_SURF_16_BANK 3 |
# define CIK_GRPH_Z(x) (((x) & 0x3) << 4) |
# define CIK_GRPH_BANK_WIDTH(x) (((x) & 0x3) << 6) |
# define CIK_ADDR_SURF_BANK_WIDTH_1 0 |
# define CIK_ADDR_SURF_BANK_WIDTH_2 1 |
# define CIK_ADDR_SURF_BANK_WIDTH_4 2 |
# define CIK_ADDR_SURF_BANK_WIDTH_8 3 |
# define CIK_GRPH_FORMAT(x) (((x) & 0x7) << 8) |
/* 8 BPP */ |
# define CIK_GRPH_FORMAT_INDEXED 0 |
/* 16 BPP */ |
# define CIK_GRPH_FORMAT_ARGB1555 0 |
# define CIK_GRPH_FORMAT_ARGB565 1 |
# define CIK_GRPH_FORMAT_ARGB4444 2 |
# define CIK_GRPH_FORMAT_AI88 3 |
# define CIK_GRPH_FORMAT_MONO16 4 |
# define CIK_GRPH_FORMAT_BGRA5551 5 |
/* 32 BPP */ |
# define CIK_GRPH_FORMAT_ARGB8888 0 |
# define CIK_GRPH_FORMAT_ARGB2101010 1 |
# define CIK_GRPH_FORMAT_32BPP_DIG 2 |
# define CIK_GRPH_FORMAT_8B_ARGB2101010 3 |
# define CIK_GRPH_FORMAT_BGRA1010102 4 |
# define CIK_GRPH_FORMAT_8B_BGRA1010102 5 |
# define CIK_GRPH_FORMAT_RGB111110 6 |
# define CIK_GRPH_FORMAT_BGR101111 7 |
# define CIK_GRPH_BANK_HEIGHT(x) (((x) & 0x3) << 11) |
# define CIK_ADDR_SURF_BANK_HEIGHT_1 0 |
# define CIK_ADDR_SURF_BANK_HEIGHT_2 1 |
# define CIK_ADDR_SURF_BANK_HEIGHT_4 2 |
# define CIK_ADDR_SURF_BANK_HEIGHT_8 3 |
# define CIK_GRPH_TILE_SPLIT(x) (((x) & 0x7) << 13) |
# define CIK_ADDR_SURF_TILE_SPLIT_64B 0 |
# define CIK_ADDR_SURF_TILE_SPLIT_128B 1 |
# define CIK_ADDR_SURF_TILE_SPLIT_256B 2 |
# define CIK_ADDR_SURF_TILE_SPLIT_512B 3 |
# define CIK_ADDR_SURF_TILE_SPLIT_1KB 4 |
# define CIK_ADDR_SURF_TILE_SPLIT_2KB 5 |
# define CIK_ADDR_SURF_TILE_SPLIT_4KB 6 |
# define CIK_GRPH_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 18) |
# define CIK_ADDR_SURF_MACRO_TILE_ASPECT_1 0 |
# define CIK_ADDR_SURF_MACRO_TILE_ASPECT_2 1 |
# define CIK_ADDR_SURF_MACRO_TILE_ASPECT_4 2 |
# define CIK_ADDR_SURF_MACRO_TILE_ASPECT_8 3 |
# define CIK_GRPH_ARRAY_MODE(x) (((x) & 0x7) << 20) |
# define CIK_GRPH_ARRAY_LINEAR_GENERAL 0 |
# define CIK_GRPH_ARRAY_LINEAR_ALIGNED 1 |
# define CIK_GRPH_ARRAY_1D_TILED_THIN1 2 |
# define CIK_GRPH_ARRAY_2D_TILED_THIN1 4 |
# define CIK_GRPH_PIPE_CONFIG(x) (((x) & 0x1f) << 24) |
# define CIK_ADDR_SURF_P2 0 |
# define CIK_ADDR_SURF_P4_8x16 4 |
# define CIK_ADDR_SURF_P4_16x16 5 |
# define CIK_ADDR_SURF_P4_16x32 6 |
# define CIK_ADDR_SURF_P4_32x32 7 |
# define CIK_ADDR_SURF_P8_16x16_8x16 8 |
# define CIK_ADDR_SURF_P8_16x32_8x16 9 |
# define CIK_ADDR_SURF_P8_32x32_8x16 10 |
# define CIK_ADDR_SURF_P8_16x32_16x16 11 |
# define CIK_ADDR_SURF_P8_32x32_16x16 12 |
# define CIK_ADDR_SURF_P8_32x32_16x32 13 |
# define CIK_ADDR_SURF_P8_32x64_32x32 14 |
# define CIK_GRPH_MICRO_TILE_MODE(x) (((x) & 0x7) << 29) |
# define CIK_DISPLAY_MICRO_TILING 0 |
# define CIK_THIN_MICRO_TILING 1 |
# define CIK_DEPTH_MICRO_TILING 2 |
# define CIK_ROTATED_MICRO_TILING 4 |
/* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */ |
#define CIK_CUR_CONTROL 0x6998 |
# define CIK_CURSOR_EN (1 << 0) |
# define CIK_CURSOR_MODE(x) (((x) & 0x3) << 8) |
# define CIK_CURSOR_MONO 0 |
# define CIK_CURSOR_24_1 1 |
# define CIK_CURSOR_24_8_PRE_MULT 2 |
# define CIK_CURSOR_24_8_UNPRE_MULT 3 |
# define CIK_CURSOR_2X_MAGNIFY (1 << 16) |
# define CIK_CURSOR_FORCE_MC_ON (1 << 20) |
# define CIK_CURSOR_URGENT_CONTROL(x) (((x) & 0x7) << 24) |
# define CIK_CURSOR_URGENT_ALWAYS 0 |
# define CIK_CURSOR_URGENT_1_8 1 |
# define CIK_CURSOR_URGENT_1_4 2 |
# define CIK_CURSOR_URGENT_3_8 3 |
# define CIK_CURSOR_URGENT_1_2 4 |
#define CIK_CUR_SURFACE_ADDRESS 0x699c |
# define CIK_CUR_SURFACE_ADDRESS_MASK 0xfffff000 |
#define CIK_CUR_SIZE 0x69a0 |
#define CIK_CUR_SURFACE_ADDRESS_HIGH 0x69a4 |
#define CIK_CUR_POSITION 0x69a8 |
#define CIK_CUR_HOT_SPOT 0x69ac |
#define CIK_CUR_COLOR1 0x69b0 |
#define CIK_CUR_COLOR2 0x69b4 |
#define CIK_CUR_UPDATE 0x69b8 |
# define CIK_CURSOR_UPDATE_PENDING (1 << 0) |
# define CIK_CURSOR_UPDATE_TAKEN (1 << 1) |
# define CIK_CURSOR_UPDATE_LOCK (1 << 16) |
# define CIK_CURSOR_DISABLE_MULTIPLE_UPDATE (1 << 24) |
#define CIK_ALPHA_CONTROL 0x6af0 |
# define CIK_CURSOR_ALPHA_BLND_ENA (1 << 1) |
#define CIK_LB_DATA_FORMAT 0x6b00 |
# define CIK_INTERLEAVE_EN (1 << 3) |
#define CIK_LB_DESKTOP_HEIGHT 0x6b0c |
#endif |
/drivers/video/drm/radeon/cik_sdma.c |
---|
0,0 → 1,955 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include <linux/firmware.h> |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "radeon_ucode.h" |
#include "radeon_asic.h" |
#include "radeon_trace.h" |
#include "cikd.h" |
/* sdma */ |
#define CIK_SDMA_UCODE_SIZE 1050 |
#define CIK_SDMA_UCODE_VERSION 64 |
u32 cik_gpu_check_soft_reset(struct radeon_device *rdev); |
/* |
* sDMA - System DMA |
* Starting with CIK, the GPU has new asynchronous |
* DMA engines. These engines are used for compute |
* and gfx. There are two DMA engines (SDMA0, SDMA1) |
* and each one supports 1 ring buffer used for gfx |
* and 2 queues used for compute. |
* |
* The programming model is very similar to the CP |
* (ring buffer, IBs, etc.), but sDMA has it's own |
* packet format that is different from the PM4 format |
* used by the CP. sDMA supports copying data, writing |
* embedded data, solid fills, and a number of other |
* things. It also has support for tiling/detiling of |
* buffers. |
*/ |
/** |
* 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); |
(void)RREG32(reg); |
} |
/** |
* cik_sdma_ring_ib_execute - Schedule an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to schedule |
* |
* Schedule an IB in the DMA ring (CIK). |
*/ |
void cik_sdma_ring_ib_execute(struct radeon_device *rdev, |
struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
u32 extra_bits = (ib->vm ? ib->vm->id : 0) & 0xf; |
if (rdev->wb.enabled) { |
u32 next_rptr = ring->wptr + 5; |
while ((next_rptr & 7) != 4) |
next_rptr++; |
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)); |
radeon_ring_write(ring, 1); /* number of DWs to follow */ |
radeon_ring_write(ring, next_rptr); |
} |
/* IB packet must end on a 8 DW boundary */ |
while ((ring->wptr & 7) != 4) |
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)); |
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 |
* @fence: radeon fence object |
* |
* Add a DMA fence packet to the ring to write |
* the fence seq number and DMA trap packet to generate |
* an interrupt if needed (CIK). |
*/ |
void cik_sdma_fence_ring_emit(struct radeon_device *rdev, |
struct radeon_fence *fence) |
{ |
struct radeon_ring *ring = &rdev->ring[fence->ring]; |
u64 addr = rdev->fence_drv[fence->ring].gpu_addr; |
/* write the fence */ |
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_FENCE, 0, 0)); |
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 */ |
cik_sdma_hdp_flush_ring_emit(rdev, fence->ring); |
} |
/** |
* cik_sdma_semaphore_ring_emit - emit a semaphore on the dma ring |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* @semaphore: radeon semaphore object |
* @emit_wait: wait or signal semaphore |
* |
* Add a DMA semaphore packet to the ring wait on or signal |
* other rings (CIK). |
*/ |
bool cik_sdma_semaphore_ring_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait) |
{ |
u64 addr = semaphore->gpu_addr; |
u32 extra_bits = emit_wait ? 0 : SDMA_SEMAPHORE_EXTRA_S; |
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)); |
return true; |
} |
/** |
* cik_sdma_gfx_stop - stop the gfx async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Stop the gfx async dma ring buffers (CIK). |
*/ |
static void cik_sdma_gfx_stop(struct radeon_device *rdev) |
{ |
u32 rb_cntl, reg_offset; |
int i; |
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) |
reg_offset = SDMA0_REGISTER_OFFSET; |
else |
reg_offset = SDMA1_REGISTER_OFFSET; |
rb_cntl = RREG32(SDMA0_GFX_RB_CNTL + reg_offset); |
rb_cntl &= ~SDMA_RB_ENABLE; |
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; |
} |
/** |
* cik_sdma_rlc_stop - stop the compute async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Stop the compute async dma queues (CIK). |
*/ |
static void cik_sdma_rlc_stop(struct radeon_device *rdev) |
{ |
/* XXX todo */ |
} |
/** |
* cik_sdma_enable - stop the async dma engines |
* |
* @rdev: radeon_device pointer |
* @enable: enable/disable the DMA MEs. |
* |
* Halt or unhalt the async dma engines (CIK). |
*/ |
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; |
else |
reg_offset = SDMA1_REGISTER_OFFSET; |
me_cntl = RREG32(SDMA0_ME_CNTL + reg_offset); |
if (enable) |
me_cntl &= ~SDMA_HALT; |
else |
me_cntl |= SDMA_HALT; |
WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl); |
} |
} |
/** |
* cik_sdma_gfx_resume - setup and start the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Set up the gfx DMA ring buffers and enable them (CIK). |
* Returns 0 for success, error for failure. |
*/ |
static int cik_sdma_gfx_resume(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring; |
u32 rb_cntl, ib_cntl; |
u32 rb_bufsz; |
u32 reg_offset, wb_offset; |
int i, r; |
for (i = 0; i < 2; i++) { |
if (i == 0) { |
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; |
reg_offset = SDMA0_REGISTER_OFFSET; |
wb_offset = R600_WB_DMA_RPTR_OFFSET; |
} else { |
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]; |
reg_offset = SDMA1_REGISTER_OFFSET; |
wb_offset = CAYMAN_WB_DMA1_RPTR_OFFSET; |
} |
WREG32(SDMA0_SEM_INCOMPLETE_TIMER_CNTL + reg_offset, 0); |
WREG32(SDMA0_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0); |
/* Set ring buffer size in dwords */ |
rb_bufsz = order_base_2(ring->ring_size / 4); |
rb_cntl = rb_bufsz << 1; |
#ifdef __BIG_ENDIAN |
rb_cntl |= SDMA_RB_SWAP_ENABLE | SDMA_RPTR_WRITEBACK_SWAP_ENABLE; |
#endif |
WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl); |
/* Initialize the ring buffer's read and write pointers */ |
WREG32(SDMA0_GFX_RB_RPTR + reg_offset, 0); |
WREG32(SDMA0_GFX_RB_WPTR + reg_offset, 0); |
/* set the wb address whether it's enabled or not */ |
WREG32(SDMA0_GFX_RB_RPTR_ADDR_HI + reg_offset, |
upper_32_bits(rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF); |
WREG32(SDMA0_GFX_RB_RPTR_ADDR_LO + reg_offset, |
((rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC)); |
if (rdev->wb.enabled) |
rb_cntl |= SDMA_RPTR_WRITEBACK_ENABLE; |
WREG32(SDMA0_GFX_RB_BASE + reg_offset, ring->gpu_addr >> 8); |
WREG32(SDMA0_GFX_RB_BASE_HI + reg_offset, ring->gpu_addr >> 40); |
ring->wptr = 0; |
WREG32(SDMA0_GFX_RB_WPTR + reg_offset, ring->wptr << 2); |
/* enable DMA RB */ |
WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl | SDMA_RB_ENABLE); |
ib_cntl = SDMA_IB_ENABLE; |
#ifdef __BIG_ENDIAN |
ib_cntl |= SDMA_IB_SWAP_ENABLE; |
#endif |
/* enable DMA IBs */ |
WREG32(SDMA0_GFX_IB_CNTL + reg_offset, ib_cntl); |
ring->ready = true; |
r = radeon_ring_test(rdev, ring->idx, ring); |
if (r) { |
ring->ready = false; |
return r; |
} |
} |
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; |
} |
/** |
* cik_sdma_rlc_resume - setup and start the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Set up the compute DMA queues and enable them (CIK). |
* Returns 0 for success, error for failure. |
*/ |
static int cik_sdma_rlc_resume(struct radeon_device *rdev) |
{ |
/* XXX todo */ |
return 0; |
} |
/** |
* cik_sdma_load_microcode - load the sDMA ME ucode |
* |
* @rdev: radeon_device pointer |
* |
* Loads the sDMA0/1 ucode. |
* Returns 0 for success, -EINVAL if the ucode is not available. |
*/ |
static int cik_sdma_load_microcode(struct radeon_device *rdev) |
{ |
int i; |
if (!rdev->sdma_fw) |
return -EINVAL; |
/* halt the MEs */ |
cik_sdma_enable(rdev, false); |
if (rdev->new_fw) { |
const struct sdma_firmware_header_v1_0 *hdr = |
(const struct sdma_firmware_header_v1_0 *)rdev->sdma_fw->data; |
const __le32 *fw_data; |
u32 fw_size; |
radeon_ucode_print_sdma_hdr(&hdr->header); |
/* sdma0 */ |
fw_data = (const __le32 *) |
(rdev->sdma_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; |
WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, le32_to_cpup(fw_data++)); |
WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); |
/* sdma1 */ |
fw_data = (const __le32 *) |
(rdev->sdma_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; |
WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, le32_to_cpup(fw_data++)); |
WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); |
} else { |
const __be32 *fw_data; |
/* sdma0 */ |
fw_data = (const __be32 *)rdev->sdma_fw->data; |
WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0); |
for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++) |
WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, be32_to_cpup(fw_data++)); |
WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); |
/* sdma1 */ |
fw_data = (const __be32 *)rdev->sdma_fw->data; |
WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0); |
for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++) |
WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, be32_to_cpup(fw_data++)); |
WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); |
} |
WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0); |
WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0); |
return 0; |
} |
/** |
* cik_sdma_resume - setup and start the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Set up the DMA engines and enable them (CIK). |
* Returns 0 for success, error for failure. |
*/ |
int cik_sdma_resume(struct radeon_device *rdev) |
{ |
int r; |
/* Reset dma */ |
WREG32(SRBM_SOFT_RESET, SOFT_RESET_SDMA | SOFT_RESET_SDMA1); |
RREG32(SRBM_SOFT_RESET); |
udelay(50); |
WREG32(SRBM_SOFT_RESET, 0); |
RREG32(SRBM_SOFT_RESET); |
r = cik_sdma_load_microcode(rdev); |
if (r) |
return r; |
/* unhalt the MEs */ |
cik_sdma_enable(rdev, true); |
/* start the gfx rings and rlc compute queues */ |
r = cik_sdma_gfx_resume(rdev); |
if (r) |
return r; |
r = cik_sdma_rlc_resume(rdev); |
if (r) |
return r; |
return 0; |
} |
/** |
* cik_sdma_fini - tear down the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engines and free the rings (CIK). |
*/ |
void cik_sdma_fini(struct radeon_device *rdev) |
{ |
/* halt the MEs */ |
cik_sdma_enable(rdev, false); |
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]); |
radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]); |
/* XXX - compute dma queue tear down */ |
} |
/** |
* cik_copy_dma - copy pages using the 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 DMA engine (CIK). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int cik_copy_dma(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.dma_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_bytes, cur_size_in_bytes; |
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 + 14); |
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; |
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, 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; |
} |
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, false); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
/** |
* cik_sdma_ring_test - simple async dma engine test |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Test the DMA engine by writing using it to write an |
* value to memory. (CIK). |
* Returns 0 for success, error for failure. |
*/ |
int cik_sdma_ring_test(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
unsigned i; |
int r; |
void __iomem *ptr = (void *)rdev->vram_scratch.ptr; |
u32 tmp; |
if (!ptr) { |
DRM_ERROR("invalid vram scratch pointer\n"); |
return -EINVAL; |
} |
tmp = 0xCAFEDEAD; |
writel(tmp, ptr); |
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)); |
radeon_ring_write(ring, 1); /* number of DWs to follow */ |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring, false); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = readl(ptr); |
if (tmp == 0xDEADBEEF) |
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 (0x%08X)\n", |
ring->idx, tmp); |
r = -EINVAL; |
} |
return r; |
} |
/** |
* cik_sdma_ib_test - test an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Test a simple IB in the DMA ring (CIK). |
* Returns 0 on success, error on failure. |
*/ |
int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
struct radeon_ib ib; |
unsigned i; |
int r; |
void __iomem *ptr = (void *)rdev->vram_scratch.ptr; |
u32 tmp = 0; |
if (!ptr) { |
DRM_ERROR("invalid vram scratch pointer\n"); |
return -EINVAL; |
} |
tmp = 0xCAFEDEAD; |
writel(tmp, ptr); |
r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); |
if (r) { |
DRM_ERROR("radeon: failed to get ib (%d).\n", r); |
return r; |
} |
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); |
ib.ptr[3] = 1; |
ib.ptr[4] = 0xDEADBEEF; |
ib.length_dw = 5; |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
if (r) { |
radeon_ib_free(rdev, &ib); |
DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); |
return r; |
} |
r = radeon_fence_wait(ib.fence, false); |
if (r) { |
DRM_ERROR("radeon: fence wait failed (%d).\n", r); |
return r; |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = readl(ptr); |
if (tmp == 0xDEADBEEF) |
break; |
DRM_UDELAY(1); |
} |
if (i < rdev->usec_timeout) { |
DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i); |
} else { |
DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp); |
r = -EINVAL; |
} |
radeon_ib_free(rdev, &ib); |
return r; |
} |
/** |
* cik_sdma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up (CIK). |
* Returns true if the engine appears to be locked up, false if not. |
*/ |
bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
u32 reset_mask = cik_gpu_check_soft_reset(rdev); |
u32 mask; |
if (ring->idx == R600_RING_TYPE_DMA_INDEX) |
mask = RADEON_RESET_DMA; |
else |
mask = RADEON_RESET_DMA1; |
if (!(reset_mask & mask)) { |
radeon_ring_lockup_update(rdev, ring); |
return false; |
} |
return radeon_ring_test_lockup(rdev, ring); |
} |
/** |
* cik_sdma_vm_copy_pages - update PTEs by copying them from the GART |
* |
* @rdev: radeon_device pointer |
* @ib: indirect buffer to fill with commands |
* @pe: addr of the page entry |
* @src: src addr to copy from |
* @count: number of page entries to update |
* |
* Update PTEs by copying them from the GART using sDMA (CIK). |
*/ |
void cik_sdma_vm_copy_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, uint64_t src, |
unsigned count) |
{ |
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; |
} |
} |
/** |
* cik_sdma_vm_write_pages - update PTEs by writing them manually |
* |
* @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 PTEs by writing them manually using sDMA (CIK). |
*/ |
void cik_sdma_vm_write_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags) |
{ |
uint64_t value; |
unsigned ndw; |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
/* for non-physically contiguous pages (system) */ |
ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE, |
SDMA_WRITE_SUB_OPCODE_LINEAR, 0); |
ib->ptr[ib->length_dw++] = pe; |
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 & R600_PTE_SYSTEM) { |
value = radeon_vm_map_gart(rdev, addr); |
value &= 0xFFFFFFFFFFFFF000ULL; |
} else if (flags & R600_PTE_VALID) { |
value = addr; |
} else { |
value = 0; |
} |
addr += incr; |
value |= flags; |
ib->ptr[ib->length_dw++] = value; |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
} |
} |
} |
/** |
* cik_sdma_vm_set_pages - 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 sDMA (CIK). |
*/ |
void cik_sdma_vm_set_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags) |
{ |
uint64_t value; |
unsigned ndw; |
while (count) { |
ndw = count; |
if (ndw > 0x7FFFF) |
ndw = 0x7FFFF; |
if (flags & R600_PTE_VALID) |
value = addr; |
else |
value = 0; |
/* for physically contiguous pages (vram) */ |
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++] = flags; /* mask */ |
ib->ptr[ib->length_dw++] = 0; |
ib->ptr[ib->length_dw++] = value; /* value */ |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
ib->ptr[ib->length_dw++] = incr; /* increment size */ |
ib->ptr[ib->length_dw++] = 0; |
ib->ptr[ib->length_dw++] = ndw; /* number of entries */ |
pe += ndw * 8; |
addr += ndw * incr; |
count -= ndw; |
} |
} |
/** |
* cik_sdma_vm_pad_ib - pad the IB to the required number of dw |
* |
* @ib: indirect buffer to fill with padding |
* |
*/ |
void cik_sdma_vm_pad_ib(struct radeon_ib *ib) |
{ |
while (ib->length_dw & 0x7) |
ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0); |
} |
/** |
* cik_dma_vm_flush - cik vm flush using sDMA |
* |
* @rdev: radeon_device pointer |
* |
* Update the page table base and flush the VM TLB |
* using sDMA (CIK). |
*/ |
void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) |
{ |
struct radeon_ring *ring = &rdev->ring[ridx]; |
if (vm == NULL) |
return; |
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); |
} else { |
radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2); |
} |
radeon_ring_write(ring, vm->pd_gpu_addr >> 12); |
/* update SH_MEM_* regs */ |
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); |
radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); |
radeon_ring_write(ring, VMID(vm->id)); |
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); |
radeon_ring_write(ring, SH_MEM_BASES >> 2); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); |
radeon_ring_write(ring, SH_MEM_CONFIG >> 2); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); |
radeon_ring_write(ring, SH_MEM_APE1_BASE >> 2); |
radeon_ring_write(ring, 1); |
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); |
radeon_ring_write(ring, SH_MEM_APE1_LIMIT >> 2); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); |
radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); |
radeon_ring_write(ring, VMID(0)); |
/* flush HDP */ |
cik_sdma_hdp_flush_ring_emit(rdev, ridx); |
/* flush TLB */ |
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); |
radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); |
radeon_ring_write(ring, 1 << vm->id); |
} |
/drivers/video/drm/radeon/cikd.h |
---|
0,0 → 1,2072 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#ifndef CIK_H |
#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 HAWAII_RB_BITMAP_WIDTH_PER_SH 4 |
/* DIDT IND registers */ |
#define DIDT_SQ_CTRL0 0x0 |
# define DIDT_CTRL_EN (1 << 0) |
#define DIDT_DB_CTRL0 0x20 |
#define DIDT_TD_CTRL0 0x40 |
#define DIDT_TCP_CTRL0 0x60 |
/* SMC IND registers */ |
#define DPM_TABLE_475 0x3F768 |
# define SamuBootLevel(x) ((x) << 0) |
# define SamuBootLevel_MASK 0x000000ff |
# define SamuBootLevel_SHIFT 0 |
# define AcpBootLevel(x) ((x) << 8) |
# define AcpBootLevel_MASK 0x0000ff00 |
# define AcpBootLevel_SHIFT 8 |
# define VceBootLevel(x) ((x) << 16) |
# define VceBootLevel_MASK 0x00ff0000 |
# define VceBootLevel_SHIFT 16 |
# define UvdBootLevel(x) ((x) << 24) |
# define UvdBootLevel_MASK 0xff000000 |
# define UvdBootLevel_SHIFT 24 |
#define FIRMWARE_FLAGS 0x3F800 |
# define INTERRUPTS_ENABLED (1 << 0) |
#define NB_DPM_CONFIG_1 0x3F9E8 |
# define Dpm0PgNbPsLo(x) ((x) << 0) |
# define Dpm0PgNbPsLo_MASK 0x000000ff |
# define Dpm0PgNbPsLo_SHIFT 0 |
# define Dpm0PgNbPsHi(x) ((x) << 8) |
# define Dpm0PgNbPsHi_MASK 0x0000ff00 |
# define Dpm0PgNbPsHi_SHIFT 8 |
# define DpmXNbPsLo(x) ((x) << 16) |
# define DpmXNbPsLo_MASK 0x00ff0000 |
# define DpmXNbPsLo_SHIFT 16 |
# define DpmXNbPsHi(x) ((x) << 24) |
# define DpmXNbPsHi_MASK 0xff000000 |
# define DpmXNbPsHi_SHIFT 24 |
#define SMC_SYSCON_RESET_CNTL 0x80000000 |
# define RST_REG (1 << 0) |
#define SMC_SYSCON_CLOCK_CNTL_0 0x80000004 |
# define CK_DISABLE (1 << 0) |
# define CKEN (1 << 24) |
#define SMC_SYSCON_MISC_CNTL 0x80000010 |
#define SMC_SYSCON_MSG_ARG_0 0x80000068 |
#define SMC_PC_C 0x80000370 |
#define SMC_SCRATCH9 0x80000424 |
#define RCU_UC_EVENTS 0xC0000004 |
# define BOOT_SEQ_DONE (1 << 7) |
#define GENERAL_PWRMGT 0xC0200000 |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define THERMAL_PROTECTION_DIS (1 << 2) |
# define THERMAL_PROTECTION_TYPE (1 << 3) |
# define SW_SMIO_INDEX(x) ((x) << 6) |
# define SW_SMIO_INDEX_MASK (1 << 6) |
# define SW_SMIO_INDEX_SHIFT 6 |
# define VOLT_PWRMGT_EN (1 << 10) |
# define GPU_COUNTER_CLK (1 << 15) |
# define DYN_SPREAD_SPECTRUM_EN (1 << 23) |
#define CNB_PWRMGT_CNTL 0xC0200004 |
# define GNB_SLOW_MODE(x) ((x) << 0) |
# define GNB_SLOW_MODE_MASK (3 << 0) |
# define GNB_SLOW_MODE_SHIFT 0 |
# define GNB_SLOW (1 << 2) |
# define FORCE_NB_PS1 (1 << 3) |
# define DPM_ENABLED (1 << 4) |
#define SCLK_PWRMGT_CNTL 0xC0200008 |
# define SCLK_PWRMGT_OFF (1 << 0) |
# define RESET_BUSY_CNT (1 << 4) |
# define RESET_SCLK_CNT (1 << 5) |
# define DYNAMIC_PM_EN (1 << 21) |
#define TARGET_AND_CURRENT_PROFILE_INDEX 0xC0200014 |
# define CURRENT_STATE_MASK (0xf << 4) |
# define CURRENT_STATE_SHIFT 4 |
# define CURR_MCLK_INDEX_MASK (0xf << 8) |
# define CURR_MCLK_INDEX_SHIFT 8 |
# define CURR_SCLK_INDEX_MASK (0x1f << 16) |
# define CURR_SCLK_INDEX_SHIFT 16 |
#define CG_SSP 0xC0200044 |
# define SST(x) ((x) << 0) |
# define SST_MASK (0xffff << 0) |
# define SSTU(x) ((x) << 16) |
# define SSTU_MASK (0xf << 16) |
#define CG_DISPLAY_GAP_CNTL 0xC0200060 |
# define DISP_GAP(x) ((x) << 0) |
# define DISP_GAP_MASK (3 << 0) |
# define VBI_TIMER_COUNT(x) ((x) << 4) |
# define VBI_TIMER_COUNT_MASK (0x3fff << 4) |
# define VBI_TIMER_UNIT(x) ((x) << 20) |
# define VBI_TIMER_UNIT_MASK (7 << 20) |
# define DISP_GAP_MCHG(x) ((x) << 24) |
# define DISP_GAP_MCHG_MASK (3 << 24) |
#define SMU_VOLTAGE_STATUS 0xC0200094 |
# define SMU_VOLTAGE_CURRENT_LEVEL_MASK (0xff << 1) |
# define SMU_VOLTAGE_CURRENT_LEVEL_SHIFT 1 |
#define TARGET_AND_CURRENT_PROFILE_INDEX_1 0xC02000F0 |
# define CURR_PCIE_INDEX_MASK (0xf << 24) |
# define CURR_PCIE_INDEX_SHIFT 24 |
#define CG_ULV_PARAMETER 0xC0200158 |
#define CG_FTV_0 0xC02001A8 |
#define CG_FTV_1 0xC02001AC |
#define CG_FTV_2 0xC02001B0 |
#define CG_FTV_3 0xC02001B4 |
#define CG_FTV_4 0xC02001B8 |
#define CG_FTV_5 0xC02001BC |
#define CG_FTV_6 0xC02001C0 |
#define CG_FTV_7 0xC02001C4 |
#define CG_DISPLAY_GAP_CNTL2 0xC0200230 |
#define LCAC_SX0_OVR_SEL 0xC0400D04 |
#define LCAC_SX0_OVR_VAL 0xC0400D08 |
#define LCAC_MC0_CNTL 0xC0400D30 |
#define LCAC_MC0_OVR_SEL 0xC0400D34 |
#define LCAC_MC0_OVR_VAL 0xC0400D38 |
#define LCAC_MC1_CNTL 0xC0400D3C |
#define LCAC_MC1_OVR_SEL 0xC0400D40 |
#define LCAC_MC1_OVR_VAL 0xC0400D44 |
#define LCAC_MC2_OVR_SEL 0xC0400D4C |
#define LCAC_MC2_OVR_VAL 0xC0400D50 |
#define LCAC_MC3_OVR_SEL 0xC0400D58 |
#define LCAC_MC3_OVR_VAL 0xC0400D5C |
#define LCAC_CPL_CNTL 0xC0400D80 |
#define LCAC_CPL_OVR_SEL 0xC0400D84 |
#define LCAC_CPL_OVR_VAL 0xC0400D88 |
/* dGPU */ |
#define CG_THERMAL_CTRL 0xC0300004 |
#define DPM_EVENT_SRC(x) ((x) << 0) |
#define DPM_EVENT_SRC_MASK (7 << 0) |
#define DIG_THERM_DPM(x) ((x) << 14) |
#define DIG_THERM_DPM_MASK 0x003FC000 |
#define DIG_THERM_DPM_SHIFT 14 |
#define CG_THERMAL_INT 0xC030000C |
#define CI_DIG_THERM_INTH(x) ((x) << 8) |
#define CI_DIG_THERM_INTH_MASK 0x0000FF00 |
#define CI_DIG_THERM_INTH_SHIFT 8 |
#define CI_DIG_THERM_INTL(x) ((x) << 16) |
#define CI_DIG_THERM_INTL_MASK 0x00FF0000 |
#define CI_DIG_THERM_INTL_SHIFT 16 |
#define THERM_INT_MASK_HIGH (1 << 24) |
#define THERM_INT_MASK_LOW (1 << 25) |
#define CG_MULT_THERMAL_STATUS 0xC0300014 |
#define ASIC_MAX_TEMP(x) ((x) << 0) |
#define ASIC_MAX_TEMP_MASK 0x000001ff |
#define ASIC_MAX_TEMP_SHIFT 0 |
#define CTF_TEMP(x) ((x) << 9) |
#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) |
#define SPLL_BYPASS_EN (1 << 3) |
#define SPLL_REF_DIV(x) ((x) << 5) |
#define SPLL_REF_DIV_MASK (0x3f << 5) |
#define SPLL_PDIV_A(x) ((x) << 20) |
#define SPLL_PDIV_A_MASK (0x7f << 20) |
#define SPLL_PDIV_A_SHIFT 20 |
#define CG_SPLL_FUNC_CNTL_2 0xC0500144 |
#define SCLK_MUX_SEL(x) ((x) << 0) |
#define SCLK_MUX_SEL_MASK (0x1ff << 0) |
#define CG_SPLL_FUNC_CNTL_3 0xC0500148 |
#define SPLL_FB_DIV(x) ((x) << 0) |
#define SPLL_FB_DIV_MASK (0x3ffffff << 0) |
#define SPLL_FB_DIV_SHIFT 0 |
#define SPLL_DITHEN (1 << 28) |
#define CG_SPLL_FUNC_CNTL_4 0xC050014C |
#define CG_SPLL_SPREAD_SPECTRUM 0xC0500164 |
#define SSEN (1 << 0) |
#define CLK_S(x) ((x) << 4) |
#define CLK_S_MASK (0xfff << 4) |
#define CLK_S_SHIFT 4 |
#define CG_SPLL_SPREAD_SPECTRUM_2 0xC0500168 |
#define CLK_V(x) ((x) << 0) |
#define CLK_V_MASK (0x3ffffff << 0) |
#define CLK_V_SHIFT 0 |
#define MPLL_BYPASSCLK_SEL 0xC050019C |
# define MPLL_CLKOUT_SEL(x) ((x) << 8) |
# define MPLL_CLKOUT_SEL_MASK 0xFF00 |
#define CG_CLKPIN_CNTL 0xC05001A0 |
# define XTALIN_DIVIDE (1 << 1) |
# define BCLK_AS_XCLK (1 << 2) |
#define CG_CLKPIN_CNTL_2 0xC05001A4 |
# define FORCE_BIF_REFCLK_EN (1 << 3) |
# define MUX_TCLK_TO_XCLK (1 << 8) |
#define THM_CLK_CNTL 0xC05001A8 |
# define CMON_CLK_SEL(x) ((x) << 0) |
# define CMON_CLK_SEL_MASK 0xFF |
# define TMON_CLK_SEL(x) ((x) << 8) |
# define TMON_CLK_SEL_MASK 0xFF00 |
#define MISC_CLK_CTRL 0xC05001AC |
# define DEEP_SLEEP_CLK_SEL(x) ((x) << 0) |
# define DEEP_SLEEP_CLK_SEL_MASK 0xFF |
# define ZCLK_SEL(x) ((x) << 8) |
# define ZCLK_SEL_MASK 0xFF00 |
/* KV/KB */ |
#define CG_THERMAL_INT_CTRL 0xC2100028 |
#define DIG_THERM_INTH(x) ((x) << 0) |
#define DIG_THERM_INTH_MASK 0x000000FF |
#define DIG_THERM_INTH_SHIFT 0 |
#define DIG_THERM_INTL(x) ((x) << 8) |
#define DIG_THERM_INTL_MASK 0x0000FF00 |
#define DIG_THERM_INTL_SHIFT 8 |
#define THERM_INTH_MASK (1 << 24) |
#define THERM_INTL_MASK (1 << 25) |
/* PCIE registers idx/data 0x38/0x3c */ |
#define PB0_PIF_PWRDOWN_0 0x1100012 /* PCIE */ |
# define PLL_POWER_STATE_IN_TXS2_0(x) ((x) << 7) |
# define PLL_POWER_STATE_IN_TXS2_0_MASK (0x7 << 7) |
# define PLL_POWER_STATE_IN_TXS2_0_SHIFT 7 |
# define PLL_POWER_STATE_IN_OFF_0(x) ((x) << 10) |
# define PLL_POWER_STATE_IN_OFF_0_MASK (0x7 << 10) |
# define PLL_POWER_STATE_IN_OFF_0_SHIFT 10 |
# define PLL_RAMP_UP_TIME_0(x) ((x) << 24) |
# define PLL_RAMP_UP_TIME_0_MASK (0x7 << 24) |
# define PLL_RAMP_UP_TIME_0_SHIFT 24 |
#define PB0_PIF_PWRDOWN_1 0x1100013 /* PCIE */ |
# define PLL_POWER_STATE_IN_TXS2_1(x) ((x) << 7) |
# define PLL_POWER_STATE_IN_TXS2_1_MASK (0x7 << 7) |
# define PLL_POWER_STATE_IN_TXS2_1_SHIFT 7 |
# define PLL_POWER_STATE_IN_OFF_1(x) ((x) << 10) |
# define PLL_POWER_STATE_IN_OFF_1_MASK (0x7 << 10) |
# define PLL_POWER_STATE_IN_OFF_1_SHIFT 10 |
# define PLL_RAMP_UP_TIME_1(x) ((x) << 24) |
# define PLL_RAMP_UP_TIME_1_MASK (0x7 << 24) |
# define PLL_RAMP_UP_TIME_1_SHIFT 24 |
#define PCIE_CNTL2 0x1001001c /* PCIE */ |
# define SLV_MEM_LS_EN (1 << 16) |
# define SLV_MEM_AGGRESSIVE_LS_EN (1 << 17) |
# define MST_MEM_LS_EN (1 << 18) |
# define REPLAY_MEM_LS_EN (1 << 19) |
#define PCIE_LC_STATUS1 0x1400028 /* PCIE */ |
# define LC_REVERSE_RCVR (1 << 0) |
# define LC_REVERSE_XMIT (1 << 1) |
# define LC_OPERATING_LINK_WIDTH_MASK (0x7 << 2) |
# define LC_OPERATING_LINK_WIDTH_SHIFT 2 |
# define LC_DETECTED_LINK_WIDTH_MASK (0x7 << 5) |
# define LC_DETECTED_LINK_WIDTH_SHIFT 5 |
#define PCIE_P_CNTL 0x1400040 /* PCIE */ |
# define P_IGNORE_EDB_ERR (1 << 6) |
#define PB1_PIF_PWRDOWN_0 0x2100012 /* PCIE */ |
#define PB1_PIF_PWRDOWN_1 0x2100013 /* PCIE */ |
#define PCIE_LC_CNTL 0x100100A0 /* PCIE */ |
# define LC_L0S_INACTIVITY(x) ((x) << 8) |
# define LC_L0S_INACTIVITY_MASK (0xf << 8) |
# define LC_L0S_INACTIVITY_SHIFT 8 |
# define LC_L1_INACTIVITY(x) ((x) << 12) |
# define LC_L1_INACTIVITY_MASK (0xf << 12) |
# define LC_L1_INACTIVITY_SHIFT 12 |
# define LC_PMI_TO_L1_DIS (1 << 16) |
# define LC_ASPM_TO_L1_DIS (1 << 24) |
#define PCIE_LC_LINK_WIDTH_CNTL 0x100100A2 /* PCIE */ |
# define LC_LINK_WIDTH_SHIFT 0 |
# define LC_LINK_WIDTH_MASK 0x7 |
# define LC_LINK_WIDTH_X0 0 |
# define LC_LINK_WIDTH_X1 1 |
# define LC_LINK_WIDTH_X2 2 |
# define LC_LINK_WIDTH_X4 3 |
# define LC_LINK_WIDTH_X8 4 |
# define LC_LINK_WIDTH_X16 6 |
# define LC_LINK_WIDTH_RD_SHIFT 4 |
# define LC_LINK_WIDTH_RD_MASK 0x70 |
# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) |
# define LC_RECONFIG_NOW (1 << 8) |
# define LC_RENEGOTIATION_SUPPORT (1 << 9) |
# define LC_RENEGOTIATE_EN (1 << 10) |
# define LC_SHORT_RECONFIG_EN (1 << 11) |
# define LC_UPCONFIGURE_SUPPORT (1 << 12) |
# define LC_UPCONFIGURE_DIS (1 << 13) |
# define LC_DYN_LANES_PWR_STATE(x) ((x) << 21) |
# define LC_DYN_LANES_PWR_STATE_MASK (0x3 << 21) |
# define LC_DYN_LANES_PWR_STATE_SHIFT 21 |
#define PCIE_LC_N_FTS_CNTL 0x100100a3 /* PCIE */ |
# define LC_XMIT_N_FTS(x) ((x) << 0) |
# define LC_XMIT_N_FTS_MASK (0xff << 0) |
# define LC_XMIT_N_FTS_SHIFT 0 |
# define LC_XMIT_N_FTS_OVERRIDE_EN (1 << 8) |
# define LC_N_FTS_MASK (0xff << 24) |
#define PCIE_LC_SPEED_CNTL 0x100100A4 /* PCIE */ |
# define LC_GEN2_EN_STRAP (1 << 0) |
# define LC_GEN3_EN_STRAP (1 << 1) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 2) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_MASK (0x3 << 3) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_SHIFT 3 |
# define LC_FORCE_EN_SW_SPEED_CHANGE (1 << 5) |
# define LC_FORCE_DIS_SW_SPEED_CHANGE (1 << 6) |
# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 7) |
# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 8) |
# define LC_INITIATE_LINK_SPEED_CHANGE (1 << 9) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 10) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 10 |
# define LC_CURRENT_DATA_RATE_MASK (0x3 << 13) /* 0/1/2 = gen1/2/3 */ |
# define LC_CURRENT_DATA_RATE_SHIFT 13 |
# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 16) |
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 18) |
# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 19) |
# define LC_OTHER_SIDE_EVER_SENT_GEN3 (1 << 20) |
# define LC_OTHER_SIDE_SUPPORTS_GEN3 (1 << 21) |
#define PCIE_LC_CNTL2 0x100100B1 /* PCIE */ |
# define LC_ALLOW_PDWN_IN_L1 (1 << 17) |
# define LC_ALLOW_PDWN_IN_L23 (1 << 18) |
#define PCIE_LC_CNTL3 0x100100B5 /* PCIE */ |
# define LC_GO_TO_RECOVERY (1 << 30) |
#define PCIE_LC_CNTL4 0x100100B6 /* PCIE */ |
# define LC_REDO_EQ (1 << 5) |
# define LC_SET_QUIESCE (1 << 13) |
/* direct registers */ |
#define PCIE_INDEX 0x38 |
#define PCIE_DATA 0x3C |
#define SMC_IND_INDEX_0 0x200 |
#define SMC_IND_DATA_0 0x204 |
#define SMC_IND_ACCESS_CNTL 0x240 |
#define AUTO_INCREMENT_IND_0 (1 << 0) |
#define SMC_MESSAGE_0 0x250 |
#define SMC_MSG_MASK 0xffff |
#define SMC_RESP_0 0x254 |
#define SMC_RESP_MASK 0xffff |
#define SMC_MSG_ARG_0 0x290 |
#define VGA_HDP_CONTROL 0x328 |
#define VGA_MEMORY_DISABLE (1 << 4) |
#define DMIF_ADDR_CALC 0xC00 |
#define PIPE0_DMIF_BUFFER_CONTROL 0x0ca0 |
# define DMIF_BUFFERS_ALLOCATED(x) ((x) << 0) |
# define DMIF_BUFFERS_ALLOCATED_COMPLETED (1 << 4) |
#define SRBM_GFX_CNTL 0xE44 |
#define PIPEID(x) ((x) << 0) |
#define MEID(x) ((x) << 2) |
#define VMID(x) ((x) << 4) |
#define QUEUEID(x) ((x) << 8) |
#define SRBM_STATUS2 0xE4C |
#define SDMA_BUSY (1 << 5) |
#define SDMA1_BUSY (1 << 6) |
#define SRBM_STATUS 0xE50 |
#define UVD_RQ_PENDING (1 << 1) |
#define GRBM_RQ_PENDING (1 << 5) |
#define VMC_BUSY (1 << 8) |
#define MCB_BUSY (1 << 9) |
#define MCB_NON_DISPLAY_BUSY (1 << 10) |
#define MCC_BUSY (1 << 11) |
#define MCD_BUSY (1 << 12) |
#define SEM_BUSY (1 << 14) |
#define IH_BUSY (1 << 17) |
#define UVD_BUSY (1 << 19) |
#define SRBM_SOFT_RESET 0xE60 |
#define SOFT_RESET_BIF (1 << 1) |
#define SOFT_RESET_R0PLL (1 << 4) |
#define SOFT_RESET_DC (1 << 5) |
#define SOFT_RESET_SDMA1 (1 << 6) |
#define SOFT_RESET_GRBM (1 << 8) |
#define SOFT_RESET_HDP (1 << 9) |
#define SOFT_RESET_IH (1 << 10) |
#define SOFT_RESET_MC (1 << 11) |
#define SOFT_RESET_ROM (1 << 14) |
#define SOFT_RESET_SEM (1 << 15) |
#define SOFT_RESET_VMC (1 << 17) |
#define SOFT_RESET_SDMA (1 << 20) |
#define SOFT_RESET_TST (1 << 21) |
#define SOFT_RESET_REGBB (1 << 22) |
#define SOFT_RESET_ORB (1 << 23) |
#define SOFT_RESET_VCE (1 << 24) |
#define VM_L2_CNTL 0x1400 |
#define ENABLE_L2_CACHE (1 << 0) |
#define ENABLE_L2_FRAGMENT_PROCESSING (1 << 1) |
#define L2_CACHE_PTE_ENDIAN_SWAP_MODE(x) ((x) << 2) |
#define L2_CACHE_PDE_ENDIAN_SWAP_MODE(x) ((x) << 4) |
#define ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE (1 << 9) |
#define ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE (1 << 10) |
#define EFFECTIVE_L2_QUEUE_SIZE(x) (((x) & 7) << 15) |
#define CONTEXT1_IDENTITY_ACCESS_MODE(x) (((x) & 3) << 19) |
#define VM_L2_CNTL2 0x1404 |
#define INVALIDATE_ALL_L1_TLBS (1 << 0) |
#define INVALIDATE_L2_CACHE (1 << 1) |
#define INVALIDATE_CACHE_MODE(x) ((x) << 26) |
#define INVALIDATE_PTE_AND_PDE_CACHES 0 |
#define INVALIDATE_ONLY_PTE_CACHES 1 |
#define INVALIDATE_ONLY_PDE_CACHES 2 |
#define VM_L2_CNTL3 0x1408 |
#define BANK_SELECT(x) ((x) << 0) |
#define L2_CACHE_UPDATE_MODE(x) ((x) << 6) |
#define L2_CACHE_BIGK_FRAGMENT_SIZE(x) ((x) << 15) |
#define L2_CACHE_BIGK_ASSOCIATIVITY (1 << 20) |
#define VM_L2_STATUS 0x140C |
#define L2_BUSY (1 << 0) |
#define VM_CONTEXT0_CNTL 0x1410 |
#define ENABLE_CONTEXT (1 << 0) |
#define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1) |
#define RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 3) |
#define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4) |
#define DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 6) |
#define DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 7) |
#define PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 9) |
#define PDE0_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 10) |
#define VALID_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 12) |
#define VALID_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 13) |
#define READ_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 15) |
#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 |
#define VM_CONTEXT8_PAGE_TABLE_BASE_ADDR 0x1438 |
#define VM_CONTEXT9_PAGE_TABLE_BASE_ADDR 0x143c |
#define VM_CONTEXT10_PAGE_TABLE_BASE_ADDR 0x1440 |
#define VM_CONTEXT11_PAGE_TABLE_BASE_ADDR 0x1444 |
#define VM_CONTEXT12_PAGE_TABLE_BASE_ADDR 0x1448 |
#define VM_CONTEXT13_PAGE_TABLE_BASE_ADDR 0x144c |
#define VM_CONTEXT14_PAGE_TABLE_BASE_ADDR 0x1450 |
#define VM_CONTEXT15_PAGE_TABLE_BASE_ADDR 0x1454 |
#define VM_INVALIDATE_REQUEST 0x1478 |
#define VM_INVALIDATE_RESPONSE 0x147c |
#define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC |
#define PROTECTIONS_MASK (0xf << 0) |
#define PROTECTIONS_SHIFT 0 |
/* bit 0: range |
* bit 1: pde0 |
* bit 2: valid |
* bit 3: read |
* 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 |
#define FAULT_VMID_MASK (0xf << 25) |
#define FAULT_VMID_SHIFT 25 |
#define VM_CONTEXT1_PROTECTION_FAULT_MCCLIENT 0x14E4 |
#define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC |
#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR 0x1518 |
#define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR 0x151c |
#define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153c |
#define VM_CONTEXT1_PAGE_TABLE_BASE_ADDR 0x1540 |
#define VM_CONTEXT2_PAGE_TABLE_BASE_ADDR 0x1544 |
#define VM_CONTEXT3_PAGE_TABLE_BASE_ADDR 0x1548 |
#define VM_CONTEXT4_PAGE_TABLE_BASE_ADDR 0x154c |
#define VM_CONTEXT5_PAGE_TABLE_BASE_ADDR 0x1550 |
#define VM_CONTEXT6_PAGE_TABLE_BASE_ADDR 0x1554 |
#define VM_CONTEXT7_PAGE_TABLE_BASE_ADDR 0x1558 |
#define VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x155c |
#define VM_CONTEXT1_PAGE_TABLE_START_ADDR 0x1560 |
#define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157C |
#define VM_CONTEXT1_PAGE_TABLE_END_ADDR 0x1580 |
#define VM_L2_CG 0x15c0 |
#define MC_CG_ENABLE (1 << 18) |
#define MC_LS_ENABLE (1 << 19) |
#define MC_SHARED_CHMAP 0x2004 |
#define NOOFCHAN_SHIFT 12 |
#define NOOFCHAN_MASK 0x0000f000 |
#define MC_SHARED_CHREMAP 0x2008 |
#define CHUB_CONTROL 0x1864 |
#define BYPASS_VM (1 << 0) |
#define MC_VM_FB_LOCATION 0x2024 |
#define MC_VM_AGP_TOP 0x2028 |
#define MC_VM_AGP_BOT 0x202C |
#define MC_VM_AGP_BASE 0x2030 |
#define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 |
#define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 |
#define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C |
#define MC_VM_MX_L1_TLB_CNTL 0x2064 |
#define ENABLE_L1_TLB (1 << 0) |
#define ENABLE_L1_FRAGMENT_PROCESSING (1 << 1) |
#define SYSTEM_ACCESS_MODE_PA_ONLY (0 << 3) |
#define SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 3) |
#define SYSTEM_ACCESS_MODE_IN_SYS (2 << 3) |
#define SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 3) |
#define SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 5) |
#define ENABLE_ADVANCED_DRIVER_MODEL (1 << 6) |
#define MC_VM_FB_OFFSET 0x2068 |
#define MC_SHARED_BLACKOUT_CNTL 0x20ac |
#define MC_HUB_MISC_HUB_CG 0x20b8 |
#define MC_HUB_MISC_VM_CG 0x20bc |
#define MC_HUB_MISC_SIP_CG 0x20c0 |
#define MC_XPB_CLK_GAT 0x2478 |
#define MC_CITF_MISC_RD_CG 0x2648 |
#define MC_CITF_MISC_WR_CG 0x264c |
#define MC_CITF_MISC_VM_CG 0x2650 |
#define MC_ARB_RAMCFG 0x2760 |
#define NOOFBANK_SHIFT 0 |
#define NOOFBANK_MASK 0x00000003 |
#define NOOFRANK_SHIFT 2 |
#define NOOFRANK_MASK 0x00000004 |
#define NOOFROWS_SHIFT 3 |
#define NOOFROWS_MASK 0x00000038 |
#define NOOFCOLS_SHIFT 6 |
#define NOOFCOLS_MASK 0x000000C0 |
#define CHANSIZE_SHIFT 8 |
#define CHANSIZE_MASK 0x00000100 |
#define NOOFGROUPS_SHIFT 12 |
#define NOOFGROUPS_MASK 0x00001000 |
#define MC_ARB_DRAM_TIMING 0x2774 |
#define MC_ARB_DRAM_TIMING2 0x2778 |
#define MC_ARB_BURST_TIME 0x2808 |
#define STATE0(x) ((x) << 0) |
#define STATE0_MASK (0x1f << 0) |
#define STATE0_SHIFT 0 |
#define STATE1(x) ((x) << 5) |
#define STATE1_MASK (0x1f << 5) |
#define STATE1_SHIFT 5 |
#define STATE2(x) ((x) << 10) |
#define STATE2_MASK (0x1f << 10) |
#define STATE2_SHIFT 10 |
#define STATE3(x) ((x) << 15) |
#define STATE3_MASK (0x1f << 15) |
#define STATE3_SHIFT 15 |
#define MC_SEQ_RAS_TIMING 0x28a0 |
#define MC_SEQ_CAS_TIMING 0x28a4 |
#define MC_SEQ_MISC_TIMING 0x28a8 |
#define MC_SEQ_MISC_TIMING2 0x28ac |
#define MC_SEQ_PMG_TIMING 0x28b0 |
#define MC_SEQ_RD_CTL_D0 0x28b4 |
#define MC_SEQ_RD_CTL_D1 0x28b8 |
#define MC_SEQ_WR_CTL_D0 0x28bc |
#define MC_SEQ_WR_CTL_D1 0x28c0 |
#define MC_SEQ_SUP_CNTL 0x28c8 |
#define RUN_MASK (1 << 0) |
#define MC_SEQ_SUP_PGM 0x28cc |
#define MC_PMG_AUTO_CMD 0x28d0 |
#define MC_SEQ_TRAIN_WAKEUP_CNTL 0x28e8 |
#define TRAIN_DONE_D0 (1 << 30) |
#define TRAIN_DONE_D1 (1 << 31) |
#define MC_IO_PAD_CNTL_D0 0x29d0 |
#define MEM_FALL_OUT_CMD (1 << 8) |
#define MC_SEQ_MISC0 0x2a00 |
#define MC_SEQ_MISC0_VEN_ID_SHIFT 8 |
#define MC_SEQ_MISC0_VEN_ID_MASK 0x00000f00 |
#define MC_SEQ_MISC0_VEN_ID_VALUE 3 |
#define MC_SEQ_MISC0_REV_ID_SHIFT 12 |
#define MC_SEQ_MISC0_REV_ID_MASK 0x0000f000 |
#define MC_SEQ_MISC0_REV_ID_VALUE 1 |
#define MC_SEQ_MISC0_GDDR5_SHIFT 28 |
#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000 |
#define MC_SEQ_MISC0_GDDR5_VALUE 5 |
#define MC_SEQ_MISC1 0x2a04 |
#define MC_SEQ_RESERVE_M 0x2a08 |
#define MC_PMG_CMD_EMRS 0x2a0c |
#define MC_SEQ_IO_DEBUG_INDEX 0x2a44 |
#define MC_SEQ_IO_DEBUG_DATA 0x2a48 |
#define MC_SEQ_MISC5 0x2a54 |
#define MC_SEQ_MISC6 0x2a58 |
#define MC_SEQ_MISC7 0x2a64 |
#define MC_SEQ_RAS_TIMING_LP 0x2a6c |
#define MC_SEQ_CAS_TIMING_LP 0x2a70 |
#define MC_SEQ_MISC_TIMING_LP 0x2a74 |
#define MC_SEQ_MISC_TIMING2_LP 0x2a78 |
#define MC_SEQ_WR_CTL_D0_LP 0x2a7c |
#define MC_SEQ_WR_CTL_D1_LP 0x2a80 |
#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84 |
#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88 |
#define MC_PMG_CMD_MRS 0x2aac |
#define MC_SEQ_RD_CTL_D0_LP 0x2b1c |
#define MC_SEQ_RD_CTL_D1_LP 0x2b20 |
#define MC_PMG_CMD_MRS1 0x2b44 |
#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48 |
#define MC_SEQ_PMG_TIMING_LP 0x2b4c |
#define MC_SEQ_WR_CTL_2 0x2b54 |
#define MC_SEQ_WR_CTL_2_LP 0x2b58 |
#define MC_PMG_CMD_MRS2 0x2b5c |
#define MC_SEQ_PMG_CMD_MRS2_LP 0x2b60 |
#define MCLK_PWRMGT_CNTL 0x2ba0 |
# define DLL_SPEED(x) ((x) << 0) |
# define DLL_SPEED_MASK (0x1f << 0) |
# define DLL_READY (1 << 6) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCK0_PDNB (1 << 8) |
# define MRDCK1_PDNB (1 << 9) |
# define MRDCK0_RESET (1 << 16) |
# define MRDCK1_RESET (1 << 17) |
# define DLL_READY_READ (1 << 24) |
#define DLL_CNTL 0x2ba4 |
# define MRDCK0_BYPASS (1 << 24) |
# define MRDCK1_BYPASS (1 << 25) |
#define MPLL_FUNC_CNTL 0x2bb4 |
#define BWCTRL(x) ((x) << 20) |
#define BWCTRL_MASK (0xff << 20) |
#define MPLL_FUNC_CNTL_1 0x2bb8 |
#define VCO_MODE(x) ((x) << 0) |
#define VCO_MODE_MASK (3 << 0) |
#define CLKFRAC(x) ((x) << 4) |
#define CLKFRAC_MASK (0xfff << 4) |
#define CLKF(x) ((x) << 16) |
#define CLKF_MASK (0xfff << 16) |
#define MPLL_FUNC_CNTL_2 0x2bbc |
#define MPLL_AD_FUNC_CNTL 0x2bc0 |
#define YCLK_POST_DIV(x) ((x) << 0) |
#define YCLK_POST_DIV_MASK (7 << 0) |
#define MPLL_DQ_FUNC_CNTL 0x2bc4 |
#define YCLK_SEL(x) ((x) << 4) |
#define YCLK_SEL_MASK (1 << 4) |
#define MPLL_SS1 0x2bcc |
#define CLKV(x) ((x) << 0) |
#define CLKV_MASK (0x3ffffff << 0) |
#define MPLL_SS2 0x2bd0 |
#define CLKS(x) ((x) << 0) |
#define CLKS_MASK (0xfff << 0) |
#define HDP_HOST_PATH_CNTL 0x2C00 |
#define CLOCK_GATING_DIS (1 << 23) |
#define HDP_NONSURFACE_BASE 0x2C04 |
#define HDP_NONSURFACE_INFO 0x2C08 |
#define HDP_NONSURFACE_SIZE 0x2C0C |
#define HDP_ADDR_CONFIG 0x2F48 |
#define HDP_MISC_CNTL 0x2F4C |
#define HDP_FLUSH_INVALIDATE_CACHE (1 << 0) |
#define HDP_MEM_POWER_LS 0x2F50 |
#define HDP_LS_ENABLE (1 << 0) |
#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 |
#define MC_SEQ_G5PDX_CTRL_LP 0x3608 |
#define MC_SEQ_G5PDX_CMD0 0x360c |
#define MC_SEQ_G5PDX_CMD0_LP 0x3610 |
#define MC_SEQ_G5PDX_CMD1 0x3614 |
#define MC_SEQ_G5PDX_CMD1_LP 0x3618 |
#define MC_SEQ_PMG_DVS_CTL 0x3628 |
#define MC_SEQ_PMG_DVS_CTL_LP 0x362c |
#define MC_SEQ_PMG_DVS_CMD 0x3630 |
#define MC_SEQ_PMG_DVS_CMD_LP 0x3634 |
#define MC_SEQ_DLL_STBY 0x3638 |
#define MC_SEQ_DLL_STBY_LP 0x363c |
#define IH_RB_CNTL 0x3e00 |
# define IH_RB_ENABLE (1 << 0) |
# define IH_RB_SIZE(x) ((x) << 1) /* log2 */ |
# define IH_RB_FULL_DRAIN_ENABLE (1 << 6) |
# define IH_WPTR_WRITEBACK_ENABLE (1 << 8) |
# define IH_WPTR_WRITEBACK_TIMER(x) ((x) << 9) /* log2 */ |
# define IH_WPTR_OVERFLOW_ENABLE (1 << 16) |
# define IH_WPTR_OVERFLOW_CLEAR (1 << 31) |
#define IH_RB_BASE 0x3e04 |
#define IH_RB_RPTR 0x3e08 |
#define IH_RB_WPTR 0x3e0c |
# define RB_OVERFLOW (1 << 0) |
# define WPTR_OFFSET_MASK 0x3fffc |
#define IH_RB_WPTR_ADDR_HI 0x3e10 |
#define IH_RB_WPTR_ADDR_LO 0x3e14 |
#define IH_CNTL 0x3e18 |
# define ENABLE_INTR (1 << 0) |
# define IH_MC_SWAP(x) ((x) << 1) |
# define IH_MC_SWAP_NONE 0 |
# define IH_MC_SWAP_16BIT 1 |
# define IH_MC_SWAP_32BIT 2 |
# define IH_MC_SWAP_64BIT 3 |
# define RPTR_REARM (1 << 4) |
# define MC_WRREQ_CREDIT(x) ((x) << 15) |
# define MC_WR_CLEAN_CNT(x) ((x) << 20) |
# define MC_VMID(x) ((x) << 25) |
#define BIF_LNCNT_RESET 0x5220 |
# define RESET_LNCNT_EN (1 << 0) |
#define CONFIG_MEMSIZE 0x5428 |
#define INTERRUPT_CNTL 0x5468 |
# define IH_DUMMY_RD_OVERRIDE (1 << 0) |
# define IH_DUMMY_RD_EN (1 << 1) |
# define IH_REQ_NONSNOOP_EN (1 << 3) |
# define GEN_IH_INT_EN (1 << 8) |
#define INTERRUPT_CNTL2 0x546c |
#define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 |
#define BIF_FB_EN 0x5490 |
#define FB_READ_EN (1 << 0) |
#define FB_WRITE_EN (1 << 1) |
#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 |
#define GPU_HDP_FLUSH_REQ 0x54DC |
#define GPU_HDP_FLUSH_DONE 0x54E0 |
#define CP0 (1 << 0) |
#define CP1 (1 << 1) |
#define CP2 (1 << 2) |
#define CP3 (1 << 3) |
#define CP4 (1 << 4) |
#define CP5 (1 << 5) |
#define CP6 (1 << 6) |
#define CP7 (1 << 7) |
#define CP8 (1 << 8) |
#define CP9 (1 << 9) |
#define SDMA0 (1 << 10) |
#define SDMA1 (1 << 11) |
/* 0x6b04, 0x7704, 0x10304, 0x10f04, 0x11b04, 0x12704 */ |
#define LB_MEMORY_CTRL 0x6b04 |
#define LB_MEMORY_SIZE(x) ((x) << 0) |
#define LB_MEMORY_CONFIG(x) ((x) << 20) |
#define DPG_WATERMARK_MASK_CONTROL 0x6cc8 |
# define LATENCY_WATERMARK_MASK(x) ((x) << 8) |
#define DPG_PIPE_LATENCY_CONTROL 0x6ccc |
# define LATENCY_LOW_WATERMARK(x) ((x) << 0) |
# define LATENCY_HIGH_WATERMARK(x) ((x) << 16) |
/* 0x6b24, 0x7724, 0x10324, 0x10f24, 0x11b24, 0x12724 */ |
#define LB_VLINE_STATUS 0x6b24 |
# define VLINE_OCCURRED (1 << 0) |
# define VLINE_ACK (1 << 4) |
# define VLINE_STAT (1 << 12) |
# define VLINE_INTERRUPT (1 << 16) |
# define VLINE_INTERRUPT_TYPE (1 << 17) |
/* 0x6b2c, 0x772c, 0x1032c, 0x10f2c, 0x11b2c, 0x1272c */ |
#define LB_VBLANK_STATUS 0x6b2c |
# define VBLANK_OCCURRED (1 << 0) |
# define VBLANK_ACK (1 << 4) |
# define VBLANK_STAT (1 << 12) |
# define VBLANK_INTERRUPT (1 << 16) |
# define VBLANK_INTERRUPT_TYPE (1 << 17) |
/* 0x6b20, 0x7720, 0x10320, 0x10f20, 0x11b20, 0x12720 */ |
#define LB_INTERRUPT_MASK 0x6b20 |
# define VBLANK_INTERRUPT_MASK (1 << 0) |
# define VLINE_INTERRUPT_MASK (1 << 4) |
# define VLINE2_INTERRUPT_MASK (1 << 8) |
#define DISP_INTERRUPT_STATUS 0x60f4 |
# define LB_D1_VLINE_INTERRUPT (1 << 2) |
# define LB_D1_VBLANK_INTERRUPT (1 << 3) |
# define DC_HPD1_INTERRUPT (1 << 17) |
# define DC_HPD1_RX_INTERRUPT (1 << 18) |
# define DACA_AUTODETECT_INTERRUPT (1 << 22) |
# define DACB_AUTODETECT_INTERRUPT (1 << 23) |
# define DC_I2C_SW_DONE_INTERRUPT (1 << 24) |
# define DC_I2C_HW_DONE_INTERRUPT (1 << 25) |
#define DISP_INTERRUPT_STATUS_CONTINUE 0x60f8 |
# define LB_D2_VLINE_INTERRUPT (1 << 2) |
# define LB_D2_VBLANK_INTERRUPT (1 << 3) |
# define DC_HPD2_INTERRUPT (1 << 17) |
# define DC_HPD2_RX_INTERRUPT (1 << 18) |
# define DISP_TIMER_INTERRUPT (1 << 24) |
#define DISP_INTERRUPT_STATUS_CONTINUE2 0x60fc |
# define LB_D3_VLINE_INTERRUPT (1 << 2) |
# define LB_D3_VBLANK_INTERRUPT (1 << 3) |
# define DC_HPD3_INTERRUPT (1 << 17) |
# define DC_HPD3_RX_INTERRUPT (1 << 18) |
#define DISP_INTERRUPT_STATUS_CONTINUE3 0x6100 |
# define LB_D4_VLINE_INTERRUPT (1 << 2) |
# define LB_D4_VBLANK_INTERRUPT (1 << 3) |
# define DC_HPD4_INTERRUPT (1 << 17) |
# define DC_HPD4_RX_INTERRUPT (1 << 18) |
#define DISP_INTERRUPT_STATUS_CONTINUE4 0x614c |
# define LB_D5_VLINE_INTERRUPT (1 << 2) |
# define LB_D5_VBLANK_INTERRUPT (1 << 3) |
# define DC_HPD5_INTERRUPT (1 << 17) |
# define DC_HPD5_RX_INTERRUPT (1 << 18) |
#define DISP_INTERRUPT_STATUS_CONTINUE5 0x6150 |
# define LB_D6_VLINE_INTERRUPT (1 << 2) |
# define LB_D6_VBLANK_INTERRUPT (1 << 3) |
# define DC_HPD6_INTERRUPT (1 << 17) |
# 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 |
#define DC_HPD2_INT_STATUS 0x6028 |
#define DC_HPD3_INT_STATUS 0x6034 |
#define DC_HPD4_INT_STATUS 0x6040 |
#define DC_HPD5_INT_STATUS 0x604c |
#define DC_HPD6_INT_STATUS 0x6058 |
# define DC_HPDx_INT_STATUS (1 << 0) |
# define DC_HPDx_SENSE (1 << 1) |
# define DC_HPDx_SENSE_DELAYED (1 << 4) |
# define DC_HPDx_RX_INT_STATUS (1 << 8) |
#define DC_HPD1_INT_CONTROL 0x6020 |
#define DC_HPD2_INT_CONTROL 0x602c |
#define DC_HPD3_INT_CONTROL 0x6038 |
#define DC_HPD4_INT_CONTROL 0x6044 |
#define DC_HPD5_INT_CONTROL 0x6050 |
#define DC_HPD6_INT_CONTROL 0x605c |
# define DC_HPDx_INT_ACK (1 << 0) |
# define DC_HPDx_INT_POLARITY (1 << 8) |
# define DC_HPDx_INT_EN (1 << 16) |
# define DC_HPDx_RX_INT_ACK (1 << 20) |
# define DC_HPDx_RX_INT_EN (1 << 24) |
#define DC_HPD1_CONTROL 0x6024 |
#define DC_HPD2_CONTROL 0x6030 |
#define DC_HPD3_CONTROL 0x603c |
#define DC_HPD4_CONTROL 0x6048 |
#define DC_HPD5_CONTROL 0x6054 |
#define DC_HPD6_CONTROL 0x6060 |
# define DC_HPDx_CONNECTION_TIMER(x) ((x) << 0) |
# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) |
# define DC_HPDx_EN (1 << 28) |
#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) |
#define GRBM_STATUS2 0x8008 |
#define ME0PIPE1_CMDFIFO_AVAIL_MASK 0x0000000F |
#define ME0PIPE1_CF_RQ_PENDING (1 << 4) |
#define ME0PIPE1_PF_RQ_PENDING (1 << 5) |
#define ME1PIPE0_RQ_PENDING (1 << 6) |
#define ME1PIPE1_RQ_PENDING (1 << 7) |
#define ME1PIPE2_RQ_PENDING (1 << 8) |
#define ME1PIPE3_RQ_PENDING (1 << 9) |
#define ME2PIPE0_RQ_PENDING (1 << 10) |
#define ME2PIPE1_RQ_PENDING (1 << 11) |
#define ME2PIPE2_RQ_PENDING (1 << 12) |
#define ME2PIPE3_RQ_PENDING (1 << 13) |
#define RLC_RQ_PENDING (1 << 14) |
#define RLC_BUSY (1 << 24) |
#define TC_BUSY (1 << 25) |
#define CPF_BUSY (1 << 28) |
#define CPC_BUSY (1 << 29) |
#define CPG_BUSY (1 << 30) |
#define GRBM_STATUS 0x8010 |
#define ME0PIPE0_CMDFIFO_AVAIL_MASK 0x0000000F |
#define SRBM_RQ_PENDING (1 << 5) |
#define ME0PIPE0_CF_RQ_PENDING (1 << 7) |
#define ME0PIPE0_PF_RQ_PENDING (1 << 8) |
#define GDS_DMA_RQ_PENDING (1 << 9) |
#define DB_CLEAN (1 << 12) |
#define CB_CLEAN (1 << 13) |
#define TA_BUSY (1 << 14) |
#define GDS_BUSY (1 << 15) |
#define WD_BUSY_NO_DMA (1 << 16) |
#define VGT_BUSY (1 << 17) |
#define IA_BUSY_NO_DMA (1 << 18) |
#define IA_BUSY (1 << 19) |
#define SX_BUSY (1 << 20) |
#define WD_BUSY (1 << 21) |
#define SPI_BUSY (1 << 22) |
#define BCI_BUSY (1 << 23) |
#define SC_BUSY (1 << 24) |
#define PA_BUSY (1 << 25) |
#define DB_BUSY (1 << 26) |
#define CP_COHERENCY_BUSY (1 << 28) |
#define CP_BUSY (1 << 29) |
#define CB_BUSY (1 << 30) |
#define GUI_ACTIVE (1 << 31) |
#define GRBM_STATUS_SE0 0x8014 |
#define GRBM_STATUS_SE1 0x8018 |
#define GRBM_STATUS_SE2 0x8038 |
#define GRBM_STATUS_SE3 0x803C |
#define SE_DB_CLEAN (1 << 1) |
#define SE_CB_CLEAN (1 << 2) |
#define SE_BCI_BUSY (1 << 22) |
#define SE_VGT_BUSY (1 << 23) |
#define SE_PA_BUSY (1 << 24) |
#define SE_TA_BUSY (1 << 25) |
#define SE_SX_BUSY (1 << 26) |
#define SE_SPI_BUSY (1 << 27) |
#define SE_SC_BUSY (1 << 29) |
#define SE_DB_BUSY (1 << 30) |
#define SE_CB_BUSY (1 << 31) |
#define GRBM_SOFT_RESET 0x8020 |
#define SOFT_RESET_CP (1 << 0) /* All CP blocks */ |
#define SOFT_RESET_RLC (1 << 2) /* RLC */ |
#define SOFT_RESET_GFX (1 << 16) /* GFX */ |
#define SOFT_RESET_CPF (1 << 17) /* CP fetcher shared by gfx and compute */ |
#define SOFT_RESET_CPC (1 << 18) /* CP Compute (MEC1/2) */ |
#define SOFT_RESET_CPG (1 << 19) /* CP GFX (PFP, ME, CE) */ |
#define GRBM_INT_CNTL 0x8060 |
# define RDERR_INT_ENABLE (1 << 0) |
# define GUI_IDLE_INT_ENABLE (1 << 19) |
#define CP_CPC_STATUS 0x8210 |
#define CP_CPC_BUSY_STAT 0x8214 |
#define CP_CPC_STALLED_STAT1 0x8218 |
#define CP_CPF_STATUS 0x821c |
#define CP_CPF_BUSY_STAT 0x8220 |
#define CP_CPF_STALLED_STAT1 0x8224 |
#define CP_MEC_CNTL 0x8234 |
#define MEC_ME2_HALT (1 << 28) |
#define MEC_ME1_HALT (1 << 30) |
#define CP_MEC_CNTL 0x8234 |
#define MEC_ME2_HALT (1 << 28) |
#define MEC_ME1_HALT (1 << 30) |
#define CP_STALLED_STAT3 0x8670 |
#define CP_STALLED_STAT1 0x8674 |
#define CP_STALLED_STAT2 0x8678 |
#define CP_STAT 0x8680 |
#define CP_ME_CNTL 0x86D8 |
#define CP_CE_HALT (1 << 24) |
#define CP_PFP_HALT (1 << 26) |
#define CP_ME_HALT (1 << 28) |
#define CP_RB0_RPTR 0x8700 |
#define CP_RB_WPTR_DELAY 0x8704 |
#define CP_RB_WPTR_POLL_CNTL 0x8708 |
#define IDLE_POLL_COUNT(x) ((x) << 16) |
#define IDLE_POLL_COUNT_MASK (0xffff << 16) |
#define CP_MEQ_THRESHOLDS 0x8764 |
#define MEQ1_START(x) ((x) << 0) |
#define MEQ2_START(x) ((x) << 8) |
#define VGT_VTX_VECT_EJECT_REG 0x88B0 |
#define VGT_CACHE_INVALIDATION 0x88C4 |
#define CACHE_INVALIDATION(x) ((x) << 0) |
#define VC_ONLY 0 |
#define TC_ONLY 1 |
#define VC_AND_TC 2 |
#define AUTO_INVLD_EN(x) ((x) << 6) |
#define NO_AUTO 0 |
#define ES_AUTO 1 |
#define GS_AUTO 2 |
#define ES_AND_GS_AUTO 3 |
#define VGT_GS_VERTEX_REUSE 0x88D4 |
#define CC_GC_SHADER_ARRAY_CONFIG 0x89bc |
#define INACTIVE_CUS_MASK 0xFFFF0000 |
#define INACTIVE_CUS_SHIFT 16 |
#define GC_USER_SHADER_ARRAY_CONFIG 0x89c0 |
#define PA_CL_ENHANCE 0x8A14 |
#define CLIP_VTX_REORDER_ENA (1 << 0) |
#define NUM_CLIP_SEQ(x) ((x) << 1) |
#define PA_SC_FORCE_EOV_MAX_CNTS 0x8B24 |
#define FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0) |
#define FORCE_EOV_MAX_REZ_CNT(x) ((x) << 16) |
#define PA_SC_FIFO_SIZE 0x8BCC |
#define SC_FRONTEND_PRIM_FIFO_SIZE(x) ((x) << 0) |
#define SC_BACKEND_PRIM_FIFO_SIZE(x) ((x) << 6) |
#define SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 15) |
#define SC_EARLYZ_TILE_FIFO_SIZE(x) ((x) << 23) |
#define PA_SC_ENHANCE 0x8BF0 |
#define ENABLE_PA_SC_OUT_OF_ORDER (1 << 0) |
#define DISABLE_PA_SC_GUIDANCE (1 << 13) |
#define SQ_CONFIG 0x8C00 |
#define SH_MEM_BASES 0x8C28 |
/* if PTR32, these are the bases for scratch and lds */ |
#define PRIVATE_BASE(x) ((x) << 0) /* scratch */ |
#define SHARED_BASE(x) ((x) << 16) /* LDS */ |
#define SH_MEM_APE1_BASE 0x8C2C |
/* if PTR32, this is the base location of GPUVM */ |
#define SH_MEM_APE1_LIMIT 0x8C30 |
/* if PTR32, this is the upper limit of GPUVM */ |
#define SH_MEM_CONFIG 0x8C34 |
#define PTR32 (1 << 0) |
#define ALIGNMENT_MODE(x) ((x) << 2) |
#define SH_MEM_ALIGNMENT_MODE_DWORD 0 |
#define SH_MEM_ALIGNMENT_MODE_DWORD_STRICT 1 |
#define SH_MEM_ALIGNMENT_MODE_STRICT 2 |
#define SH_MEM_ALIGNMENT_MODE_UNALIGNED 3 |
#define DEFAULT_MTYPE(x) ((x) << 4) |
#define APE1_MTYPE(x) ((x) << 7) |
#define SX_DEBUG_1 0x9060 |
#define SPI_CONFIG_CNTL 0x9100 |
#define SPI_CONFIG_CNTL_1 0x913C |
#define VTX_DONE_DELAY(x) ((x) << 0) |
#define INTERP_ONE_PRIM_PER_ROW (1 << 4) |
#define TA_CNTL_AUX 0x9508 |
#define DB_DEBUG 0x9830 |
#define DB_DEBUG2 0x9834 |
#define DB_DEBUG3 0x9838 |
#define CC_RB_BACKEND_DISABLE 0x98F4 |
#define BACKEND_DISABLE(x) ((x) << 16) |
#define GB_ADDR_CONFIG 0x98F8 |
#define NUM_PIPES(x) ((x) << 0) |
#define NUM_PIPES_MASK 0x00000007 |
#define NUM_PIPES_SHIFT 0 |
#define PIPE_INTERLEAVE_SIZE(x) ((x) << 4) |
#define PIPE_INTERLEAVE_SIZE_MASK 0x00000070 |
#define PIPE_INTERLEAVE_SIZE_SHIFT 4 |
#define NUM_SHADER_ENGINES(x) ((x) << 12) |
#define NUM_SHADER_ENGINES_MASK 0x00003000 |
#define NUM_SHADER_ENGINES_SHIFT 12 |
#define SHADER_ENGINE_TILE_SIZE(x) ((x) << 16) |
#define SHADER_ENGINE_TILE_SIZE_MASK 0x00070000 |
#define SHADER_ENGINE_TILE_SIZE_SHIFT 16 |
#define ROW_SIZE(x) ((x) << 28) |
#define ROW_SIZE_MASK 0x30000000 |
#define ROW_SIZE_SHIFT 28 |
#define GB_TILE_MODE0 0x9910 |
# define ARRAY_MODE(x) ((x) << 2) |
# define ARRAY_LINEAR_GENERAL 0 |
# define ARRAY_LINEAR_ALIGNED 1 |
# define ARRAY_1D_TILED_THIN1 2 |
# define ARRAY_2D_TILED_THIN1 4 |
# define ARRAY_PRT_TILED_THIN1 5 |
# define ARRAY_PRT_2D_TILED_THIN1 6 |
# define PIPE_CONFIG(x) ((x) << 6) |
# define ADDR_SURF_P2 0 |
# define ADDR_SURF_P4_8x16 4 |
# define ADDR_SURF_P4_16x16 5 |
# define ADDR_SURF_P4_16x32 6 |
# define ADDR_SURF_P4_32x32 7 |
# define ADDR_SURF_P8_16x16_8x16 8 |
# define ADDR_SURF_P8_16x32_8x16 9 |
# define ADDR_SURF_P8_32x32_8x16 10 |
# define ADDR_SURF_P8_16x32_16x16 11 |
# 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 |
# define ADDR_SURF_TILE_SPLIT_256B 2 |
# define ADDR_SURF_TILE_SPLIT_512B 3 |
# define ADDR_SURF_TILE_SPLIT_1KB 4 |
# define ADDR_SURF_TILE_SPLIT_2KB 5 |
# define ADDR_SURF_TILE_SPLIT_4KB 6 |
# define MICRO_TILE_MODE_NEW(x) ((x) << 22) |
# define ADDR_SURF_DISPLAY_MICRO_TILING 0 |
# define ADDR_SURF_THIN_MICRO_TILING 1 |
# define ADDR_SURF_DEPTH_MICRO_TILING 2 |
# define ADDR_SURF_ROTATED_MICRO_TILING 3 |
# define SAMPLE_SPLIT(x) ((x) << 25) |
# define ADDR_SURF_SAMPLE_SPLIT_1 0 |
# define ADDR_SURF_SAMPLE_SPLIT_2 1 |
# define ADDR_SURF_SAMPLE_SPLIT_4 2 |
# define ADDR_SURF_SAMPLE_SPLIT_8 3 |
#define GB_MACROTILE_MODE0 0x9990 |
# define BANK_WIDTH(x) ((x) << 0) |
# define ADDR_SURF_BANK_WIDTH_1 0 |
# define ADDR_SURF_BANK_WIDTH_2 1 |
# define ADDR_SURF_BANK_WIDTH_4 2 |
# define ADDR_SURF_BANK_WIDTH_8 3 |
# define BANK_HEIGHT(x) ((x) << 2) |
# define ADDR_SURF_BANK_HEIGHT_1 0 |
# define ADDR_SURF_BANK_HEIGHT_2 1 |
# define ADDR_SURF_BANK_HEIGHT_4 2 |
# define ADDR_SURF_BANK_HEIGHT_8 3 |
# define MACRO_TILE_ASPECT(x) ((x) << 4) |
# define ADDR_SURF_MACRO_ASPECT_1 0 |
# define ADDR_SURF_MACRO_ASPECT_2 1 |
# define ADDR_SURF_MACRO_ASPECT_4 2 |
# define ADDR_SURF_MACRO_ASPECT_8 3 |
# define NUM_BANKS(x) ((x) << 6) |
# define ADDR_SURF_2_BANK 0 |
# define ADDR_SURF_4_BANK 1 |
# define ADDR_SURF_8_BANK 2 |
# define ADDR_SURF_16_BANK 3 |
#define CB_HW_CONTROL 0x9A10 |
#define GC_USER_RB_BACKEND_DISABLE 0x9B7C |
#define BACKEND_DISABLE_MASK 0x00FF0000 |
#define BACKEND_DISABLE_SHIFT 16 |
#define TCP_CHAN_STEER_LO 0xac0c |
#define TCP_CHAN_STEER_HI 0xac10 |
#define TC_CFG_L1_LOAD_POLICY0 0xAC68 |
#define TC_CFG_L1_LOAD_POLICY1 0xAC6C |
#define TC_CFG_L1_STORE_POLICY 0xAC70 |
#define TC_CFG_L2_LOAD_POLICY0 0xAC74 |
#define TC_CFG_L2_LOAD_POLICY1 0xAC78 |
#define TC_CFG_L2_STORE_POLICY0 0xAC7C |
#define TC_CFG_L2_STORE_POLICY1 0xAC80 |
#define TC_CFG_L2_ATOMIC_POLICY 0xAC84 |
#define TC_CFG_L1_VOLATILE 0xAC88 |
#define TC_CFG_L2_VOLATILE 0xAC8C |
#define CP_RB0_BASE 0xC100 |
#define CP_RB0_CNTL 0xC104 |
#define RB_BUFSZ(x) ((x) << 0) |
#define RB_BLKSZ(x) ((x) << 8) |
#define BUF_SWAP_32BIT (2 << 16) |
#define RB_NO_UPDATE (1 << 27) |
#define RB_RPTR_WR_ENA (1 << 31) |
#define CP_RB0_RPTR_ADDR 0xC10C |
#define RB_RPTR_SWAP_32BIT (2 << 0) |
#define CP_RB0_RPTR_ADDR_HI 0xC110 |
#define CP_RB0_WPTR 0xC114 |
#define CP_DEVICE_ID 0xC12C |
#define CP_ENDIAN_SWAP 0xC140 |
#define CP_RB_VMID 0xC144 |
#define CP_PFP_UCODE_ADDR 0xC150 |
#define CP_PFP_UCODE_DATA 0xC154 |
#define CP_ME_RAM_RADDR 0xC158 |
#define CP_ME_RAM_WADDR 0xC15C |
#define CP_ME_RAM_DATA 0xC160 |
#define CP_CE_UCODE_ADDR 0xC168 |
#define CP_CE_UCODE_DATA 0xC16C |
#define CP_MEC_ME1_UCODE_ADDR 0xC170 |
#define CP_MEC_ME1_UCODE_DATA 0xC174 |
#define CP_MEC_ME2_UCODE_ADDR 0xC178 |
#define CP_MEC_ME2_UCODE_DATA 0xC17C |
#define CP_INT_CNTL_RING0 0xC1A8 |
# define CNTX_BUSY_INT_ENABLE (1 << 19) |
# define CNTX_EMPTY_INT_ENABLE (1 << 20) |
# define PRIV_INSTR_INT_ENABLE (1 << 22) |
# define PRIV_REG_INT_ENABLE (1 << 23) |
# define TIME_STAMP_INT_ENABLE (1 << 26) |
# define CP_RINGID2_INT_ENABLE (1 << 29) |
# define CP_RINGID1_INT_ENABLE (1 << 30) |
# define CP_RINGID0_INT_ENABLE (1 << 31) |
#define CP_INT_STATUS_RING0 0xC1B4 |
# define PRIV_INSTR_INT_STAT (1 << 22) |
# define PRIV_REG_INT_STAT (1 << 23) |
# define TIME_STAMP_INT_STAT (1 << 26) |
# define CP_RINGID2_INT_STAT (1 << 29) |
# define CP_RINGID1_INT_STAT (1 << 30) |
# define CP_RINGID0_INT_STAT (1 << 31) |
#define CP_MEM_SLP_CNTL 0xC1E4 |
# define CP_MEM_LS_EN (1 << 0) |
#define CP_CPF_DEBUG 0xC200 |
#define CP_PQ_WPTR_POLL_CNTL 0xC20C |
#define WPTR_POLL_EN (1 << 31) |
#define CP_ME1_PIPE0_INT_CNTL 0xC214 |
#define CP_ME1_PIPE1_INT_CNTL 0xC218 |
#define CP_ME1_PIPE2_INT_CNTL 0xC21C |
#define CP_ME1_PIPE3_INT_CNTL 0xC220 |
#define CP_ME2_PIPE0_INT_CNTL 0xC224 |
#define CP_ME2_PIPE1_INT_CNTL 0xC228 |
#define CP_ME2_PIPE2_INT_CNTL 0xC22C |
#define CP_ME2_PIPE3_INT_CNTL 0xC230 |
# define DEQUEUE_REQUEST_INT_ENABLE (1 << 13) |
# define WRM_POLL_TIMEOUT_INT_ENABLE (1 << 17) |
# define PRIV_REG_INT_ENABLE (1 << 23) |
# define TIME_STAMP_INT_ENABLE (1 << 26) |
# define GENERIC2_INT_ENABLE (1 << 29) |
# define GENERIC1_INT_ENABLE (1 << 30) |
# define GENERIC0_INT_ENABLE (1 << 31) |
#define CP_ME1_PIPE0_INT_STATUS 0xC214 |
#define CP_ME1_PIPE1_INT_STATUS 0xC218 |
#define CP_ME1_PIPE2_INT_STATUS 0xC21C |
#define CP_ME1_PIPE3_INT_STATUS 0xC220 |
#define CP_ME2_PIPE0_INT_STATUS 0xC224 |
#define CP_ME2_PIPE1_INT_STATUS 0xC228 |
#define CP_ME2_PIPE2_INT_STATUS 0xC22C |
#define CP_ME2_PIPE3_INT_STATUS 0xC230 |
# define DEQUEUE_REQUEST_INT_STATUS (1 << 13) |
# define WRM_POLL_TIMEOUT_INT_STATUS (1 << 17) |
# define PRIV_REG_INT_STATUS (1 << 23) |
# define TIME_STAMP_INT_STATUS (1 << 26) |
# define GENERIC2_INT_STATUS (1 << 29) |
# define GENERIC1_INT_STATUS (1 << 30) |
# define GENERIC0_INT_STATUS (1 << 31) |
#define CP_MAX_CONTEXT 0xC2B8 |
#define CP_RB0_BASE_HI 0xC2C4 |
#define RLC_CNTL 0xC300 |
# define RLC_ENABLE (1 << 0) |
#define RLC_MC_CNTL 0xC30C |
#define RLC_MEM_SLP_CNTL 0xC318 |
# define RLC_MEM_LS_EN (1 << 0) |
#define RLC_LB_CNTR_MAX 0xC348 |
#define RLC_LB_CNTL 0xC364 |
# define LOAD_BALANCE_ENABLE (1 << 0) |
#define RLC_LB_CNTR_INIT 0xC36C |
#define RLC_SAVE_AND_RESTORE_BASE 0xC374 |
#define RLC_DRIVER_DMA_STATUS 0xC378 /* dGPU */ |
#define RLC_CP_TABLE_RESTORE 0xC378 /* APU */ |
#define RLC_PG_DELAY_2 0xC37C |
#define RLC_GPM_UCODE_ADDR 0xC388 |
#define RLC_GPM_UCODE_DATA 0xC38C |
#define RLC_GPU_CLOCK_COUNT_LSB 0xC390 |
#define RLC_GPU_CLOCK_COUNT_MSB 0xC394 |
#define RLC_CAPTURE_GPU_CLOCK_COUNT 0xC398 |
#define RLC_UCODE_CNTL 0xC39C |
#define RLC_GPM_STAT 0xC400 |
# define RLC_GPM_BUSY (1 << 0) |
# define GFX_POWER_STATUS (1 << 1) |
# define GFX_CLOCK_STATUS (1 << 2) |
#define RLC_PG_CNTL 0xC40C |
# define GFX_PG_ENABLE (1 << 0) |
# define GFX_PG_SRC (1 << 1) |
# define DYN_PER_CU_PG_ENABLE (1 << 2) |
# define STATIC_PER_CU_PG_ENABLE (1 << 3) |
# define DISABLE_GDS_PG (1 << 13) |
# define DISABLE_CP_PG (1 << 15) |
# define SMU_CLK_SLOWDOWN_ON_PU_ENABLE (1 << 17) |
# define SMU_CLK_SLOWDOWN_ON_PD_ENABLE (1 << 18) |
#define RLC_CGTT_MGCG_OVERRIDE 0xC420 |
#define RLC_CGCG_CGLS_CTRL 0xC424 |
# define CGCG_EN (1 << 0) |
# define CGLS_EN (1 << 1) |
#define RLC_PG_DELAY 0xC434 |
#define RLC_LB_INIT_CU_MASK 0xC43C |
#define RLC_LB_PARAMS 0xC444 |
#define RLC_PG_AO_CU_MASK 0xC44C |
#define RLC_MAX_PG_CU 0xC450 |
# define MAX_PU_CU(x) ((x) << 0) |
# define MAX_PU_CU_MASK (0xff << 0) |
#define RLC_AUTO_PG_CTRL 0xC454 |
# define AUTO_PG_EN (1 << 0) |
# define GRBM_REG_SGIT(x) ((x) << 3) |
# define GRBM_REG_SGIT_MASK (0xffff << 3) |
#define RLC_SERDES_WR_CU_MASTER_MASK 0xC474 |
#define RLC_SERDES_WR_NONCU_MASTER_MASK 0xC478 |
#define RLC_SERDES_WR_CTRL 0xC47C |
#define BPM_ADDR(x) ((x) << 0) |
#define BPM_ADDR_MASK (0xff << 0) |
#define CGLS_ENABLE (1 << 16) |
#define CGCG_OVERRIDE_0 (1 << 20) |
#define MGCG_OVERRIDE_0 (1 << 22) |
#define MGCG_OVERRIDE_1 (1 << 23) |
#define RLC_SERDES_CU_MASTER_BUSY 0xC484 |
#define RLC_SERDES_NONCU_MASTER_BUSY 0xC488 |
# define SE_MASTER_BUSY_MASK 0x0000ffff |
# define GC_MASTER_BUSY (1 << 16) |
# define TC0_MASTER_BUSY (1 << 17) |
# define TC1_MASTER_BUSY (1 << 18) |
#define RLC_GPM_SCRATCH_ADDR 0xC4B0 |
#define RLC_GPM_SCRATCH_DATA 0xC4B4 |
#define RLC_GPR_REG2 0xC4E8 |
#define REQ 0x00000001 |
#define MESSAGE(x) ((x) << 1) |
#define MESSAGE_MASK 0x0000001e |
#define MSG_ENTER_RLC_SAFE_MODE 1 |
#define MSG_EXIT_RLC_SAFE_MODE 0 |
#define CP_HPD_EOP_BASE_ADDR 0xC904 |
#define CP_HPD_EOP_BASE_ADDR_HI 0xC908 |
#define CP_HPD_EOP_VMID 0xC90C |
#define CP_HPD_EOP_CONTROL 0xC910 |
#define EOP_SIZE(x) ((x) << 0) |
#define EOP_SIZE_MASK (0x3f << 0) |
#define CP_MQD_BASE_ADDR 0xC914 |
#define CP_MQD_BASE_ADDR_HI 0xC918 |
#define CP_HQD_ACTIVE 0xC91C |
#define CP_HQD_VMID 0xC920 |
#define CP_HQD_PQ_BASE 0xC934 |
#define CP_HQD_PQ_BASE_HI 0xC938 |
#define CP_HQD_PQ_RPTR 0xC93C |
#define CP_HQD_PQ_RPTR_REPORT_ADDR 0xC940 |
#define CP_HQD_PQ_RPTR_REPORT_ADDR_HI 0xC944 |
#define CP_HQD_PQ_WPTR_POLL_ADDR 0xC948 |
#define CP_HQD_PQ_WPTR_POLL_ADDR_HI 0xC94C |
#define CP_HQD_PQ_DOORBELL_CONTROL 0xC950 |
#define DOORBELL_OFFSET(x) ((x) << 2) |
#define DOORBELL_OFFSET_MASK (0x1fffff << 2) |
#define DOORBELL_SOURCE (1 << 28) |
#define DOORBELL_SCHD_HIT (1 << 29) |
#define DOORBELL_EN (1 << 30) |
#define DOORBELL_HIT (1 << 31) |
#define CP_HQD_PQ_WPTR 0xC954 |
#define CP_HQD_PQ_CONTROL 0xC958 |
#define QUEUE_SIZE(x) ((x) << 0) |
#define QUEUE_SIZE_MASK (0x3f << 0) |
#define RPTR_BLOCK_SIZE(x) ((x) << 8) |
#define RPTR_BLOCK_SIZE_MASK (0x3f << 8) |
#define PQ_VOLATILE (1 << 26) |
#define NO_UPDATE_RPTR (1 << 27) |
#define UNORD_DISPATCH (1 << 28) |
#define ROQ_PQ_IB_FLIP (1 << 29) |
#define PRIV_STATE (1 << 30) |
#define KMD_QUEUE (1 << 31) |
#define CP_HQD_DEQUEUE_REQUEST 0xC974 |
#define CP_MQD_CONTROL 0xC99C |
#define MQD_VMID(x) ((x) << 0) |
#define MQD_VMID_MASK (0xf << 0) |
#define DB_RENDER_CONTROL 0x28000 |
#define PA_SC_RASTER_CONFIG 0x28350 |
# define RASTER_CONFIG_RB_MAP_0 0 |
# 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) |
# define SAMPLE_STREAMOUTSTATS2 (2 << 0) |
# define SAMPLE_STREAMOUTSTATS3 (3 << 0) |
# define CACHE_FLUSH_TS (4 << 0) |
# define CACHE_FLUSH (6 << 0) |
# define CS_PARTIAL_FLUSH (7 << 0) |
# define VGT_STREAMOUT_RESET (10 << 0) |
# define END_OF_PIPE_INCR_DE (11 << 0) |
# define END_OF_PIPE_IB_END (12 << 0) |
# define RST_PIX_CNT (13 << 0) |
# define VS_PARTIAL_FLUSH (15 << 0) |
# define PS_PARTIAL_FLUSH (16 << 0) |
# define CACHE_FLUSH_AND_INV_TS_EVENT (20 << 0) |
# define ZPASS_DONE (21 << 0) |
# define CACHE_FLUSH_AND_INV_EVENT (22 << 0) |
# define PERFCOUNTER_START (23 << 0) |
# define PERFCOUNTER_STOP (24 << 0) |
# define PIPELINESTAT_START (25 << 0) |
# define PIPELINESTAT_STOP (26 << 0) |
# define PERFCOUNTER_SAMPLE (27 << 0) |
# define SAMPLE_PIPELINESTAT (30 << 0) |
# define SO_VGT_STREAMOUT_FLUSH (31 << 0) |
# define SAMPLE_STREAMOUTSTATS (32 << 0) |
# define RESET_VTX_CNT (33 << 0) |
# define VGT_FLUSH (36 << 0) |
# define BOTTOM_OF_PIPE_TS (40 << 0) |
# define DB_CACHE_FLUSH_AND_INV (42 << 0) |
# define FLUSH_AND_INV_DB_DATA_TS (43 << 0) |
# define FLUSH_AND_INV_DB_META (44 << 0) |
# define FLUSH_AND_INV_CB_DATA_TS (45 << 0) |
# define FLUSH_AND_INV_CB_META (46 << 0) |
# define CS_DONE (47 << 0) |
# define PS_DONE (48 << 0) |
# define FLUSH_AND_INV_CB_PIXEL_DATA (49 << 0) |
# define THREAD_TRACE_START (51 << 0) |
# define THREAD_TRACE_STOP (52 << 0) |
# define THREAD_TRACE_FLUSH (54 << 0) |
# define THREAD_TRACE_FINISH (55 << 0) |
# define PIXEL_PIPE_STAT_CONTROL (56 << 0) |
# define PIXEL_PIPE_STAT_DUMP (57 << 0) |
# define PIXEL_PIPE_STAT_RESET (58 << 0) |
#define SCRATCH_REG0 0x30100 |
#define SCRATCH_REG1 0x30104 |
#define SCRATCH_REG2 0x30108 |
#define SCRATCH_REG3 0x3010C |
#define SCRATCH_REG4 0x30110 |
#define SCRATCH_REG5 0x30114 |
#define SCRATCH_REG6 0x30118 |
#define SCRATCH_REG7 0x3011C |
#define SCRATCH_UMSK 0x30140 |
#define SCRATCH_ADDR 0x30144 |
#define CP_SEM_WAIT_TIMER 0x301BC |
#define CP_SEM_INCOMPLETE_TIMER_CNTL 0x301C8 |
#define CP_WAIT_REG_MEM_TIMEOUT 0x301D0 |
#define GRBM_GFX_INDEX 0x30800 |
#define INSTANCE_INDEX(x) ((x) << 0) |
#define SH_INDEX(x) ((x) << 8) |
#define SE_INDEX(x) ((x) << 16) |
#define SH_BROADCAST_WRITES (1 << 29) |
#define INSTANCE_BROADCAST_WRITES (1 << 30) |
#define SE_BROADCAST_WRITES (1 << 31) |
#define VGT_ESGS_RING_SIZE 0x30900 |
#define VGT_GSVS_RING_SIZE 0x30904 |
#define VGT_PRIMITIVE_TYPE 0x30908 |
#define VGT_INDEX_TYPE 0x3090C |
#define VGT_NUM_INDICES 0x30930 |
#define VGT_NUM_INSTANCES 0x30934 |
#define VGT_TF_RING_SIZE 0x30938 |
#define VGT_HS_OFFCHIP_PARAM 0x3093C |
#define VGT_TF_MEMORY_BASE 0x30940 |
#define PA_SU_LINE_STIPPLE_VALUE 0x30a00 |
#define PA_SC_LINE_STIPPLE_STATE 0x30a04 |
#define SQC_CACHES 0x30d20 |
#define CP_PERFMON_CNTL 0x36020 |
#define CGTS_SM_CTRL_REG 0x3c000 |
#define SM_MODE(x) ((x) << 17) |
#define SM_MODE_MASK (0x7 << 17) |
#define SM_MODE_ENABLE (1 << 20) |
#define CGTS_OVERRIDE (1 << 21) |
#define CGTS_LS_OVERRIDE (1 << 22) |
#define ON_MONITOR_ADD_EN (1 << 23) |
#define ON_MONITOR_ADD(x) ((x) << 24) |
#define ON_MONITOR_ADD_MASK (0xff << 24) |
#define CGTS_TCC_DISABLE 0x3c00c |
#define CGTS_USER_TCC_DISABLE 0x3c010 |
#define TCC_DISABLE_MASK 0xFFFF0000 |
#define TCC_DISABLE_SHIFT 16 |
#define CB_CGTT_SCLK_CTRL 0x3c2a0 |
/* |
* PM4 |
*/ |
#define PACKET_TYPE0 0 |
#define PACKET_TYPE1 1 |
#define PACKET_TYPE2 2 |
#define PACKET_TYPE3 3 |
#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3) |
#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF) |
#define CP_PACKET0_GET_REG(h) (((h) & 0xFFFF) << 2) |
#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) |
#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \ |
(((reg) >> 2) & 0xFFFF) | \ |
((n) & 0x3FFF) << 16) |
#define CP_PACKET2 0x80000000 |
#define PACKET2_PAD_SHIFT 0 |
#define PACKET2_PAD_MASK (0x3fffffff << 0) |
#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) |
#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ |
(((op) & 0xFF) << 8) | \ |
((n) & 0x3FFF) << 16) |
#define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1) |
/* Packet 3 types */ |
#define PACKET3_NOP 0x10 |
#define PACKET3_SET_BASE 0x11 |
#define PACKET3_BASE_INDEX(x) ((x) << 0) |
#define CE_PARTITION_BASE 3 |
#define PACKET3_CLEAR_STATE 0x12 |
#define PACKET3_INDEX_BUFFER_SIZE 0x13 |
#define PACKET3_DISPATCH_DIRECT 0x15 |
#define PACKET3_DISPATCH_INDIRECT 0x16 |
#define PACKET3_ATOMIC_GDS 0x1D |
#define PACKET3_ATOMIC_MEM 0x1E |
#define PACKET3_OCCLUSION_QUERY 0x1F |
#define PACKET3_SET_PREDICATION 0x20 |
#define PACKET3_REG_RMW 0x21 |
#define PACKET3_COND_EXEC 0x22 |
#define PACKET3_PRED_EXEC 0x23 |
#define PACKET3_DRAW_INDIRECT 0x24 |
#define PACKET3_DRAW_INDEX_INDIRECT 0x25 |
#define PACKET3_INDEX_BASE 0x26 |
#define PACKET3_DRAW_INDEX_2 0x27 |
#define PACKET3_CONTEXT_CONTROL 0x28 |
#define PACKET3_INDEX_TYPE 0x2A |
#define PACKET3_DRAW_INDIRECT_MULTI 0x2C |
#define PACKET3_DRAW_INDEX_AUTO 0x2D |
#define PACKET3_NUM_INSTANCES 0x2F |
#define PACKET3_DRAW_INDEX_MULTI_AUTO 0x30 |
#define PACKET3_INDIRECT_BUFFER_CONST 0x33 |
#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34 |
#define PACKET3_DRAW_INDEX_OFFSET_2 0x35 |
#define PACKET3_DRAW_PREAMBLE 0x36 |
#define PACKET3_WRITE_DATA 0x37 |
#define WRITE_DATA_DST_SEL(x) ((x) << 8) |
/* 0 - register |
* 1 - memory (sync - via GRBM) |
* 2 - gl2 |
* 3 - gds |
* 4 - reserved |
* 5 - memory (async - direct) |
*/ |
#define WR_ONE_ADDR (1 << 16) |
#define WR_CONFIRM (1 << 20) |
#define WRITE_DATA_CACHE_POLICY(x) ((x) << 25) |
/* 0 - LRU |
* 1 - Stream |
*/ |
#define WRITE_DATA_ENGINE_SEL(x) ((x) << 30) |
/* 0 - me |
* 1 - pfp |
* 2 - ce |
*/ |
#define PACKET3_DRAW_INDEX_INDIRECT_MULTI 0x38 |
#define PACKET3_MEM_SEMAPHORE 0x39 |
# define PACKET3_SEM_USE_MAILBOX (0x1 << 16) |
# define PACKET3_SEM_SEL_SIGNAL_TYPE (0x1 << 20) /* 0 = increment, 1 = write 1 */ |
# define PACKET3_SEM_CLIENT_CODE ((x) << 24) /* 0 = CP, 1 = CB, 2 = DB */ |
# define PACKET3_SEM_SEL_SIGNAL (0x6 << 29) |
# define PACKET3_SEM_SEL_WAIT (0x7 << 29) |
#define PACKET3_COPY_DW 0x3B |
#define PACKET3_WAIT_REG_MEM 0x3C |
#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) |
/* 0 - always |
* 1 - < |
* 2 - <= |
* 3 - == |
* 4 - != |
* 5 - >= |
* 6 - > |
*/ |
#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) |
/* 0 - reg |
* 1 - mem |
*/ |
#define WAIT_REG_MEM_OPERATION(x) ((x) << 6) |
/* 0 - wait_reg_mem |
* 1 - wr_wait_wr_reg |
*/ |
#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) |
/* 0 - me |
* 1 - pfp |
*/ |
#define PACKET3_INDIRECT_BUFFER 0x3F |
#define INDIRECT_BUFFER_TCL2_VOLATILE (1 << 22) |
#define INDIRECT_BUFFER_VALID (1 << 23) |
#define INDIRECT_BUFFER_CACHE_POLICY(x) ((x) << 28) |
/* 0 - LRU |
* 1 - Stream |
* 2 - Bypass |
*/ |
#define PACKET3_COPY_DATA 0x40 |
#define PACKET3_PFP_SYNC_ME 0x42 |
#define PACKET3_SURFACE_SYNC 0x43 |
# define PACKET3_DEST_BASE_0_ENA (1 << 0) |
# define PACKET3_DEST_BASE_1_ENA (1 << 1) |
# define PACKET3_CB0_DEST_BASE_ENA (1 << 6) |
# define PACKET3_CB1_DEST_BASE_ENA (1 << 7) |
# define PACKET3_CB2_DEST_BASE_ENA (1 << 8) |
# define PACKET3_CB3_DEST_BASE_ENA (1 << 9) |
# define PACKET3_CB4_DEST_BASE_ENA (1 << 10) |
# define PACKET3_CB5_DEST_BASE_ENA (1 << 11) |
# define PACKET3_CB6_DEST_BASE_ENA (1 << 12) |
# define PACKET3_CB7_DEST_BASE_ENA (1 << 13) |
# define PACKET3_DB_DEST_BASE_ENA (1 << 14) |
# define PACKET3_TCL1_VOL_ACTION_ENA (1 << 15) |
# define PACKET3_TC_VOL_ACTION_ENA (1 << 16) /* L2 */ |
# define PACKET3_TC_WB_ACTION_ENA (1 << 18) /* L2 */ |
# define PACKET3_DEST_BASE_2_ENA (1 << 19) |
# define PACKET3_DEST_BASE_3_ENA (1 << 21) |
# define PACKET3_TCL1_ACTION_ENA (1 << 22) |
# define PACKET3_TC_ACTION_ENA (1 << 23) /* L2 */ |
# define PACKET3_CB_ACTION_ENA (1 << 25) |
# define PACKET3_DB_ACTION_ENA (1 << 26) |
# define PACKET3_SH_KCACHE_ACTION_ENA (1 << 27) |
# define PACKET3_SH_KCACHE_VOL_ACTION_ENA (1 << 28) |
# define PACKET3_SH_ICACHE_ACTION_ENA (1 << 29) |
#define PACKET3_COND_WRITE 0x45 |
#define PACKET3_EVENT_WRITE 0x46 |
#define EVENT_TYPE(x) ((x) << 0) |
#define EVENT_INDEX(x) ((x) << 8) |
/* 0 - any non-TS event |
* 1 - ZPASS_DONE, PIXEL_PIPE_STAT_* |
* 2 - SAMPLE_PIPELINESTAT |
* 3 - SAMPLE_STREAMOUTSTAT* |
* 4 - *S_PARTIAL_FLUSH |
* 5 - EOP events |
* 6 - EOS events |
*/ |
#define PACKET3_EVENT_WRITE_EOP 0x47 |
#define EOP_TCL1_VOL_ACTION_EN (1 << 12) |
#define EOP_TC_VOL_ACTION_EN (1 << 13) /* L2 */ |
#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 DATA_SEL(x) ((x) << 29) |
/* 0 - discard |
* 1 - send low 32bit data |
* 2 - send 64bit data |
* 3 - send 64bit GPU counter value |
* 4 - send 64bit sys counter value |
*/ |
#define INT_SEL(x) ((x) << 24) |
/* 0 - none |
* 1 - interrupt only (DATA_SEL = 0) |
* 2 - interrupt when data write is confirmed |
*/ |
#define DST_SEL(x) ((x) << 16) |
/* 0 - MC |
* 1 - TC/L2 |
*/ |
#define PACKET3_EVENT_WRITE_EOS 0x48 |
#define PACKET3_RELEASE_MEM 0x49 |
#define PACKET3_PREAMBLE_CNTL 0x4A |
# 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 |
#define PACKET3_LOAD_SH_REG 0x5F |
#define PACKET3_LOAD_CONFIG_REG 0x60 |
#define PACKET3_LOAD_CONTEXT_REG 0x61 |
#define PACKET3_SET_CONFIG_REG 0x68 |
#define PACKET3_SET_CONFIG_REG_START 0x00008000 |
#define PACKET3_SET_CONFIG_REG_END 0x0000b000 |
#define PACKET3_SET_CONTEXT_REG 0x69 |
#define PACKET3_SET_CONTEXT_REG_START 0x00028000 |
#define PACKET3_SET_CONTEXT_REG_END 0x00029000 |
#define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73 |
#define PACKET3_SET_SH_REG 0x76 |
#define PACKET3_SET_SH_REG_START 0x0000b000 |
#define PACKET3_SET_SH_REG_END 0x0000c000 |
#define PACKET3_SET_SH_REG_OFFSET 0x77 |
#define PACKET3_SET_QUEUE_REG 0x78 |
#define PACKET3_SET_UCONFIG_REG 0x79 |
#define PACKET3_SET_UCONFIG_REG_START 0x00030000 |
#define PACKET3_SET_UCONFIG_REG_END 0x00031000 |
#define PACKET3_SCRATCH_RAM_WRITE 0x7D |
#define PACKET3_SCRATCH_RAM_READ 0x7E |
#define PACKET3_LOAD_CONST_RAM 0x80 |
#define PACKET3_WRITE_CONST_RAM 0x81 |
#define PACKET3_DUMP_CONST_RAM 0x83 |
#define PACKET3_INCREMENT_CE_COUNTER 0x84 |
#define PACKET3_INCREMENT_DE_COUNTER 0x85 |
#define PACKET3_WAIT_ON_CE_COUNTER 0x86 |
#define PACKET3_WAIT_ON_DE_COUNTER_DIFF 0x88 |
#define PACKET3_SWITCH_BUFFER 0x8B |
/* SDMA - first instance at 0xd000, second at 0xd800 */ |
#define SDMA0_REGISTER_OFFSET 0x0 /* not a register */ |
#define SDMA1_REGISTER_OFFSET 0x800 /* not a register */ |
#define SDMA0_UCODE_ADDR 0xD000 |
#define SDMA0_UCODE_DATA 0xD004 |
#define SDMA0_POWER_CNTL 0xD008 |
#define SDMA0_CLK_CTRL 0xD00C |
#define SDMA0_CNTL 0xD010 |
# define TRAP_ENABLE (1 << 0) |
# define SEM_INCOMPLETE_INT_ENABLE (1 << 1) |
# define SEM_WAIT_INT_ENABLE (1 << 2) |
# define DATA_SWAP_ENABLE (1 << 3) |
# define FENCE_SWAP_ENABLE (1 << 4) |
# define AUTO_CTXSW_ENABLE (1 << 18) |
# define CTXEMPTY_INT_ENABLE (1 << 28) |
#define SDMA0_TILING_CONFIG 0xD018 |
#define SDMA0_SEM_INCOMPLETE_TIMER_CNTL 0xD020 |
#define SDMA0_SEM_WAIT_FAIL_TIMER_CNTL 0xD024 |
#define SDMA0_STATUS_REG 0xd034 |
# define SDMA_IDLE (1 << 0) |
#define SDMA0_ME_CNTL 0xD048 |
# define SDMA_HALT (1 << 0) |
#define SDMA0_GFX_RB_CNTL 0xD200 |
# define SDMA_RB_ENABLE (1 << 0) |
# define SDMA_RB_SIZE(x) ((x) << 1) /* log2 */ |
# define SDMA_RB_SWAP_ENABLE (1 << 9) /* 8IN32 */ |
# define SDMA_RPTR_WRITEBACK_ENABLE (1 << 12) |
# define SDMA_RPTR_WRITEBACK_SWAP_ENABLE (1 << 13) /* 8IN32 */ |
# define SDMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */ |
#define SDMA0_GFX_RB_BASE 0xD204 |
#define SDMA0_GFX_RB_BASE_HI 0xD208 |
#define SDMA0_GFX_RB_RPTR 0xD20C |
#define SDMA0_GFX_RB_WPTR 0xD210 |
#define SDMA0_GFX_RB_RPTR_ADDR_HI 0xD220 |
#define SDMA0_GFX_RB_RPTR_ADDR_LO 0xD224 |
#define SDMA0_GFX_IB_CNTL 0xD228 |
# define SDMA_IB_ENABLE (1 << 0) |
# define SDMA_IB_SWAP_ENABLE (1 << 4) |
# define SDMA_SWITCH_INSIDE_IB (1 << 8) |
# define SDMA_CMD_VMID(x) ((x) << 16) |
#define SDMA0_GFX_VIRTUAL_ADDR 0xD29C |
#define SDMA0_GFX_APE1_CNTL 0xD2A0 |
#define SDMA_PACKET(op, sub_op, e) ((((e) & 0xFFFF) << 16) | \ |
(((sub_op) & 0xFF) << 8) | \ |
(((op) & 0xFF) << 0)) |
/* sDMA opcodes */ |
#define SDMA_OPCODE_NOP 0 |
#define SDMA_OPCODE_COPY 1 |
# define SDMA_COPY_SUB_OPCODE_LINEAR 0 |
# define SDMA_COPY_SUB_OPCODE_TILED 1 |
# define SDMA_COPY_SUB_OPCODE_SOA 3 |
# define SDMA_COPY_SUB_OPCODE_LINEAR_SUB_WINDOW 4 |
# define SDMA_COPY_SUB_OPCODE_TILED_SUB_WINDOW 5 |
# define SDMA_COPY_SUB_OPCODE_T2T_SUB_WINDOW 6 |
#define SDMA_OPCODE_WRITE 2 |
# define SDMA_WRITE_SUB_OPCODE_LINEAR 0 |
# define SDMA_WRTIE_SUB_OPCODE_TILED 1 |
#define SDMA_OPCODE_INDIRECT_BUFFER 4 |
#define SDMA_OPCODE_FENCE 5 |
#define SDMA_OPCODE_TRAP 6 |
#define SDMA_OPCODE_SEMAPHORE 7 |
# define SDMA_SEMAPHORE_EXTRA_O (1 << 13) |
/* 0 - increment |
* 1 - write 1 |
*/ |
# define SDMA_SEMAPHORE_EXTRA_S (1 << 14) |
/* 0 - wait |
* 1 - signal |
*/ |
# define SDMA_SEMAPHORE_EXTRA_M (1 << 15) |
/* mailbox */ |
#define SDMA_OPCODE_POLL_REG_MEM 8 |
# define SDMA_POLL_REG_MEM_EXTRA_OP(x) ((x) << 10) |
/* 0 - wait_reg_mem |
* 1 - wr_wait_wr_reg |
*/ |
# define SDMA_POLL_REG_MEM_EXTRA_FUNC(x) ((x) << 12) |
/* 0 - always |
* 1 - < |
* 2 - <= |
* 3 - == |
* 4 - != |
* 5 - >= |
* 6 - > |
*/ |
# define SDMA_POLL_REG_MEM_EXTRA_M (1 << 15) |
/* 0 = register |
* 1 = memory |
*/ |
#define SDMA_OPCODE_COND_EXEC 9 |
#define SDMA_OPCODE_CONSTANT_FILL 11 |
# define SDMA_CONSTANT_FILL_EXTRA_SIZE(x) ((x) << 14) |
/* 0 = byte fill |
* 2 = DW fill |
*/ |
#define SDMA_OPCODE_GENERATE_PTE_PDE 12 |
#define SDMA_OPCODE_TIMESTAMP 13 |
# define SDMA_TIMESTAMP_SUB_OPCODE_SET_LOCAL 0 |
# define SDMA_TIMESTAMP_SUB_OPCODE_GET_LOCAL 1 |
# define SDMA_TIMESTAMP_SUB_OPCODE_GET_GLOBAL 2 |
#define SDMA_OPCODE_SRBM_WRITE 14 |
# define SDMA_SRBM_WRITE_EXTRA_BYTE_ENABLE(x) ((x) << 12) |
/* byte mask */ |
/* UVD */ |
#define UVD_UDEC_ADDR_CONFIG 0xef4c |
#define UVD_UDEC_DB_ADDR_CONFIG 0xef50 |
#define UVD_UDEC_DBW_ADDR_CONFIG 0xef54 |
#define UVD_LMI_EXT40_ADDR 0xf498 |
#define UVD_LMI_ADDR_EXT 0xf594 |
#define UVD_VCPU_CACHE_OFFSET0 0xf608 |
#define UVD_VCPU_CACHE_SIZE0 0xf60c |
#define UVD_VCPU_CACHE_OFFSET1 0xf610 |
#define UVD_VCPU_CACHE_SIZE1 0xf614 |
#define UVD_VCPU_CACHE_OFFSET2 0xf618 |
#define UVD_VCPU_CACHE_SIZE2 0xf61c |
#define UVD_RBC_RB_RPTR 0xf690 |
#define UVD_RBC_RB_WPTR 0xf694 |
#define UVD_CGC_CTRL 0xF4B0 |
# define DCM (1 << 0) |
# define CG_DT(x) ((x) << 2) |
# define CG_DT_MASK (0xf << 2) |
# define CLK_OD(x) ((x) << 6) |
# define CLK_OD_MASK (0x1f << 6) |
/* UVD clocks */ |
#define CG_DCLK_CNTL 0xC050009C |
# define DCLK_DIVIDER_MASK 0x7f |
# define DCLK_DIR_CNTL_EN (1 << 8) |
#define CG_DCLK_STATUS 0xC05000A0 |
# define DCLK_STATUS (1 << 0) |
#define CG_VCLK_CNTL 0xC05000A4 |
#define CG_VCLK_STATUS 0xC05000A8 |
/* 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 |
/drivers/video/drm/radeon/clearstate_cayman.h |
---|
0,0 → 1,1081 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
static const u32 SECT_CONTEXT_def_1[] = |
{ |
0x00000000, // DB_RENDER_CONTROL |
0x00000000, // DB_COUNT_CONTROL |
0x00000000, // DB_DEPTH_VIEW |
0x00000000, // DB_RENDER_OVERRIDE |
0x00000000, // DB_RENDER_OVERRIDE2 |
0x00000000, // DB_HTILE_DATA_BASE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_STENCIL_CLEAR |
0x00000000, // DB_DEPTH_CLEAR |
0x00000000, // PA_SC_SCREEN_SCISSOR_TL |
0x40004000, // PA_SC_SCREEN_SCISSOR_BR |
0, // HOLE |
0x00000000, // DB_DEPTH_INFO |
0x00000000, // DB_Z_INFO |
0x00000000, // DB_STENCIL_INFO |
0x00000000, // DB_Z_READ_BASE |
0x00000000, // DB_STENCIL_READ_BASE |
0x00000000, // DB_Z_WRITE_BASE |
0x00000000, // DB_STENCIL_WRITE_BASE |
0x00000000, // DB_DEPTH_SIZE |
0x00000000, // DB_DEPTH_SLICE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_15 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_15 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_15 |
0x00000000, // PA_SC_WINDOW_OFFSET |
0x80000000, // PA_SC_WINDOW_SCISSOR_TL |
0x40004000, // PA_SC_WINDOW_SCISSOR_BR |
0x0000ffff, // PA_SC_CLIPRECT_RULE |
0x00000000, // PA_SC_CLIPRECT_0_TL |
0x40004000, // PA_SC_CLIPRECT_0_BR |
0x00000000, // PA_SC_CLIPRECT_1_TL |
0x40004000, // PA_SC_CLIPRECT_1_BR |
0x00000000, // PA_SC_CLIPRECT_2_TL |
0x40004000, // PA_SC_CLIPRECT_2_BR |
0x00000000, // PA_SC_CLIPRECT_3_TL |
0x40004000, // PA_SC_CLIPRECT_3_BR |
0xaa99aaaa, // PA_SC_EDGERULE |
0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET |
0xffffffff, // CB_TARGET_MASK |
0xffffffff, // CB_SHADER_MASK |
0x80000000, // PA_SC_GENERIC_SCISSOR_TL |
0x40004000, // PA_SC_GENERIC_SCISSOR_BR |
0x00000000, // COHER_DEST_BASE_0 |
0x00000000, // COHER_DEST_BASE_1 |
0x80000000, // PA_SC_VPORT_SCISSOR_0_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_0_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_1_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_1_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_2_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_2_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_3_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_3_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_4_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_4_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_5_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_5_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_6_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_6_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_7_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_7_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_8_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_8_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_9_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_9_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_10_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_10_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_11_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_11_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_12_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_12_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_13_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_13_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_14_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_14_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_15_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_15_BR |
0x00000000, // PA_SC_VPORT_ZMIN_0 |
0x3f800000, // PA_SC_VPORT_ZMAX_0 |
0x00000000, // PA_SC_VPORT_ZMIN_1 |
0x3f800000, // PA_SC_VPORT_ZMAX_1 |
0x00000000, // PA_SC_VPORT_ZMIN_2 |
0x3f800000, // PA_SC_VPORT_ZMAX_2 |
0x00000000, // PA_SC_VPORT_ZMIN_3 |
0x3f800000, // PA_SC_VPORT_ZMAX_3 |
0x00000000, // PA_SC_VPORT_ZMIN_4 |
0x3f800000, // PA_SC_VPORT_ZMAX_4 |
0x00000000, // PA_SC_VPORT_ZMIN_5 |
0x3f800000, // PA_SC_VPORT_ZMAX_5 |
0x00000000, // PA_SC_VPORT_ZMIN_6 |
0x3f800000, // PA_SC_VPORT_ZMAX_6 |
0x00000000, // PA_SC_VPORT_ZMIN_7 |
0x3f800000, // PA_SC_VPORT_ZMAX_7 |
0x00000000, // PA_SC_VPORT_ZMIN_8 |
0x3f800000, // PA_SC_VPORT_ZMAX_8 |
0x00000000, // PA_SC_VPORT_ZMIN_9 |
0x3f800000, // PA_SC_VPORT_ZMAX_9 |
0x00000000, // PA_SC_VPORT_ZMIN_10 |
0x3f800000, // PA_SC_VPORT_ZMAX_10 |
0x00000000, // PA_SC_VPORT_ZMIN_11 |
0x3f800000, // PA_SC_VPORT_ZMAX_11 |
0x00000000, // PA_SC_VPORT_ZMIN_12 |
0x3f800000, // PA_SC_VPORT_ZMAX_12 |
0x00000000, // PA_SC_VPORT_ZMIN_13 |
0x3f800000, // PA_SC_VPORT_ZMAX_13 |
0x00000000, // PA_SC_VPORT_ZMIN_14 |
0x3f800000, // PA_SC_VPORT_ZMAX_14 |
0x00000000, // PA_SC_VPORT_ZMIN_15 |
0x3f800000, // PA_SC_VPORT_ZMAX_15 |
0x00000000, // SX_MISC |
0x00000000, // SX_SURFACE_SYNC |
0x00000000, // SX_SCATTER_EXPORT_BASE |
0x00000000, // SX_SCATTER_EXPORT_SIZE |
0x00000000, // CP_PERFMON_CNTX_CNTL |
0x00000000, // CP_RINGID |
0x00000000, // CP_VMID |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_VTX_SEMANTIC_0 |
0x00000000, // SQ_VTX_SEMANTIC_1 |
0x00000000, // SQ_VTX_SEMANTIC_2 |
0x00000000, // SQ_VTX_SEMANTIC_3 |
0x00000000, // SQ_VTX_SEMANTIC_4 |
0x00000000, // SQ_VTX_SEMANTIC_5 |
0x00000000, // SQ_VTX_SEMANTIC_6 |
0x00000000, // SQ_VTX_SEMANTIC_7 |
0x00000000, // SQ_VTX_SEMANTIC_8 |
0x00000000, // SQ_VTX_SEMANTIC_9 |
0x00000000, // SQ_VTX_SEMANTIC_10 |
0x00000000, // SQ_VTX_SEMANTIC_11 |
0x00000000, // SQ_VTX_SEMANTIC_12 |
0x00000000, // SQ_VTX_SEMANTIC_13 |
0x00000000, // SQ_VTX_SEMANTIC_14 |
0x00000000, // SQ_VTX_SEMANTIC_15 |
0x00000000, // SQ_VTX_SEMANTIC_16 |
0x00000000, // SQ_VTX_SEMANTIC_17 |
0x00000000, // SQ_VTX_SEMANTIC_18 |
0x00000000, // SQ_VTX_SEMANTIC_19 |
0x00000000, // SQ_VTX_SEMANTIC_20 |
0x00000000, // SQ_VTX_SEMANTIC_21 |
0x00000000, // SQ_VTX_SEMANTIC_22 |
0x00000000, // SQ_VTX_SEMANTIC_23 |
0x00000000, // SQ_VTX_SEMANTIC_24 |
0x00000000, // SQ_VTX_SEMANTIC_25 |
0x00000000, // SQ_VTX_SEMANTIC_26 |
0x00000000, // SQ_VTX_SEMANTIC_27 |
0x00000000, // SQ_VTX_SEMANTIC_28 |
0x00000000, // SQ_VTX_SEMANTIC_29 |
0x00000000, // SQ_VTX_SEMANTIC_30 |
0x00000000, // SQ_VTX_SEMANTIC_31 |
0xffffffff, // VGT_MAX_VTX_INDX |
0x00000000, // VGT_MIN_VTX_INDX |
0x00000000, // VGT_INDX_OFFSET |
0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX |
0x00000000, // SX_ALPHA_TEST_CONTROL |
0x00000000, // CB_BLEND_RED |
0x00000000, // CB_BLEND_GREEN |
0x00000000, // CB_BLEND_BLUE |
0x00000000, // CB_BLEND_ALPHA |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_STENCILREFMASK |
0x00000000, // DB_STENCILREFMASK_BF |
0x00000000, // SX_ALPHA_REF |
0x00000000, // PA_CL_VPORT_XSCALE |
0x00000000, // PA_CL_VPORT_XOFFSET |
0x00000000, // PA_CL_VPORT_YSCALE |
0x00000000, // PA_CL_VPORT_YOFFSET |
0x00000000, // PA_CL_VPORT_ZSCALE |
0x00000000, // PA_CL_VPORT_ZOFFSET |
0x00000000, // PA_CL_VPORT_XSCALE_1 |
0x00000000, // PA_CL_VPORT_XOFFSET_1 |
0x00000000, // PA_CL_VPORT_YSCALE_1 |
0x00000000, // PA_CL_VPORT_YOFFSET_1 |
0x00000000, // PA_CL_VPORT_ZSCALE_1 |
0x00000000, // PA_CL_VPORT_ZOFFSET_1 |
0x00000000, // PA_CL_VPORT_XSCALE_2 |
0x00000000, // PA_CL_VPORT_XOFFSET_2 |
0x00000000, // PA_CL_VPORT_YSCALE_2 |
0x00000000, // PA_CL_VPORT_YOFFSET_2 |
0x00000000, // PA_CL_VPORT_ZSCALE_2 |
0x00000000, // PA_CL_VPORT_ZOFFSET_2 |
0x00000000, // PA_CL_VPORT_XSCALE_3 |
0x00000000, // PA_CL_VPORT_XOFFSET_3 |
0x00000000, // PA_CL_VPORT_YSCALE_3 |
0x00000000, // PA_CL_VPORT_YOFFSET_3 |
0x00000000, // PA_CL_VPORT_ZSCALE_3 |
0x00000000, // PA_CL_VPORT_ZOFFSET_3 |
0x00000000, // PA_CL_VPORT_XSCALE_4 |
0x00000000, // PA_CL_VPORT_XOFFSET_4 |
0x00000000, // PA_CL_VPORT_YSCALE_4 |
0x00000000, // PA_CL_VPORT_YOFFSET_4 |
0x00000000, // PA_CL_VPORT_ZSCALE_4 |
0x00000000, // PA_CL_VPORT_ZOFFSET_4 |
0x00000000, // PA_CL_VPORT_XSCALE_5 |
0x00000000, // PA_CL_VPORT_XOFFSET_5 |
0x00000000, // PA_CL_VPORT_YSCALE_5 |
0x00000000, // PA_CL_VPORT_YOFFSET_5 |
0x00000000, // PA_CL_VPORT_ZSCALE_5 |
0x00000000, // PA_CL_VPORT_ZOFFSET_5 |
0x00000000, // PA_CL_VPORT_XSCALE_6 |
0x00000000, // PA_CL_VPORT_XOFFSET_6 |
0x00000000, // PA_CL_VPORT_YSCALE_6 |
0x00000000, // PA_CL_VPORT_YOFFSET_6 |
0x00000000, // PA_CL_VPORT_ZSCALE_6 |
0x00000000, // PA_CL_VPORT_ZOFFSET_6 |
0x00000000, // PA_CL_VPORT_XSCALE_7 |
0x00000000, // PA_CL_VPORT_XOFFSET_7 |
0x00000000, // PA_CL_VPORT_YSCALE_7 |
0x00000000, // PA_CL_VPORT_YOFFSET_7 |
0x00000000, // PA_CL_VPORT_ZSCALE_7 |
0x00000000, // PA_CL_VPORT_ZOFFSET_7 |
0x00000000, // PA_CL_VPORT_XSCALE_8 |
0x00000000, // PA_CL_VPORT_XOFFSET_8 |
0x00000000, // PA_CL_VPORT_YSCALE_8 |
0x00000000, // PA_CL_VPORT_YOFFSET_8 |
0x00000000, // PA_CL_VPORT_ZSCALE_8 |
0x00000000, // PA_CL_VPORT_ZOFFSET_8 |
0x00000000, // PA_CL_VPORT_XSCALE_9 |
0x00000000, // PA_CL_VPORT_XOFFSET_9 |
0x00000000, // PA_CL_VPORT_YSCALE_9 |
0x00000000, // PA_CL_VPORT_YOFFSET_9 |
0x00000000, // PA_CL_VPORT_ZSCALE_9 |
0x00000000, // PA_CL_VPORT_ZOFFSET_9 |
0x00000000, // PA_CL_VPORT_XSCALE_10 |
0x00000000, // PA_CL_VPORT_XOFFSET_10 |
0x00000000, // PA_CL_VPORT_YSCALE_10 |
0x00000000, // PA_CL_VPORT_YOFFSET_10 |
0x00000000, // PA_CL_VPORT_ZSCALE_10 |
0x00000000, // PA_CL_VPORT_ZOFFSET_10 |
0x00000000, // PA_CL_VPORT_XSCALE_11 |
0x00000000, // PA_CL_VPORT_XOFFSET_11 |
0x00000000, // PA_CL_VPORT_YSCALE_11 |
0x00000000, // PA_CL_VPORT_YOFFSET_11 |
0x00000000, // PA_CL_VPORT_ZSCALE_11 |
0x00000000, // PA_CL_VPORT_ZOFFSET_11 |
0x00000000, // PA_CL_VPORT_XSCALE_12 |
0x00000000, // PA_CL_VPORT_XOFFSET_12 |
0x00000000, // PA_CL_VPORT_YSCALE_12 |
0x00000000, // PA_CL_VPORT_YOFFSET_12 |
0x00000000, // PA_CL_VPORT_ZSCALE_12 |
0x00000000, // PA_CL_VPORT_ZOFFSET_12 |
0x00000000, // PA_CL_VPORT_XSCALE_13 |
0x00000000, // PA_CL_VPORT_XOFFSET_13 |
0x00000000, // PA_CL_VPORT_YSCALE_13 |
0x00000000, // PA_CL_VPORT_YOFFSET_13 |
0x00000000, // PA_CL_VPORT_ZSCALE_13 |
0x00000000, // PA_CL_VPORT_ZOFFSET_13 |
0x00000000, // PA_CL_VPORT_XSCALE_14 |
0x00000000, // PA_CL_VPORT_XOFFSET_14 |
0x00000000, // PA_CL_VPORT_YSCALE_14 |
0x00000000, // PA_CL_VPORT_YOFFSET_14 |
0x00000000, // PA_CL_VPORT_ZSCALE_14 |
0x00000000, // PA_CL_VPORT_ZOFFSET_14 |
0x00000000, // PA_CL_VPORT_XSCALE_15 |
0x00000000, // PA_CL_VPORT_XOFFSET_15 |
0x00000000, // PA_CL_VPORT_YSCALE_15 |
0x00000000, // PA_CL_VPORT_YOFFSET_15 |
0x00000000, // PA_CL_VPORT_ZSCALE_15 |
0x00000000, // PA_CL_VPORT_ZOFFSET_15 |
0x00000000, // PA_CL_UCP_0_X |
0x00000000, // PA_CL_UCP_0_Y |
0x00000000, // PA_CL_UCP_0_Z |
0x00000000, // PA_CL_UCP_0_W |
0x00000000, // PA_CL_UCP_1_X |
0x00000000, // PA_CL_UCP_1_Y |
0x00000000, // PA_CL_UCP_1_Z |
0x00000000, // PA_CL_UCP_1_W |
0x00000000, // PA_CL_UCP_2_X |
0x00000000, // PA_CL_UCP_2_Y |
0x00000000, // PA_CL_UCP_2_Z |
0x00000000, // PA_CL_UCP_2_W |
0x00000000, // PA_CL_UCP_3_X |
0x00000000, // PA_CL_UCP_3_Y |
0x00000000, // PA_CL_UCP_3_Z |
0x00000000, // PA_CL_UCP_3_W |
0x00000000, // PA_CL_UCP_4_X |
0x00000000, // PA_CL_UCP_4_Y |
0x00000000, // PA_CL_UCP_4_Z |
0x00000000, // PA_CL_UCP_4_W |
0x00000000, // PA_CL_UCP_5_X |
0x00000000, // PA_CL_UCP_5_Y |
0x00000000, // PA_CL_UCP_5_Z |
0x00000000, // PA_CL_UCP_5_W |
0x00000000, // SPI_VS_OUT_ID_0 |
0x00000000, // SPI_VS_OUT_ID_1 |
0x00000000, // SPI_VS_OUT_ID_2 |
0x00000000, // SPI_VS_OUT_ID_3 |
0x00000000, // SPI_VS_OUT_ID_4 |
0x00000000, // SPI_VS_OUT_ID_5 |
0x00000000, // SPI_VS_OUT_ID_6 |
0x00000000, // SPI_VS_OUT_ID_7 |
0x00000000, // SPI_VS_OUT_ID_8 |
0x00000000, // SPI_VS_OUT_ID_9 |
0x00000000, // SPI_PS_INPUT_CNTL_0 |
0x00000000, // SPI_PS_INPUT_CNTL_1 |
0x00000000, // SPI_PS_INPUT_CNTL_2 |
0x00000000, // SPI_PS_INPUT_CNTL_3 |
0x00000000, // SPI_PS_INPUT_CNTL_4 |
0x00000000, // SPI_PS_INPUT_CNTL_5 |
0x00000000, // SPI_PS_INPUT_CNTL_6 |
0x00000000, // SPI_PS_INPUT_CNTL_7 |
0x00000000, // SPI_PS_INPUT_CNTL_8 |
0x00000000, // SPI_PS_INPUT_CNTL_9 |
0x00000000, // SPI_PS_INPUT_CNTL_10 |
0x00000000, // SPI_PS_INPUT_CNTL_11 |
0x00000000, // SPI_PS_INPUT_CNTL_12 |
0x00000000, // SPI_PS_INPUT_CNTL_13 |
0x00000000, // SPI_PS_INPUT_CNTL_14 |
0x00000000, // SPI_PS_INPUT_CNTL_15 |
0x00000000, // SPI_PS_INPUT_CNTL_16 |
0x00000000, // SPI_PS_INPUT_CNTL_17 |
0x00000000, // SPI_PS_INPUT_CNTL_18 |
0x00000000, // SPI_PS_INPUT_CNTL_19 |
0x00000000, // SPI_PS_INPUT_CNTL_20 |
0x00000000, // SPI_PS_INPUT_CNTL_21 |
0x00000000, // SPI_PS_INPUT_CNTL_22 |
0x00000000, // SPI_PS_INPUT_CNTL_23 |
0x00000000, // SPI_PS_INPUT_CNTL_24 |
0x00000000, // SPI_PS_INPUT_CNTL_25 |
0x00000000, // SPI_PS_INPUT_CNTL_26 |
0x00000000, // SPI_PS_INPUT_CNTL_27 |
0x00000000, // SPI_PS_INPUT_CNTL_28 |
0x00000000, // SPI_PS_INPUT_CNTL_29 |
0x00000000, // SPI_PS_INPUT_CNTL_30 |
0x00000000, // SPI_PS_INPUT_CNTL_31 |
0x00000000, // SPI_VS_OUT_CONFIG |
0x00000001, // SPI_THREAD_GROUPING |
0x00000002, // SPI_PS_IN_CONTROL_0 |
0x00000000, // SPI_PS_IN_CONTROL_1 |
0x00000000, // SPI_INTERP_CONTROL_0 |
0x00000000, // SPI_INPUT_Z |
0x00000000, // SPI_FOG_CNTL |
0x00000000, // SPI_BARYC_CNTL |
0x00000000, // SPI_PS_IN_CONTROL_2 |
0x00000000, // SPI_COMPUTE_INPUT_CNTL |
0x00000000, // SPI_COMPUTE_NUM_THREAD_X |
0x00000000, // SPI_COMPUTE_NUM_THREAD_Y |
0x00000000, // SPI_COMPUTE_NUM_THREAD_Z |
0x00000000, // SPI_GPR_MGMT |
0x00000000, // SPI_LDS_MGMT |
0x00000000, // SPI_STACK_MGMT |
0x00000000, // SPI_WAVE_MGMT_1 |
0x00000000, // SPI_WAVE_MGMT_2 |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // GDS_ADDR_BASE |
0x00003fff, // GDS_ADDR_SIZE |
0, // HOLE |
0, // HOLE |
0x00000000, // GDS_ORDERED_COUNT |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // GDS_APPEND_CONSUME_UAV0 |
0x00000000, // GDS_APPEND_CONSUME_UAV1 |
0x00000000, // GDS_APPEND_CONSUME_UAV2 |
0x00000000, // GDS_APPEND_CONSUME_UAV3 |
0x00000000, // GDS_APPEND_CONSUME_UAV4 |
0x00000000, // GDS_APPEND_CONSUME_UAV5 |
0x00000000, // GDS_APPEND_CONSUME_UAV6 |
0x00000000, // GDS_APPEND_CONSUME_UAV7 |
0x00000000, // GDS_APPEND_CONSUME_UAV8 |
0x00000000, // GDS_APPEND_CONSUME_UAV9 |
0x00000000, // GDS_APPEND_CONSUME_UAV10 |
0x00000000, // GDS_APPEND_CONSUME_UAV11 |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_BLEND0_CONTROL |
0x00000000, // CB_BLEND1_CONTROL |
0x00000000, // CB_BLEND2_CONTROL |
0x00000000, // CB_BLEND3_CONTROL |
0x00000000, // CB_BLEND4_CONTROL |
0x00000000, // CB_BLEND5_CONTROL |
0x00000000, // CB_BLEND6_CONTROL |
0x00000000, // CB_BLEND7_CONTROL |
}; |
static const u32 SECT_CONTEXT_def_2[] = |
{ |
0x00000000, // PA_CL_POINT_X_RAD |
0x00000000, // PA_CL_POINT_Y_RAD |
0x00000000, // PA_CL_POINT_SIZE |
0x00000000, // PA_CL_POINT_CULL_RAD |
0x00000000, // VGT_DMA_BASE_HI |
0x00000000, // VGT_DMA_BASE |
}; |
static const u32 SECT_CONTEXT_def_3[] = |
{ |
0x00000000, // DB_DEPTH_CONTROL |
0x00000000, // DB_EQAA |
0x00000000, // CB_COLOR_CONTROL |
0x00000200, // DB_SHADER_CONTROL |
0x00000000, // PA_CL_CLIP_CNTL |
0x00000000, // PA_SU_SC_MODE_CNTL |
0x00000000, // PA_CL_VTE_CNTL |
0x00000000, // PA_CL_VS_OUT_CNTL |
0x00000000, // PA_CL_NANINF_CNTL |
0x00000000, // PA_SU_LINE_STIPPLE_CNTL |
0x00000000, // PA_SU_LINE_STIPPLE_SCALE |
0x00000000, // PA_SU_PRIM_FILTER_CNTL |
0x00000000, // SQ_LSTMP_RING_ITEMSIZE |
0x00000000, // SQ_HSTMP_RING_ITEMSIZE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_PS |
0x00000000, // SQ_PGM_RESOURCES_PS |
0x00000000, // SQ_PGM_RESOURCES_2_PS |
0x00000000, // SQ_PGM_EXPORTS_PS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_VS |
0x00000000, // SQ_PGM_RESOURCES_VS |
0x00000000, // SQ_PGM_RESOURCES_2_VS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_GS |
0x00000000, // SQ_PGM_RESOURCES_GS |
0x00000000, // SQ_PGM_RESOURCES_2_GS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_ES |
0x00000000, // SQ_PGM_RESOURCES_ES |
0x00000000, // SQ_PGM_RESOURCES_2_ES |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_FS |
0x00000000, // SQ_PGM_RESOURCES_FS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_HS |
0x00000000, // SQ_PGM_RESOURCES_HS |
0x00000000, // SQ_PGM_RESOURCES_2_HS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_LS |
0x00000000, // SQ_PGM_RESOURCES_LS |
0x00000000, // SQ_PGM_RESOURCES_2_LS |
}; |
static const u32 SECT_CONTEXT_def_4[] = |
{ |
0x00000000, // SQ_LDS_ALLOC |
0x00000000, // SQ_LDS_ALLOC_PS |
0x00000000, // SQ_VTX_SEMANTIC_CLEAR |
0, // HOLE |
0x00000000, // SQ_THREAD_TRACE_CTRL |
0, // HOLE |
0x00000000, // SQ_ESGS_RING_ITEMSIZE |
0x00000000, // SQ_GSVS_RING_ITEMSIZE |
0x00000000, // SQ_ESTMP_RING_ITEMSIZE |
0x00000000, // SQ_GSTMP_RING_ITEMSIZE |
0x00000000, // SQ_VSTMP_RING_ITEMSIZE |
0x00000000, // SQ_PSTMP_RING_ITEMSIZE |
0, // HOLE |
0x00000000, // SQ_GS_VERT_ITEMSIZE |
0x00000000, // SQ_GS_VERT_ITEMSIZE_1 |
0x00000000, // SQ_GS_VERT_ITEMSIZE_2 |
0x00000000, // SQ_GS_VERT_ITEMSIZE_3 |
0x00000000, // SQ_GSVS_RING_OFFSET_1 |
0x00000000, // SQ_GSVS_RING_OFFSET_2 |
0x00000000, // SQ_GSVS_RING_OFFSET_3 |
0x00000000, // SQ_GWS_RING_OFFSET |
0, // HOLE |
0x00000000, // SQ_ALU_CONST_CACHE_PS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_15 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_15 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_15 |
0x00000000, // PA_SU_POINT_SIZE |
0x00000000, // PA_SU_POINT_MINMAX |
0x00000000, // PA_SU_LINE_CNTL |
0x00000000, // PA_SC_LINE_STIPPLE |
0x00000000, // VGT_OUTPUT_PATH_CNTL |
0x00000000, // VGT_HOS_CNTL |
0x00000000, // VGT_HOS_MAX_TESS_LEVEL |
0x00000000, // VGT_HOS_MIN_TESS_LEVEL |
0x00000000, // VGT_HOS_REUSE_DEPTH |
0x00000000, // VGT_GROUP_PRIM_TYPE |
0x00000000, // VGT_GROUP_FIRST_DECR |
0x00000000, // VGT_GROUP_DECR |
0x00000000, // VGT_GROUP_VECT_0_CNTL |
0x00000000, // VGT_GROUP_VECT_1_CNTL |
0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL |
0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL |
0x00000000, // VGT_GS_MODE |
0, // HOLE |
0x00000000, // PA_SC_MODE_CNTL_0 |
0x00000000, // PA_SC_MODE_CNTL_1 |
0x00000000, // VGT_ENHANCE |
0x00000100, // VGT_GS_PER_ES |
0x00000080, // VGT_ES_PER_GS |
0x00000002, // VGT_GS_PER_VS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_GS_OUT_PRIM_TYPE |
0x00000000, // IA_ENHANCE |
}; |
static const u32 SECT_CONTEXT_def_5[] = |
{ |
0x00000000, // VGT_DMA_MAX_SIZE |
0x00000000, // VGT_DMA_INDEX_TYPE |
0, // HOLE |
0x00000000, // VGT_PRIMITIVEID_EN |
0x00000000, // VGT_DMA_NUM_INSTANCES |
}; |
static const u32 SECT_CONTEXT_def_6[] = |
{ |
0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_INSTANCE_STEP_RATE_0 |
0x00000000, // VGT_INSTANCE_STEP_RATE_1 |
0x000000ff, // IA_MULTI_VGT_PARAM |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_REUSE_OFF |
0x00000000, // VGT_VTX_CNT_EN |
0x00000000, // DB_HTILE_SURFACE |
0x00000000, // DB_SRESULTS_COMPARE_STATE0 |
0x00000000, // DB_SRESULTS_COMPARE_STATE1 |
0x00000000, // DB_PRELOAD_CONTROL |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_0 |
0x00000000, // VGT_STRMOUT_BUFFER_BASE_0 |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_1 |
0x00000000, // VGT_STRMOUT_BUFFER_BASE_1 |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_2 |
0x00000000, // VGT_STRMOUT_BUFFER_BASE_2 |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_3 |
0x00000000, // VGT_STRMOUT_BUFFER_BASE_3 |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_0 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_1 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_2 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_3 |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE |
0, // HOLE |
0x00000000, // VGT_GS_MAX_VERT_OUT |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_0 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_1 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_2 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_3 |
0x00000000, // VGT_SHADER_STAGES_EN |
0x00000000, // VGT_LS_HS_CONFIG |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_TF_PARAM |
0x00000000, // DB_ALPHA_TO_MASK |
}; |
static const u32 SECT_CONTEXT_def_7[] = |
{ |
0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL |
0x00000000, // PA_SU_POLY_OFFSET_CLAMP |
0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE |
0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET |
0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE |
0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET |
0x00000000, // VGT_GS_INSTANCE_CNT |
0x00000000, // VGT_STRMOUT_CONFIG |
0x00000000, // VGT_STRMOUT_BUFFER_CONFIG |
0x00000000, // CB_IMMED0_BASE |
0x00000000, // CB_IMMED1_BASE |
0x00000000, // CB_IMMED2_BASE |
0x00000000, // CB_IMMED3_BASE |
0x00000000, // CB_IMMED4_BASE |
0x00000000, // CB_IMMED5_BASE |
0x00000000, // CB_IMMED6_BASE |
0x00000000, // CB_IMMED7_BASE |
0x00000000, // CB_IMMED8_BASE |
0x00000000, // CB_IMMED9_BASE |
0x00000000, // CB_IMMED10_BASE |
0x00000000, // CB_IMMED11_BASE |
0, // HOLE |
0, // HOLE |
0x00000000, // PA_SC_CENTROID_PRIORITY_0 |
0x00000000, // PA_SC_CENTROID_PRIORITY_1 |
0x00001000, // PA_SC_LINE_CNTL |
0x00000000, // PA_SC_AA_CONFIG |
0x00000005, // PA_SU_VTX_CNTL |
0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ |
0x3f800000, // PA_CL_GB_VERT_DISC_ADJ |
0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ |
0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_3 |
0xffffffff, // PA_SC_AA_MASK_X0Y0_X1Y0 |
0xffffffff, // PA_SC_AA_MASK_X0Y1_X1Y1 |
0x00000000, // CB_CLRCMP_CONTROL |
0x00000000, // CB_CLRCMP_SRC |
0x00000000, // CB_CLRCMP_DST |
0x00000000, // CB_CLRCMP_MSK |
0, // HOLE |
0, // HOLE |
0x0000000e, // VGT_VERTEX_REUSE_BLOCK_CNTL |
0x00000010, // VGT_OUT_DEALLOC_CNTL |
0x00000000, // CB_COLOR0_BASE |
0x00000000, // CB_COLOR0_PITCH |
0x00000000, // CB_COLOR0_SLICE |
0x00000000, // CB_COLOR0_VIEW |
0x00000000, // CB_COLOR0_INFO |
0x00000000, // CB_COLOR0_ATTRIB |
0x00000000, // CB_COLOR0_DIM |
0x00000000, // CB_COLOR0_CMASK |
0x00000000, // CB_COLOR0_CMASK_SLICE |
0x00000000, // CB_COLOR0_FMASK |
0x00000000, // CB_COLOR0_FMASK_SLICE |
0x00000000, // CB_COLOR0_CLEAR_WORD0 |
0x00000000, // CB_COLOR0_CLEAR_WORD1 |
0x00000000, // CB_COLOR0_CLEAR_WORD2 |
0x00000000, // CB_COLOR0_CLEAR_WORD3 |
0x00000000, // CB_COLOR1_BASE |
0x00000000, // CB_COLOR1_PITCH |
0x00000000, // CB_COLOR1_SLICE |
0x00000000, // CB_COLOR1_VIEW |
0x00000000, // CB_COLOR1_INFO |
0x00000000, // CB_COLOR1_ATTRIB |
0x00000000, // CB_COLOR1_DIM |
0x00000000, // CB_COLOR1_CMASK |
0x00000000, // CB_COLOR1_CMASK_SLICE |
0x00000000, // CB_COLOR1_FMASK |
0x00000000, // CB_COLOR1_FMASK_SLICE |
0x00000000, // CB_COLOR1_CLEAR_WORD0 |
0x00000000, // CB_COLOR1_CLEAR_WORD1 |
0x00000000, // CB_COLOR1_CLEAR_WORD2 |
0x00000000, // CB_COLOR1_CLEAR_WORD3 |
0x00000000, // CB_COLOR2_BASE |
0x00000000, // CB_COLOR2_PITCH |
0x00000000, // CB_COLOR2_SLICE |
0x00000000, // CB_COLOR2_VIEW |
0x00000000, // CB_COLOR2_INFO |
0x00000000, // CB_COLOR2_ATTRIB |
0x00000000, // CB_COLOR2_DIM |
0x00000000, // CB_COLOR2_CMASK |
0x00000000, // CB_COLOR2_CMASK_SLICE |
0x00000000, // CB_COLOR2_FMASK |
0x00000000, // CB_COLOR2_FMASK_SLICE |
0x00000000, // CB_COLOR2_CLEAR_WORD0 |
0x00000000, // CB_COLOR2_CLEAR_WORD1 |
0x00000000, // CB_COLOR2_CLEAR_WORD2 |
0x00000000, // CB_COLOR2_CLEAR_WORD3 |
0x00000000, // CB_COLOR3_BASE |
0x00000000, // CB_COLOR3_PITCH |
0x00000000, // CB_COLOR3_SLICE |
0x00000000, // CB_COLOR3_VIEW |
0x00000000, // CB_COLOR3_INFO |
0x00000000, // CB_COLOR3_ATTRIB |
0x00000000, // CB_COLOR3_DIM |
0x00000000, // CB_COLOR3_CMASK |
0x00000000, // CB_COLOR3_CMASK_SLICE |
0x00000000, // CB_COLOR3_FMASK |
0x00000000, // CB_COLOR3_FMASK_SLICE |
0x00000000, // CB_COLOR3_CLEAR_WORD0 |
0x00000000, // CB_COLOR3_CLEAR_WORD1 |
0x00000000, // CB_COLOR3_CLEAR_WORD2 |
0x00000000, // CB_COLOR3_CLEAR_WORD3 |
0x00000000, // CB_COLOR4_BASE |
0x00000000, // CB_COLOR4_PITCH |
0x00000000, // CB_COLOR4_SLICE |
0x00000000, // CB_COLOR4_VIEW |
0x00000000, // CB_COLOR4_INFO |
0x00000000, // CB_COLOR4_ATTRIB |
0x00000000, // CB_COLOR4_DIM |
0x00000000, // CB_COLOR4_CMASK |
0x00000000, // CB_COLOR4_CMASK_SLICE |
0x00000000, // CB_COLOR4_FMASK |
0x00000000, // CB_COLOR4_FMASK_SLICE |
0x00000000, // CB_COLOR4_CLEAR_WORD0 |
0x00000000, // CB_COLOR4_CLEAR_WORD1 |
0x00000000, // CB_COLOR4_CLEAR_WORD2 |
0x00000000, // CB_COLOR4_CLEAR_WORD3 |
0x00000000, // CB_COLOR5_BASE |
0x00000000, // CB_COLOR5_PITCH |
0x00000000, // CB_COLOR5_SLICE |
0x00000000, // CB_COLOR5_VIEW |
0x00000000, // CB_COLOR5_INFO |
0x00000000, // CB_COLOR5_ATTRIB |
0x00000000, // CB_COLOR5_DIM |
0x00000000, // CB_COLOR5_CMASK |
0x00000000, // CB_COLOR5_CMASK_SLICE |
0x00000000, // CB_COLOR5_FMASK |
0x00000000, // CB_COLOR5_FMASK_SLICE |
0x00000000, // CB_COLOR5_CLEAR_WORD0 |
0x00000000, // CB_COLOR5_CLEAR_WORD1 |
0x00000000, // CB_COLOR5_CLEAR_WORD2 |
0x00000000, // CB_COLOR5_CLEAR_WORD3 |
0x00000000, // CB_COLOR6_BASE |
0x00000000, // CB_COLOR6_PITCH |
0x00000000, // CB_COLOR6_SLICE |
0x00000000, // CB_COLOR6_VIEW |
0x00000000, // CB_COLOR6_INFO |
0x00000000, // CB_COLOR6_ATTRIB |
0x00000000, // CB_COLOR6_DIM |
0x00000000, // CB_COLOR6_CMASK |
0x00000000, // CB_COLOR6_CMASK_SLICE |
0x00000000, // CB_COLOR6_FMASK |
0x00000000, // CB_COLOR6_FMASK_SLICE |
0x00000000, // CB_COLOR6_CLEAR_WORD0 |
0x00000000, // CB_COLOR6_CLEAR_WORD1 |
0x00000000, // CB_COLOR6_CLEAR_WORD2 |
0x00000000, // CB_COLOR6_CLEAR_WORD3 |
0x00000000, // CB_COLOR7_BASE |
0x00000000, // CB_COLOR7_PITCH |
0x00000000, // CB_COLOR7_SLICE |
0x00000000, // CB_COLOR7_VIEW |
0x00000000, // CB_COLOR7_INFO |
0x00000000, // CB_COLOR7_ATTRIB |
0x00000000, // CB_COLOR7_DIM |
0x00000000, // CB_COLOR7_CMASK |
0x00000000, // CB_COLOR7_CMASK_SLICE |
0x00000000, // CB_COLOR7_FMASK |
0x00000000, // CB_COLOR7_FMASK_SLICE |
0x00000000, // CB_COLOR7_CLEAR_WORD0 |
0x00000000, // CB_COLOR7_CLEAR_WORD1 |
0x00000000, // CB_COLOR7_CLEAR_WORD2 |
0x00000000, // CB_COLOR7_CLEAR_WORD3 |
0x00000000, // CB_COLOR8_BASE |
0x00000000, // CB_COLOR8_PITCH |
0x00000000, // CB_COLOR8_SLICE |
0x00000000, // CB_COLOR8_VIEW |
0x00000000, // CB_COLOR8_INFO |
0x00000000, // CB_COLOR8_ATTRIB |
0x00000000, // CB_COLOR8_DIM |
0x00000000, // CB_COLOR9_BASE |
0x00000000, // CB_COLOR9_PITCH |
0x00000000, // CB_COLOR9_SLICE |
0x00000000, // CB_COLOR9_VIEW |
0x00000000, // CB_COLOR9_INFO |
0x00000000, // CB_COLOR9_ATTRIB |
0x00000000, // CB_COLOR9_DIM |
0x00000000, // CB_COLOR10_BASE |
0x00000000, // CB_COLOR10_PITCH |
0x00000000, // CB_COLOR10_SLICE |
0x00000000, // CB_COLOR10_VIEW |
0x00000000, // CB_COLOR10_INFO |
0x00000000, // CB_COLOR10_ATTRIB |
0x00000000, // CB_COLOR10_DIM |
0x00000000, // CB_COLOR11_BASE |
0x00000000, // CB_COLOR11_PITCH |
0x00000000, // CB_COLOR11_SLICE |
0x00000000, // CB_COLOR11_VIEW |
0x00000000, // CB_COLOR11_INFO |
0x00000000, // CB_COLOR11_ATTRIB |
0x00000000, // CB_COLOR11_DIM |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_ALU_CONST_CACHE_HS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_15 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_15 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_15 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_15 |
}; |
static const struct cs_extent_def SECT_CONTEXT_defs[] = |
{ |
{SECT_CONTEXT_def_1, 0x0000a000, 488 }, |
{SECT_CONTEXT_def_2, 0x0000a1f5, 6 }, |
{SECT_CONTEXT_def_3, 0x0000a200, 55 }, |
{SECT_CONTEXT_def_4, 0x0000a23a, 99 }, |
{SECT_CONTEXT_def_5, 0x0000a29e, 5 }, |
{SECT_CONTEXT_def_6, 0x0000a2a5, 56 }, |
{SECT_CONTEXT_def_7, 0x0000a2de, 290 }, |
{ NULL, 0, 0 } |
}; |
static const u32 SECT_CLEAR_def_1[] = |
{ |
0xffffffff, // SQ_TEX_SAMPLER_CLEAR |
0xffffffff, // SQ_TEX_RESOURCE_CLEAR |
0xffffffff, // SQ_LOOP_BOOL_CLEAR |
}; |
static const struct cs_extent_def SECT_CLEAR_defs[] = |
{ |
{SECT_CLEAR_def_1, 0x0000ffc0, 3 }, |
{ NULL, 0, 0 } |
}; |
static const u32 SECT_CTRLCONST_def_1[] = |
{ |
0x00000000, // SQ_VTX_BASE_VTX_LOC |
0x00000000, // SQ_VTX_START_INST_LOC |
}; |
static const struct cs_extent_def SECT_CTRLCONST_defs[] = |
{ |
{SECT_CTRLCONST_def_1, 0x0000f3fc, 2 }, |
{ 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 }, |
{ NULL, SECT_NONE } |
}; |
/drivers/video/drm/radeon/clearstate_ci.h |
---|
0,0 → 1,944 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
static const unsigned int ci_SECT_CONTEXT_def_1[] = |
{ |
0x00000000, // DB_RENDER_CONTROL |
0x00000000, // DB_COUNT_CONTROL |
0x00000000, // DB_DEPTH_VIEW |
0x00000000, // DB_RENDER_OVERRIDE |
0x00000000, // DB_RENDER_OVERRIDE2 |
0x00000000, // DB_HTILE_DATA_BASE |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_DEPTH_BOUNDS_MIN |
0x00000000, // DB_DEPTH_BOUNDS_MAX |
0x00000000, // DB_STENCIL_CLEAR |
0x00000000, // DB_DEPTH_CLEAR |
0x00000000, // PA_SC_SCREEN_SCISSOR_TL |
0x40004000, // PA_SC_SCREEN_SCISSOR_BR |
0, // HOLE |
0x00000000, // DB_DEPTH_INFO |
0x00000000, // DB_Z_INFO |
0x00000000, // DB_STENCIL_INFO |
0x00000000, // DB_Z_READ_BASE |
0x00000000, // DB_STENCIL_READ_BASE |
0x00000000, // DB_Z_WRITE_BASE |
0x00000000, // DB_STENCIL_WRITE_BASE |
0x00000000, // DB_DEPTH_SIZE |
0x00000000, // DB_DEPTH_SLICE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // TA_BC_BASE_ADDR |
0x00000000, // TA_BC_BASE_ADDR_HI |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // COHER_DEST_BASE_HI_0 |
0x00000000, // COHER_DEST_BASE_HI_1 |
0x00000000, // COHER_DEST_BASE_HI_2 |
0x00000000, // COHER_DEST_BASE_HI_3 |
0x00000000, // COHER_DEST_BASE_2 |
0x00000000, // COHER_DEST_BASE_3 |
0x00000000, // PA_SC_WINDOW_OFFSET |
0x80000000, // PA_SC_WINDOW_SCISSOR_TL |
0x40004000, // PA_SC_WINDOW_SCISSOR_BR |
0x0000ffff, // PA_SC_CLIPRECT_RULE |
0x00000000, // PA_SC_CLIPRECT_0_TL |
0x40004000, // PA_SC_CLIPRECT_0_BR |
0x00000000, // PA_SC_CLIPRECT_1_TL |
0x40004000, // PA_SC_CLIPRECT_1_BR |
0x00000000, // PA_SC_CLIPRECT_2_TL |
0x40004000, // PA_SC_CLIPRECT_2_BR |
0x00000000, // PA_SC_CLIPRECT_3_TL |
0x40004000, // PA_SC_CLIPRECT_3_BR |
0xaa99aaaa, // PA_SC_EDGERULE |
0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET |
0xffffffff, // CB_TARGET_MASK |
0xffffffff, // CB_SHADER_MASK |
0x80000000, // PA_SC_GENERIC_SCISSOR_TL |
0x40004000, // PA_SC_GENERIC_SCISSOR_BR |
0x00000000, // COHER_DEST_BASE_0 |
0x00000000, // COHER_DEST_BASE_1 |
0x80000000, // PA_SC_VPORT_SCISSOR_0_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_0_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_1_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_1_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_2_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_2_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_3_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_3_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_4_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_4_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_5_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_5_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_6_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_6_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_7_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_7_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_8_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_8_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_9_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_9_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_10_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_10_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_11_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_11_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_12_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_12_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_13_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_13_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_14_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_14_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_15_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_15_BR |
0x00000000, // PA_SC_VPORT_ZMIN_0 |
0x3f800000, // PA_SC_VPORT_ZMAX_0 |
0x00000000, // PA_SC_VPORT_ZMIN_1 |
0x3f800000, // PA_SC_VPORT_ZMAX_1 |
0x00000000, // PA_SC_VPORT_ZMIN_2 |
0x3f800000, // PA_SC_VPORT_ZMAX_2 |
0x00000000, // PA_SC_VPORT_ZMIN_3 |
0x3f800000, // PA_SC_VPORT_ZMAX_3 |
0x00000000, // PA_SC_VPORT_ZMIN_4 |
0x3f800000, // PA_SC_VPORT_ZMAX_4 |
0x00000000, // PA_SC_VPORT_ZMIN_5 |
0x3f800000, // PA_SC_VPORT_ZMAX_5 |
0x00000000, // PA_SC_VPORT_ZMIN_6 |
0x3f800000, // PA_SC_VPORT_ZMAX_6 |
0x00000000, // PA_SC_VPORT_ZMIN_7 |
0x3f800000, // PA_SC_VPORT_ZMAX_7 |
0x00000000, // PA_SC_VPORT_ZMIN_8 |
0x3f800000, // PA_SC_VPORT_ZMAX_8 |
0x00000000, // PA_SC_VPORT_ZMIN_9 |
0x3f800000, // PA_SC_VPORT_ZMAX_9 |
0x00000000, // PA_SC_VPORT_ZMIN_10 |
0x3f800000, // PA_SC_VPORT_ZMAX_10 |
0x00000000, // PA_SC_VPORT_ZMIN_11 |
0x3f800000, // PA_SC_VPORT_ZMAX_11 |
0x00000000, // PA_SC_VPORT_ZMIN_12 |
0x3f800000, // PA_SC_VPORT_ZMAX_12 |
0x00000000, // PA_SC_VPORT_ZMIN_13 |
0x3f800000, // PA_SC_VPORT_ZMAX_13 |
0x00000000, // PA_SC_VPORT_ZMIN_14 |
0x3f800000, // PA_SC_VPORT_ZMAX_14 |
0x00000000, // PA_SC_VPORT_ZMIN_15 |
0x3f800000, // PA_SC_VPORT_ZMAX_15 |
}; |
static const unsigned int ci_SECT_CONTEXT_def_2[] = |
{ |
0x00000000, // PA_SC_SCREEN_EXTENT_CONTROL |
0, // HOLE |
0x00000000, // CP_PERFMON_CNTX_CNTL |
0x00000000, // CP_RINGID |
0x00000000, // CP_VMID |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0xffffffff, // VGT_MAX_VTX_INDX |
0x00000000, // VGT_MIN_VTX_INDX |
0x00000000, // VGT_INDX_OFFSET |
0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX |
0, // HOLE |
0x00000000, // CB_BLEND_RED |
0x00000000, // CB_BLEND_GREEN |
0x00000000, // CB_BLEND_BLUE |
0x00000000, // CB_BLEND_ALPHA |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_STENCIL_CONTROL |
0x00000000, // DB_STENCILREFMASK |
0x00000000, // DB_STENCILREFMASK_BF |
0, // HOLE |
0x00000000, // PA_CL_VPORT_XSCALE |
0x00000000, // PA_CL_VPORT_XOFFSET |
0x00000000, // PA_CL_VPORT_YSCALE |
0x00000000, // PA_CL_VPORT_YOFFSET |
0x00000000, // PA_CL_VPORT_ZSCALE |
0x00000000, // PA_CL_VPORT_ZOFFSET |
0x00000000, // PA_CL_VPORT_XSCALE_1 |
0x00000000, // PA_CL_VPORT_XOFFSET_1 |
0x00000000, // PA_CL_VPORT_YSCALE_1 |
0x00000000, // PA_CL_VPORT_YOFFSET_1 |
0x00000000, // PA_CL_VPORT_ZSCALE_1 |
0x00000000, // PA_CL_VPORT_ZOFFSET_1 |
0x00000000, // PA_CL_VPORT_XSCALE_2 |
0x00000000, // PA_CL_VPORT_XOFFSET_2 |
0x00000000, // PA_CL_VPORT_YSCALE_2 |
0x00000000, // PA_CL_VPORT_YOFFSET_2 |
0x00000000, // PA_CL_VPORT_ZSCALE_2 |
0x00000000, // PA_CL_VPORT_ZOFFSET_2 |
0x00000000, // PA_CL_VPORT_XSCALE_3 |
0x00000000, // PA_CL_VPORT_XOFFSET_3 |
0x00000000, // PA_CL_VPORT_YSCALE_3 |
0x00000000, // PA_CL_VPORT_YOFFSET_3 |
0x00000000, // PA_CL_VPORT_ZSCALE_3 |
0x00000000, // PA_CL_VPORT_ZOFFSET_3 |
0x00000000, // PA_CL_VPORT_XSCALE_4 |
0x00000000, // PA_CL_VPORT_XOFFSET_4 |
0x00000000, // PA_CL_VPORT_YSCALE_4 |
0x00000000, // PA_CL_VPORT_YOFFSET_4 |
0x00000000, // PA_CL_VPORT_ZSCALE_4 |
0x00000000, // PA_CL_VPORT_ZOFFSET_4 |
0x00000000, // PA_CL_VPORT_XSCALE_5 |
0x00000000, // PA_CL_VPORT_XOFFSET_5 |
0x00000000, // PA_CL_VPORT_YSCALE_5 |
0x00000000, // PA_CL_VPORT_YOFFSET_5 |
0x00000000, // PA_CL_VPORT_ZSCALE_5 |
0x00000000, // PA_CL_VPORT_ZOFFSET_5 |
0x00000000, // PA_CL_VPORT_XSCALE_6 |
0x00000000, // PA_CL_VPORT_XOFFSET_6 |
0x00000000, // PA_CL_VPORT_YSCALE_6 |
0x00000000, // PA_CL_VPORT_YOFFSET_6 |
0x00000000, // PA_CL_VPORT_ZSCALE_6 |
0x00000000, // PA_CL_VPORT_ZOFFSET_6 |
0x00000000, // PA_CL_VPORT_XSCALE_7 |
0x00000000, // PA_CL_VPORT_XOFFSET_7 |
0x00000000, // PA_CL_VPORT_YSCALE_7 |
0x00000000, // PA_CL_VPORT_YOFFSET_7 |
0x00000000, // PA_CL_VPORT_ZSCALE_7 |
0x00000000, // PA_CL_VPORT_ZOFFSET_7 |
0x00000000, // PA_CL_VPORT_XSCALE_8 |
0x00000000, // PA_CL_VPORT_XOFFSET_8 |
0x00000000, // PA_CL_VPORT_YSCALE_8 |
0x00000000, // PA_CL_VPORT_YOFFSET_8 |
0x00000000, // PA_CL_VPORT_ZSCALE_8 |
0x00000000, // PA_CL_VPORT_ZOFFSET_8 |
0x00000000, // PA_CL_VPORT_XSCALE_9 |
0x00000000, // PA_CL_VPORT_XOFFSET_9 |
0x00000000, // PA_CL_VPORT_YSCALE_9 |
0x00000000, // PA_CL_VPORT_YOFFSET_9 |
0x00000000, // PA_CL_VPORT_ZSCALE_9 |
0x00000000, // PA_CL_VPORT_ZOFFSET_9 |
0x00000000, // PA_CL_VPORT_XSCALE_10 |
0x00000000, // PA_CL_VPORT_XOFFSET_10 |
0x00000000, // PA_CL_VPORT_YSCALE_10 |
0x00000000, // PA_CL_VPORT_YOFFSET_10 |
0x00000000, // PA_CL_VPORT_ZSCALE_10 |
0x00000000, // PA_CL_VPORT_ZOFFSET_10 |
0x00000000, // PA_CL_VPORT_XSCALE_11 |
0x00000000, // PA_CL_VPORT_XOFFSET_11 |
0x00000000, // PA_CL_VPORT_YSCALE_11 |
0x00000000, // PA_CL_VPORT_YOFFSET_11 |
0x00000000, // PA_CL_VPORT_ZSCALE_11 |
0x00000000, // PA_CL_VPORT_ZOFFSET_11 |
0x00000000, // PA_CL_VPORT_XSCALE_12 |
0x00000000, // PA_CL_VPORT_XOFFSET_12 |
0x00000000, // PA_CL_VPORT_YSCALE_12 |
0x00000000, // PA_CL_VPORT_YOFFSET_12 |
0x00000000, // PA_CL_VPORT_ZSCALE_12 |
0x00000000, // PA_CL_VPORT_ZOFFSET_12 |
0x00000000, // PA_CL_VPORT_XSCALE_13 |
0x00000000, // PA_CL_VPORT_XOFFSET_13 |
0x00000000, // PA_CL_VPORT_YSCALE_13 |
0x00000000, // PA_CL_VPORT_YOFFSET_13 |
0x00000000, // PA_CL_VPORT_ZSCALE_13 |
0x00000000, // PA_CL_VPORT_ZOFFSET_13 |
0x00000000, // PA_CL_VPORT_XSCALE_14 |
0x00000000, // PA_CL_VPORT_XOFFSET_14 |
0x00000000, // PA_CL_VPORT_YSCALE_14 |
0x00000000, // PA_CL_VPORT_YOFFSET_14 |
0x00000000, // PA_CL_VPORT_ZSCALE_14 |
0x00000000, // PA_CL_VPORT_ZOFFSET_14 |
0x00000000, // PA_CL_VPORT_XSCALE_15 |
0x00000000, // PA_CL_VPORT_XOFFSET_15 |
0x00000000, // PA_CL_VPORT_YSCALE_15 |
0x00000000, // PA_CL_VPORT_YOFFSET_15 |
0x00000000, // PA_CL_VPORT_ZSCALE_15 |
0x00000000, // PA_CL_VPORT_ZOFFSET_15 |
0x00000000, // PA_CL_UCP_0_X |
0x00000000, // PA_CL_UCP_0_Y |
0x00000000, // PA_CL_UCP_0_Z |
0x00000000, // PA_CL_UCP_0_W |
0x00000000, // PA_CL_UCP_1_X |
0x00000000, // PA_CL_UCP_1_Y |
0x00000000, // PA_CL_UCP_1_Z |
0x00000000, // PA_CL_UCP_1_W |
0x00000000, // PA_CL_UCP_2_X |
0x00000000, // PA_CL_UCP_2_Y |
0x00000000, // PA_CL_UCP_2_Z |
0x00000000, // PA_CL_UCP_2_W |
0x00000000, // PA_CL_UCP_3_X |
0x00000000, // PA_CL_UCP_3_Y |
0x00000000, // PA_CL_UCP_3_Z |
0x00000000, // PA_CL_UCP_3_W |
0x00000000, // PA_CL_UCP_4_X |
0x00000000, // PA_CL_UCP_4_Y |
0x00000000, // PA_CL_UCP_4_Z |
0x00000000, // PA_CL_UCP_4_W |
0x00000000, // PA_CL_UCP_5_X |
0x00000000, // PA_CL_UCP_5_Y |
0x00000000, // PA_CL_UCP_5_Z |
0x00000000, // PA_CL_UCP_5_W |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SPI_PS_INPUT_CNTL_0 |
0x00000000, // SPI_PS_INPUT_CNTL_1 |
0x00000000, // SPI_PS_INPUT_CNTL_2 |
0x00000000, // SPI_PS_INPUT_CNTL_3 |
0x00000000, // SPI_PS_INPUT_CNTL_4 |
0x00000000, // SPI_PS_INPUT_CNTL_5 |
0x00000000, // SPI_PS_INPUT_CNTL_6 |
0x00000000, // SPI_PS_INPUT_CNTL_7 |
0x00000000, // SPI_PS_INPUT_CNTL_8 |
0x00000000, // SPI_PS_INPUT_CNTL_9 |
0x00000000, // SPI_PS_INPUT_CNTL_10 |
0x00000000, // SPI_PS_INPUT_CNTL_11 |
0x00000000, // SPI_PS_INPUT_CNTL_12 |
0x00000000, // SPI_PS_INPUT_CNTL_13 |
0x00000000, // SPI_PS_INPUT_CNTL_14 |
0x00000000, // SPI_PS_INPUT_CNTL_15 |
0x00000000, // SPI_PS_INPUT_CNTL_16 |
0x00000000, // SPI_PS_INPUT_CNTL_17 |
0x00000000, // SPI_PS_INPUT_CNTL_18 |
0x00000000, // SPI_PS_INPUT_CNTL_19 |
0x00000000, // SPI_PS_INPUT_CNTL_20 |
0x00000000, // SPI_PS_INPUT_CNTL_21 |
0x00000000, // SPI_PS_INPUT_CNTL_22 |
0x00000000, // SPI_PS_INPUT_CNTL_23 |
0x00000000, // SPI_PS_INPUT_CNTL_24 |
0x00000000, // SPI_PS_INPUT_CNTL_25 |
0x00000000, // SPI_PS_INPUT_CNTL_26 |
0x00000000, // SPI_PS_INPUT_CNTL_27 |
0x00000000, // SPI_PS_INPUT_CNTL_28 |
0x00000000, // SPI_PS_INPUT_CNTL_29 |
0x00000000, // SPI_PS_INPUT_CNTL_30 |
0x00000000, // SPI_PS_INPUT_CNTL_31 |
0x00000000, // SPI_VS_OUT_CONFIG |
0, // HOLE |
0x00000000, // SPI_PS_INPUT_ENA |
0x00000000, // SPI_PS_INPUT_ADDR |
0x00000000, // SPI_INTERP_CONTROL_0 |
0x00000002, // SPI_PS_IN_CONTROL |
0, // HOLE |
0x00000000, // SPI_BARYC_CNTL |
0, // HOLE |
0x00000000, // SPI_TMPRING_SIZE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SPI_SHADER_POS_FORMAT |
0x00000000, // SPI_SHADER_Z_FORMAT |
0x00000000, // SPI_SHADER_COL_FORMAT |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_BLEND0_CONTROL |
0x00000000, // CB_BLEND1_CONTROL |
0x00000000, // CB_BLEND2_CONTROL |
0x00000000, // CB_BLEND3_CONTROL |
0x00000000, // CB_BLEND4_CONTROL |
0x00000000, // CB_BLEND5_CONTROL |
0x00000000, // CB_BLEND6_CONTROL |
0x00000000, // CB_BLEND7_CONTROL |
}; |
static const unsigned int ci_SECT_CONTEXT_def_3[] = |
{ |
0x00000000, // PA_CL_POINT_X_RAD |
0x00000000, // PA_CL_POINT_Y_RAD |
0x00000000, // PA_CL_POINT_SIZE |
0x00000000, // PA_CL_POINT_CULL_RAD |
0x00000000, // VGT_DMA_BASE_HI |
0x00000000, // VGT_DMA_BASE |
}; |
static const unsigned int ci_SECT_CONTEXT_def_4[] = |
{ |
0x00000000, // DB_DEPTH_CONTROL |
0x00000000, // DB_EQAA |
0x00000000, // CB_COLOR_CONTROL |
0x00000000, // DB_SHADER_CONTROL |
0x00090000, // PA_CL_CLIP_CNTL |
0x00000004, // PA_SU_SC_MODE_CNTL |
0x00000000, // PA_CL_VTE_CNTL |
0x00000000, // PA_CL_VS_OUT_CNTL |
0x00000000, // PA_CL_NANINF_CNTL |
0x00000000, // PA_SU_LINE_STIPPLE_CNTL |
0x00000000, // PA_SU_LINE_STIPPLE_SCALE |
0x00000000, // PA_SU_PRIM_FILTER_CNTL |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // PA_SU_POINT_SIZE |
0x00000000, // PA_SU_POINT_MINMAX |
0x00000000, // PA_SU_LINE_CNTL |
0x00000000, // PA_SC_LINE_STIPPLE |
0x00000000, // VGT_OUTPUT_PATH_CNTL |
0x00000000, // VGT_HOS_CNTL |
0x00000000, // VGT_HOS_MAX_TESS_LEVEL |
0x00000000, // VGT_HOS_MIN_TESS_LEVEL |
0x00000000, // VGT_HOS_REUSE_DEPTH |
0x00000000, // VGT_GROUP_PRIM_TYPE |
0x00000000, // VGT_GROUP_FIRST_DECR |
0x00000000, // VGT_GROUP_DECR |
0x00000000, // VGT_GROUP_VECT_0_CNTL |
0x00000000, // VGT_GROUP_VECT_1_CNTL |
0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL |
0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL |
0x00000000, // VGT_GS_MODE |
0x00000000, // VGT_GS_ONCHIP_CNTL |
0x00000000, // PA_SC_MODE_CNTL_0 |
0x00000000, // PA_SC_MODE_CNTL_1 |
0x00000000, // VGT_ENHANCE |
0x00000100, // VGT_GS_PER_ES |
0x00000080, // VGT_ES_PER_GS |
0x00000002, // VGT_GS_PER_VS |
0x00000000, // VGT_GSVS_RING_OFFSET_1 |
0x00000000, // VGT_GSVS_RING_OFFSET_2 |
0x00000000, // VGT_GSVS_RING_OFFSET_3 |
0x00000000, // VGT_GS_OUT_PRIM_TYPE |
0x00000000, // IA_ENHANCE |
}; |
static const unsigned int ci_SECT_CONTEXT_def_5[] = |
{ |
0x00000000, // WD_ENHANCE |
0x00000000, // VGT_PRIMITIVEID_EN |
}; |
static const unsigned int ci_SECT_CONTEXT_def_6[] = |
{ |
0x00000000, // VGT_PRIMITIVEID_RESET |
}; |
static const unsigned int ci_SECT_CONTEXT_def_7[] = |
{ |
0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_INSTANCE_STEP_RATE_0 |
0x00000000, // VGT_INSTANCE_STEP_RATE_1 |
0x000000ff, // IA_MULTI_VGT_PARAM |
0x00000000, // VGT_ESGS_RING_ITEMSIZE |
0x00000000, // VGT_GSVS_RING_ITEMSIZE |
0x00000000, // VGT_REUSE_OFF |
0x00000000, // VGT_VTX_CNT_EN |
0x00000000, // DB_HTILE_SURFACE |
0x00000000, // DB_SRESULTS_COMPARE_STATE0 |
0x00000000, // DB_SRESULTS_COMPARE_STATE1 |
0x00000000, // DB_PRELOAD_CONTROL |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_0 |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_1 |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_2 |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_3 |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3 |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE |
0, // HOLE |
0x00000000, // VGT_GS_MAX_VERT_OUT |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_SHADER_STAGES_EN |
0x00000000, // VGT_LS_HS_CONFIG |
0x00000000, // VGT_GS_VERT_ITEMSIZE |
0x00000000, // VGT_GS_VERT_ITEMSIZE_1 |
0x00000000, // VGT_GS_VERT_ITEMSIZE_2 |
0x00000000, // VGT_GS_VERT_ITEMSIZE_3 |
0x00000000, // VGT_TF_PARAM |
0x00000000, // DB_ALPHA_TO_MASK |
0, // HOLE |
0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL |
0x00000000, // PA_SU_POLY_OFFSET_CLAMP |
0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE |
0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET |
0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE |
0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET |
0x00000000, // VGT_GS_INSTANCE_CNT |
0x00000000, // VGT_STRMOUT_CONFIG |
0x00000000, // VGT_STRMOUT_BUFFER_CONFIG |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // PA_SC_CENTROID_PRIORITY_0 |
0x00000000, // PA_SC_CENTROID_PRIORITY_1 |
0x00001000, // PA_SC_LINE_CNTL |
0x00000000, // PA_SC_AA_CONFIG |
0x00000005, // PA_SU_VTX_CNTL |
0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ |
0x3f800000, // PA_CL_GB_VERT_DISC_ADJ |
0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ |
0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_3 |
0xffffffff, // PA_SC_AA_MASK_X0Y0_X1Y0 |
0xffffffff, // PA_SC_AA_MASK_X0Y1_X1Y1 |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x0000000e, // VGT_VERTEX_REUSE_BLOCK_CNTL |
0x00000010, // VGT_OUT_DEALLOC_CNTL |
0x00000000, // CB_COLOR0_BASE |
0x00000000, // CB_COLOR0_PITCH |
0x00000000, // CB_COLOR0_SLICE |
0x00000000, // CB_COLOR0_VIEW |
0x00000000, // CB_COLOR0_INFO |
0x00000000, // CB_COLOR0_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR0_CMASK |
0x00000000, // CB_COLOR0_CMASK_SLICE |
0x00000000, // CB_COLOR0_FMASK |
0x00000000, // CB_COLOR0_FMASK_SLICE |
0x00000000, // CB_COLOR0_CLEAR_WORD0 |
0x00000000, // CB_COLOR0_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR1_BASE |
0x00000000, // CB_COLOR1_PITCH |
0x00000000, // CB_COLOR1_SLICE |
0x00000000, // CB_COLOR1_VIEW |
0x00000000, // CB_COLOR1_INFO |
0x00000000, // CB_COLOR1_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR1_CMASK |
0x00000000, // CB_COLOR1_CMASK_SLICE |
0x00000000, // CB_COLOR1_FMASK |
0x00000000, // CB_COLOR1_FMASK_SLICE |
0x00000000, // CB_COLOR1_CLEAR_WORD0 |
0x00000000, // CB_COLOR1_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR2_BASE |
0x00000000, // CB_COLOR2_PITCH |
0x00000000, // CB_COLOR2_SLICE |
0x00000000, // CB_COLOR2_VIEW |
0x00000000, // CB_COLOR2_INFO |
0x00000000, // CB_COLOR2_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR2_CMASK |
0x00000000, // CB_COLOR2_CMASK_SLICE |
0x00000000, // CB_COLOR2_FMASK |
0x00000000, // CB_COLOR2_FMASK_SLICE |
0x00000000, // CB_COLOR2_CLEAR_WORD0 |
0x00000000, // CB_COLOR2_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR3_BASE |
0x00000000, // CB_COLOR3_PITCH |
0x00000000, // CB_COLOR3_SLICE |
0x00000000, // CB_COLOR3_VIEW |
0x00000000, // CB_COLOR3_INFO |
0x00000000, // CB_COLOR3_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR3_CMASK |
0x00000000, // CB_COLOR3_CMASK_SLICE |
0x00000000, // CB_COLOR3_FMASK |
0x00000000, // CB_COLOR3_FMASK_SLICE |
0x00000000, // CB_COLOR3_CLEAR_WORD0 |
0x00000000, // CB_COLOR3_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR4_BASE |
0x00000000, // CB_COLOR4_PITCH |
0x00000000, // CB_COLOR4_SLICE |
0x00000000, // CB_COLOR4_VIEW |
0x00000000, // CB_COLOR4_INFO |
0x00000000, // CB_COLOR4_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR4_CMASK |
0x00000000, // CB_COLOR4_CMASK_SLICE |
0x00000000, // CB_COLOR4_FMASK |
0x00000000, // CB_COLOR4_FMASK_SLICE |
0x00000000, // CB_COLOR4_CLEAR_WORD0 |
0x00000000, // CB_COLOR4_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR5_BASE |
0x00000000, // CB_COLOR5_PITCH |
0x00000000, // CB_COLOR5_SLICE |
0x00000000, // CB_COLOR5_VIEW |
0x00000000, // CB_COLOR5_INFO |
0x00000000, // CB_COLOR5_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR5_CMASK |
0x00000000, // CB_COLOR5_CMASK_SLICE |
0x00000000, // CB_COLOR5_FMASK |
0x00000000, // CB_COLOR5_FMASK_SLICE |
0x00000000, // CB_COLOR5_CLEAR_WORD0 |
0x00000000, // CB_COLOR5_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR6_BASE |
0x00000000, // CB_COLOR6_PITCH |
0x00000000, // CB_COLOR6_SLICE |
0x00000000, // CB_COLOR6_VIEW |
0x00000000, // CB_COLOR6_INFO |
0x00000000, // CB_COLOR6_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR6_CMASK |
0x00000000, // CB_COLOR6_CMASK_SLICE |
0x00000000, // CB_COLOR6_FMASK |
0x00000000, // CB_COLOR6_FMASK_SLICE |
0x00000000, // CB_COLOR6_CLEAR_WORD0 |
0x00000000, // CB_COLOR6_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR7_BASE |
0x00000000, // CB_COLOR7_PITCH |
0x00000000, // CB_COLOR7_SLICE |
0x00000000, // CB_COLOR7_VIEW |
0x00000000, // CB_COLOR7_INFO |
0x00000000, // CB_COLOR7_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR7_CMASK |
0x00000000, // CB_COLOR7_CMASK_SLICE |
0x00000000, // CB_COLOR7_FMASK |
0x00000000, // CB_COLOR7_FMASK_SLICE |
0x00000000, // CB_COLOR7_CLEAR_WORD0 |
0x00000000, // CB_COLOR7_CLEAR_WORD1 |
}; |
static const struct cs_extent_def ci_SECT_CONTEXT_defs[] = |
{ |
{ci_SECT_CONTEXT_def_1, 0x0000a000, 212 }, |
{ci_SECT_CONTEXT_def_2, 0x0000a0d6, 274 }, |
{ci_SECT_CONTEXT_def_3, 0x0000a1f5, 6 }, |
{ci_SECT_CONTEXT_def_4, 0x0000a200, 157 }, |
{ci_SECT_CONTEXT_def_5, 0x0000a2a0, 2 }, |
{ci_SECT_CONTEXT_def_6, 0x0000a2a3, 1 }, |
{ci_SECT_CONTEXT_def_7, 0x0000a2a5, 233 }, |
{ NULL, 0, 0 } |
}; |
static const struct cs_section_def ci_cs_data[] = { |
{ ci_SECT_CONTEXT_defs, SECT_CONTEXT }, |
{ NULL, SECT_NONE } |
}; |
/drivers/video/drm/radeon/clearstate_defs.h |
---|
0,0 → 1,44 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef CLEARSTATE_DEFS_H |
#define CLEARSTATE_DEFS_H |
enum section_id { |
SECT_NONE, |
SECT_CONTEXT, |
SECT_CLEAR, |
SECT_CTRLCONST |
}; |
struct cs_extent_def { |
const unsigned int *extent; |
const unsigned int reg_index; |
const unsigned int reg_count; |
}; |
struct cs_section_def { |
const struct cs_extent_def *section; |
const enum section_id id; |
}; |
#endif |
/drivers/video/drm/radeon/clearstate_evergreen.h |
---|
0,0 → 1,1080 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
static const u32 SECT_CONTEXT_def_1[] = |
{ |
0x00000000, // DB_RENDER_CONTROL |
0x00000000, // DB_COUNT_CONTROL |
0x00000000, // DB_DEPTH_VIEW |
0x00000000, // DB_RENDER_OVERRIDE |
0x00000000, // DB_RENDER_OVERRIDE2 |
0x00000000, // DB_HTILE_DATA_BASE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_STENCIL_CLEAR |
0x00000000, // DB_DEPTH_CLEAR |
0x00000000, // PA_SC_SCREEN_SCISSOR_TL |
0x40004000, // PA_SC_SCREEN_SCISSOR_BR |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_Z_INFO |
0x00000000, // DB_STENCIL_INFO |
0x00000000, // DB_Z_READ_BASE |
0x00000000, // DB_STENCIL_READ_BASE |
0x00000000, // DB_Z_WRITE_BASE |
0x00000000, // DB_STENCIL_WRITE_BASE |
0x00000000, // DB_DEPTH_SIZE |
0x00000000, // DB_DEPTH_SLICE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_15 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_15 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_15 |
0x00000000, // PA_SC_WINDOW_OFFSET |
0x80000000, // PA_SC_WINDOW_SCISSOR_TL |
0x40004000, // PA_SC_WINDOW_SCISSOR_BR |
0x0000ffff, // PA_SC_CLIPRECT_RULE |
0x00000000, // PA_SC_CLIPRECT_0_TL |
0x40004000, // PA_SC_CLIPRECT_0_BR |
0x00000000, // PA_SC_CLIPRECT_1_TL |
0x40004000, // PA_SC_CLIPRECT_1_BR |
0x00000000, // PA_SC_CLIPRECT_2_TL |
0x40004000, // PA_SC_CLIPRECT_2_BR |
0x00000000, // PA_SC_CLIPRECT_3_TL |
0x40004000, // PA_SC_CLIPRECT_3_BR |
0xaa99aaaa, // PA_SC_EDGERULE |
0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET |
0xffffffff, // CB_TARGET_MASK |
0xffffffff, // CB_SHADER_MASK |
0x80000000, // PA_SC_GENERIC_SCISSOR_TL |
0x40004000, // PA_SC_GENERIC_SCISSOR_BR |
0x00000000, // COHER_DEST_BASE_0 |
0x00000000, // COHER_DEST_BASE_1 |
0x80000000, // PA_SC_VPORT_SCISSOR_0_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_0_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_1_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_1_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_2_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_2_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_3_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_3_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_4_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_4_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_5_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_5_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_6_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_6_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_7_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_7_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_8_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_8_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_9_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_9_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_10_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_10_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_11_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_11_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_12_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_12_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_13_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_13_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_14_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_14_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_15_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_15_BR |
0x00000000, // PA_SC_VPORT_ZMIN_0 |
0x3f800000, // PA_SC_VPORT_ZMAX_0 |
0x00000000, // PA_SC_VPORT_ZMIN_1 |
0x3f800000, // PA_SC_VPORT_ZMAX_1 |
0x00000000, // PA_SC_VPORT_ZMIN_2 |
0x3f800000, // PA_SC_VPORT_ZMAX_2 |
0x00000000, // PA_SC_VPORT_ZMIN_3 |
0x3f800000, // PA_SC_VPORT_ZMAX_3 |
0x00000000, // PA_SC_VPORT_ZMIN_4 |
0x3f800000, // PA_SC_VPORT_ZMAX_4 |
0x00000000, // PA_SC_VPORT_ZMIN_5 |
0x3f800000, // PA_SC_VPORT_ZMAX_5 |
0x00000000, // PA_SC_VPORT_ZMIN_6 |
0x3f800000, // PA_SC_VPORT_ZMAX_6 |
0x00000000, // PA_SC_VPORT_ZMIN_7 |
0x3f800000, // PA_SC_VPORT_ZMAX_7 |
0x00000000, // PA_SC_VPORT_ZMIN_8 |
0x3f800000, // PA_SC_VPORT_ZMAX_8 |
0x00000000, // PA_SC_VPORT_ZMIN_9 |
0x3f800000, // PA_SC_VPORT_ZMAX_9 |
0x00000000, // PA_SC_VPORT_ZMIN_10 |
0x3f800000, // PA_SC_VPORT_ZMAX_10 |
0x00000000, // PA_SC_VPORT_ZMIN_11 |
0x3f800000, // PA_SC_VPORT_ZMAX_11 |
0x00000000, // PA_SC_VPORT_ZMIN_12 |
0x3f800000, // PA_SC_VPORT_ZMAX_12 |
0x00000000, // PA_SC_VPORT_ZMIN_13 |
0x3f800000, // PA_SC_VPORT_ZMAX_13 |
0x00000000, // PA_SC_VPORT_ZMIN_14 |
0x3f800000, // PA_SC_VPORT_ZMAX_14 |
0x00000000, // PA_SC_VPORT_ZMIN_15 |
0x3f800000, // PA_SC_VPORT_ZMAX_15 |
0x00000000, // SX_MISC |
0x00000000, // SX_SURFACE_SYNC |
0x00000000, // CP_PERFMON_CNTX_CNTL |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_VTX_SEMANTIC_0 |
0x00000000, // SQ_VTX_SEMANTIC_1 |
0x00000000, // SQ_VTX_SEMANTIC_2 |
0x00000000, // SQ_VTX_SEMANTIC_3 |
0x00000000, // SQ_VTX_SEMANTIC_4 |
0x00000000, // SQ_VTX_SEMANTIC_5 |
0x00000000, // SQ_VTX_SEMANTIC_6 |
0x00000000, // SQ_VTX_SEMANTIC_7 |
0x00000000, // SQ_VTX_SEMANTIC_8 |
0x00000000, // SQ_VTX_SEMANTIC_9 |
0x00000000, // SQ_VTX_SEMANTIC_10 |
0x00000000, // SQ_VTX_SEMANTIC_11 |
0x00000000, // SQ_VTX_SEMANTIC_12 |
0x00000000, // SQ_VTX_SEMANTIC_13 |
0x00000000, // SQ_VTX_SEMANTIC_14 |
0x00000000, // SQ_VTX_SEMANTIC_15 |
0x00000000, // SQ_VTX_SEMANTIC_16 |
0x00000000, // SQ_VTX_SEMANTIC_17 |
0x00000000, // SQ_VTX_SEMANTIC_18 |
0x00000000, // SQ_VTX_SEMANTIC_19 |
0x00000000, // SQ_VTX_SEMANTIC_20 |
0x00000000, // SQ_VTX_SEMANTIC_21 |
0x00000000, // SQ_VTX_SEMANTIC_22 |
0x00000000, // SQ_VTX_SEMANTIC_23 |
0x00000000, // SQ_VTX_SEMANTIC_24 |
0x00000000, // SQ_VTX_SEMANTIC_25 |
0x00000000, // SQ_VTX_SEMANTIC_26 |
0x00000000, // SQ_VTX_SEMANTIC_27 |
0x00000000, // SQ_VTX_SEMANTIC_28 |
0x00000000, // SQ_VTX_SEMANTIC_29 |
0x00000000, // SQ_VTX_SEMANTIC_30 |
0x00000000, // SQ_VTX_SEMANTIC_31 |
0xffffffff, // VGT_MAX_VTX_INDX |
0x00000000, // VGT_MIN_VTX_INDX |
0x00000000, // VGT_INDX_OFFSET |
0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX |
0x00000000, // SX_ALPHA_TEST_CONTROL |
0x00000000, // CB_BLEND_RED |
0x00000000, // CB_BLEND_GREEN |
0x00000000, // CB_BLEND_BLUE |
0x00000000, // CB_BLEND_ALPHA |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_STENCILREFMASK |
0x00000000, // DB_STENCILREFMASK_BF |
0x00000000, // SX_ALPHA_REF |
0x00000000, // PA_CL_VPORT_XSCALE |
0x00000000, // PA_CL_VPORT_XOFFSET |
0x00000000, // PA_CL_VPORT_YSCALE |
0x00000000, // PA_CL_VPORT_YOFFSET |
0x00000000, // PA_CL_VPORT_ZSCALE |
0x00000000, // PA_CL_VPORT_ZOFFSET |
0x00000000, // PA_CL_VPORT_XSCALE_1 |
0x00000000, // PA_CL_VPORT_XOFFSET_1 |
0x00000000, // PA_CL_VPORT_YSCALE_1 |
0x00000000, // PA_CL_VPORT_YOFFSET_1 |
0x00000000, // PA_CL_VPORT_ZSCALE_1 |
0x00000000, // PA_CL_VPORT_ZOFFSET_1 |
0x00000000, // PA_CL_VPORT_XSCALE_2 |
0x00000000, // PA_CL_VPORT_XOFFSET_2 |
0x00000000, // PA_CL_VPORT_YSCALE_2 |
0x00000000, // PA_CL_VPORT_YOFFSET_2 |
0x00000000, // PA_CL_VPORT_ZSCALE_2 |
0x00000000, // PA_CL_VPORT_ZOFFSET_2 |
0x00000000, // PA_CL_VPORT_XSCALE_3 |
0x00000000, // PA_CL_VPORT_XOFFSET_3 |
0x00000000, // PA_CL_VPORT_YSCALE_3 |
0x00000000, // PA_CL_VPORT_YOFFSET_3 |
0x00000000, // PA_CL_VPORT_ZSCALE_3 |
0x00000000, // PA_CL_VPORT_ZOFFSET_3 |
0x00000000, // PA_CL_VPORT_XSCALE_4 |
0x00000000, // PA_CL_VPORT_XOFFSET_4 |
0x00000000, // PA_CL_VPORT_YSCALE_4 |
0x00000000, // PA_CL_VPORT_YOFFSET_4 |
0x00000000, // PA_CL_VPORT_ZSCALE_4 |
0x00000000, // PA_CL_VPORT_ZOFFSET_4 |
0x00000000, // PA_CL_VPORT_XSCALE_5 |
0x00000000, // PA_CL_VPORT_XOFFSET_5 |
0x00000000, // PA_CL_VPORT_YSCALE_5 |
0x00000000, // PA_CL_VPORT_YOFFSET_5 |
0x00000000, // PA_CL_VPORT_ZSCALE_5 |
0x00000000, // PA_CL_VPORT_ZOFFSET_5 |
0x00000000, // PA_CL_VPORT_XSCALE_6 |
0x00000000, // PA_CL_VPORT_XOFFSET_6 |
0x00000000, // PA_CL_VPORT_YSCALE_6 |
0x00000000, // PA_CL_VPORT_YOFFSET_6 |
0x00000000, // PA_CL_VPORT_ZSCALE_6 |
0x00000000, // PA_CL_VPORT_ZOFFSET_6 |
0x00000000, // PA_CL_VPORT_XSCALE_7 |
0x00000000, // PA_CL_VPORT_XOFFSET_7 |
0x00000000, // PA_CL_VPORT_YSCALE_7 |
0x00000000, // PA_CL_VPORT_YOFFSET_7 |
0x00000000, // PA_CL_VPORT_ZSCALE_7 |
0x00000000, // PA_CL_VPORT_ZOFFSET_7 |
0x00000000, // PA_CL_VPORT_XSCALE_8 |
0x00000000, // PA_CL_VPORT_XOFFSET_8 |
0x00000000, // PA_CL_VPORT_YSCALE_8 |
0x00000000, // PA_CL_VPORT_YOFFSET_8 |
0x00000000, // PA_CL_VPORT_ZSCALE_8 |
0x00000000, // PA_CL_VPORT_ZOFFSET_8 |
0x00000000, // PA_CL_VPORT_XSCALE_9 |
0x00000000, // PA_CL_VPORT_XOFFSET_9 |
0x00000000, // PA_CL_VPORT_YSCALE_9 |
0x00000000, // PA_CL_VPORT_YOFFSET_9 |
0x00000000, // PA_CL_VPORT_ZSCALE_9 |
0x00000000, // PA_CL_VPORT_ZOFFSET_9 |
0x00000000, // PA_CL_VPORT_XSCALE_10 |
0x00000000, // PA_CL_VPORT_XOFFSET_10 |
0x00000000, // PA_CL_VPORT_YSCALE_10 |
0x00000000, // PA_CL_VPORT_YOFFSET_10 |
0x00000000, // PA_CL_VPORT_ZSCALE_10 |
0x00000000, // PA_CL_VPORT_ZOFFSET_10 |
0x00000000, // PA_CL_VPORT_XSCALE_11 |
0x00000000, // PA_CL_VPORT_XOFFSET_11 |
0x00000000, // PA_CL_VPORT_YSCALE_11 |
0x00000000, // PA_CL_VPORT_YOFFSET_11 |
0x00000000, // PA_CL_VPORT_ZSCALE_11 |
0x00000000, // PA_CL_VPORT_ZOFFSET_11 |
0x00000000, // PA_CL_VPORT_XSCALE_12 |
0x00000000, // PA_CL_VPORT_XOFFSET_12 |
0x00000000, // PA_CL_VPORT_YSCALE_12 |
0x00000000, // PA_CL_VPORT_YOFFSET_12 |
0x00000000, // PA_CL_VPORT_ZSCALE_12 |
0x00000000, // PA_CL_VPORT_ZOFFSET_12 |
0x00000000, // PA_CL_VPORT_XSCALE_13 |
0x00000000, // PA_CL_VPORT_XOFFSET_13 |
0x00000000, // PA_CL_VPORT_YSCALE_13 |
0x00000000, // PA_CL_VPORT_YOFFSET_13 |
0x00000000, // PA_CL_VPORT_ZSCALE_13 |
0x00000000, // PA_CL_VPORT_ZOFFSET_13 |
0x00000000, // PA_CL_VPORT_XSCALE_14 |
0x00000000, // PA_CL_VPORT_XOFFSET_14 |
0x00000000, // PA_CL_VPORT_YSCALE_14 |
0x00000000, // PA_CL_VPORT_YOFFSET_14 |
0x00000000, // PA_CL_VPORT_ZSCALE_14 |
0x00000000, // PA_CL_VPORT_ZOFFSET_14 |
0x00000000, // PA_CL_VPORT_XSCALE_15 |
0x00000000, // PA_CL_VPORT_XOFFSET_15 |
0x00000000, // PA_CL_VPORT_YSCALE_15 |
0x00000000, // PA_CL_VPORT_YOFFSET_15 |
0x00000000, // PA_CL_VPORT_ZSCALE_15 |
0x00000000, // PA_CL_VPORT_ZOFFSET_15 |
0x00000000, // PA_CL_UCP_0_X |
0x00000000, // PA_CL_UCP_0_Y |
0x00000000, // PA_CL_UCP_0_Z |
0x00000000, // PA_CL_UCP_0_W |
0x00000000, // PA_CL_UCP_1_X |
0x00000000, // PA_CL_UCP_1_Y |
0x00000000, // PA_CL_UCP_1_Z |
0x00000000, // PA_CL_UCP_1_W |
0x00000000, // PA_CL_UCP_2_X |
0x00000000, // PA_CL_UCP_2_Y |
0x00000000, // PA_CL_UCP_2_Z |
0x00000000, // PA_CL_UCP_2_W |
0x00000000, // PA_CL_UCP_3_X |
0x00000000, // PA_CL_UCP_3_Y |
0x00000000, // PA_CL_UCP_3_Z |
0x00000000, // PA_CL_UCP_3_W |
0x00000000, // PA_CL_UCP_4_X |
0x00000000, // PA_CL_UCP_4_Y |
0x00000000, // PA_CL_UCP_4_Z |
0x00000000, // PA_CL_UCP_4_W |
0x00000000, // PA_CL_UCP_5_X |
0x00000000, // PA_CL_UCP_5_Y |
0x00000000, // PA_CL_UCP_5_Z |
0x00000000, // PA_CL_UCP_5_W |
0x00000000, // SPI_VS_OUT_ID_0 |
0x00000000, // SPI_VS_OUT_ID_1 |
0x00000000, // SPI_VS_OUT_ID_2 |
0x00000000, // SPI_VS_OUT_ID_3 |
0x00000000, // SPI_VS_OUT_ID_4 |
0x00000000, // SPI_VS_OUT_ID_5 |
0x00000000, // SPI_VS_OUT_ID_6 |
0x00000000, // SPI_VS_OUT_ID_7 |
0x00000000, // SPI_VS_OUT_ID_8 |
0x00000000, // SPI_VS_OUT_ID_9 |
0x00000000, // SPI_PS_INPUT_CNTL_0 |
0x00000000, // SPI_PS_INPUT_CNTL_1 |
0x00000000, // SPI_PS_INPUT_CNTL_2 |
0x00000000, // SPI_PS_INPUT_CNTL_3 |
0x00000000, // SPI_PS_INPUT_CNTL_4 |
0x00000000, // SPI_PS_INPUT_CNTL_5 |
0x00000000, // SPI_PS_INPUT_CNTL_6 |
0x00000000, // SPI_PS_INPUT_CNTL_7 |
0x00000000, // SPI_PS_INPUT_CNTL_8 |
0x00000000, // SPI_PS_INPUT_CNTL_9 |
0x00000000, // SPI_PS_INPUT_CNTL_10 |
0x00000000, // SPI_PS_INPUT_CNTL_11 |
0x00000000, // SPI_PS_INPUT_CNTL_12 |
0x00000000, // SPI_PS_INPUT_CNTL_13 |
0x00000000, // SPI_PS_INPUT_CNTL_14 |
0x00000000, // SPI_PS_INPUT_CNTL_15 |
0x00000000, // SPI_PS_INPUT_CNTL_16 |
0x00000000, // SPI_PS_INPUT_CNTL_17 |
0x00000000, // SPI_PS_INPUT_CNTL_18 |
0x00000000, // SPI_PS_INPUT_CNTL_19 |
0x00000000, // SPI_PS_INPUT_CNTL_20 |
0x00000000, // SPI_PS_INPUT_CNTL_21 |
0x00000000, // SPI_PS_INPUT_CNTL_22 |
0x00000000, // SPI_PS_INPUT_CNTL_23 |
0x00000000, // SPI_PS_INPUT_CNTL_24 |
0x00000000, // SPI_PS_INPUT_CNTL_25 |
0x00000000, // SPI_PS_INPUT_CNTL_26 |
0x00000000, // SPI_PS_INPUT_CNTL_27 |
0x00000000, // SPI_PS_INPUT_CNTL_28 |
0x00000000, // SPI_PS_INPUT_CNTL_29 |
0x00000000, // SPI_PS_INPUT_CNTL_30 |
0x00000000, // SPI_PS_INPUT_CNTL_31 |
0x00000000, // SPI_VS_OUT_CONFIG |
0x00000001, // SPI_THREAD_GROUPING |
0x00000000, // SPI_PS_IN_CONTROL_0 |
0x00000000, // SPI_PS_IN_CONTROL_1 |
0x00000000, // SPI_INTERP_CONTROL_0 |
0x00000000, // SPI_INPUT_Z |
0x00000000, // SPI_FOG_CNTL |
0x00000000, // SPI_BARYC_CNTL |
0x00000000, // SPI_PS_IN_CONTROL_2 |
0x00000000, // SPI_COMPUTE_INPUT_CNTL |
0x00000000, // SPI_COMPUTE_NUM_THREAD_X |
0x00000000, // SPI_COMPUTE_NUM_THREAD_Y |
0x00000000, // SPI_COMPUTE_NUM_THREAD_Z |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // GDS_ADDR_BASE |
0x00003fff, // GDS_ADDR_SIZE |
0x00000001, // GDS_ORDERED_WAVE_PER_SE |
0x00000000, // GDS_APPEND_CONSUME_UAV0 |
0x00000000, // GDS_APPEND_CONSUME_UAV1 |
0x00000000, // GDS_APPEND_CONSUME_UAV2 |
0x00000000, // GDS_APPEND_CONSUME_UAV3 |
0x00000000, // GDS_APPEND_CONSUME_UAV4 |
0x00000000, // GDS_APPEND_CONSUME_UAV5 |
0x00000000, // GDS_APPEND_CONSUME_UAV6 |
0x00000000, // GDS_APPEND_CONSUME_UAV7 |
0x00000000, // GDS_APPEND_CONSUME_UAV8 |
0x00000000, // GDS_APPEND_CONSUME_UAV9 |
0x00000000, // GDS_APPEND_CONSUME_UAV10 |
0x00000000, // GDS_APPEND_CONSUME_UAV11 |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_BLEND0_CONTROL |
0x00000000, // CB_BLEND1_CONTROL |
0x00000000, // CB_BLEND2_CONTROL |
0x00000000, // CB_BLEND3_CONTROL |
0x00000000, // CB_BLEND4_CONTROL |
0x00000000, // CB_BLEND5_CONTROL |
0x00000000, // CB_BLEND6_CONTROL |
0x00000000, // CB_BLEND7_CONTROL |
}; |
static const u32 SECT_CONTEXT_def_2[] = |
{ |
0x00000000, // PA_CL_POINT_X_RAD |
0x00000000, // PA_CL_POINT_Y_RAD |
0x00000000, // PA_CL_POINT_SIZE |
0x00000000, // PA_CL_POINT_CULL_RAD |
0x00000000, // VGT_DMA_BASE_HI |
0x00000000, // VGT_DMA_BASE |
}; |
static const u32 SECT_CONTEXT_def_3[] = |
{ |
0x00000000, // DB_DEPTH_CONTROL |
0, // HOLE |
0x00000000, // CB_COLOR_CONTROL |
0x00000200, // DB_SHADER_CONTROL |
0x00000000, // PA_CL_CLIP_CNTL |
0x00000000, // PA_SU_SC_MODE_CNTL |
0x00000000, // PA_CL_VTE_CNTL |
0x00000000, // PA_CL_VS_OUT_CNTL |
0x00000000, // PA_CL_NANINF_CNTL |
0x00000000, // PA_SU_LINE_STIPPLE_CNTL |
0x00000000, // PA_SU_LINE_STIPPLE_SCALE |
0x00000000, // PA_SU_PRIM_FILTER_CNTL |
0x00000000, // SQ_LSTMP_RING_ITEMSIZE |
0x00000000, // SQ_HSTMP_RING_ITEMSIZE |
0x00000000, // SQ_DYN_GPR_RESOURCE_LIMIT_1 |
0, // HOLE |
0x00000000, // SQ_PGM_START_PS |
0x00000000, // SQ_PGM_RESOURCES_PS |
0x00000000, // SQ_PGM_RESOURCES_2_PS |
0x00000000, // SQ_PGM_EXPORTS_PS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_VS |
0x00000000, // SQ_PGM_RESOURCES_VS |
0x00000000, // SQ_PGM_RESOURCES_2_VS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_GS |
0x00000000, // SQ_PGM_RESOURCES_GS |
0x00000000, // SQ_PGM_RESOURCES_2_GS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_ES |
0x00000000, // SQ_PGM_RESOURCES_ES |
0x00000000, // SQ_PGM_RESOURCES_2_ES |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_FS |
0x00000000, // SQ_PGM_RESOURCES_FS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_HS |
0x00000000, // SQ_PGM_RESOURCES_HS |
0x00000000, // SQ_PGM_RESOURCES_2_HS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_PGM_START_LS |
0x00000000, // SQ_PGM_RESOURCES_LS |
0x00000000, // SQ_PGM_RESOURCES_2_LS |
}; |
static const u32 SECT_CONTEXT_def_4[] = |
{ |
0x00000000, // SQ_LDS_ALLOC |
0x00000000, // SQ_LDS_ALLOC_PS |
0x00000000, // SQ_VTX_SEMANTIC_CLEAR |
0, // HOLE |
0x00000000, // SQ_THREAD_TRACE_CTRL |
0, // HOLE |
0x00000000, // SQ_ESGS_RING_ITEMSIZE |
0x00000000, // SQ_GSVS_RING_ITEMSIZE |
0x00000000, // SQ_ESTMP_RING_ITEMSIZE |
0x00000000, // SQ_GSTMP_RING_ITEMSIZE |
0x00000000, // SQ_VSTMP_RING_ITEMSIZE |
0x00000000, // SQ_PSTMP_RING_ITEMSIZE |
0, // HOLE |
0x00000000, // SQ_GS_VERT_ITEMSIZE |
0x00000000, // SQ_GS_VERT_ITEMSIZE_1 |
0x00000000, // SQ_GS_VERT_ITEMSIZE_2 |
0x00000000, // SQ_GS_VERT_ITEMSIZE_3 |
0x00000000, // SQ_GSVS_RING_OFFSET_1 |
0x00000000, // SQ_GSVS_RING_OFFSET_2 |
0x00000000, // SQ_GSVS_RING_OFFSET_3 |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_ALU_CONST_CACHE_PS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_PS_15 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_VS_15 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_GS_15 |
0x00000000, // PA_SU_POINT_SIZE |
0x00000000, // PA_SU_POINT_MINMAX |
0x00000000, // PA_SU_LINE_CNTL |
0x00000000, // PA_SC_LINE_STIPPLE |
0x00000000, // VGT_OUTPUT_PATH_CNTL |
0x00000000, // VGT_HOS_CNTL |
0x00000000, // VGT_HOS_MAX_TESS_LEVEL |
0x00000000, // VGT_HOS_MIN_TESS_LEVEL |
0x00000000, // VGT_HOS_REUSE_DEPTH |
0x00000000, // VGT_GROUP_PRIM_TYPE |
0x00000000, // VGT_GROUP_FIRST_DECR |
0x00000000, // VGT_GROUP_DECR |
0x00000000, // VGT_GROUP_VECT_0_CNTL |
0x00000000, // VGT_GROUP_VECT_1_CNTL |
0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL |
0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL |
0x00000000, // VGT_GS_MODE |
0, // HOLE |
0x00000000, // PA_SC_MODE_CNTL_0 |
0x00000000, // PA_SC_MODE_CNTL_1 |
0x00000000, // VGT_ENHANCE |
0x00000000, // VGT_GS_PER_ES |
0x00000000, // VGT_ES_PER_GS |
0x00000000, // VGT_GS_PER_VS |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_GS_OUT_PRIM_TYPE |
}; |
static const u32 SECT_CONTEXT_def_5[] = |
{ |
0x00000000, // VGT_DMA_MAX_SIZE |
0x00000000, // VGT_DMA_INDEX_TYPE |
0, // HOLE |
0x00000000, // VGT_PRIMITIVEID_EN |
0x00000000, // VGT_DMA_NUM_INSTANCES |
}; |
static const u32 SECT_CONTEXT_def_6[] = |
{ |
0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_INSTANCE_STEP_RATE_0 |
0x00000000, // VGT_INSTANCE_STEP_RATE_1 |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_REUSE_OFF |
0x00000000, // VGT_VTX_CNT_EN |
0x00000000, // DB_HTILE_SURFACE |
0x00000000, // DB_SRESULTS_COMPARE_STATE0 |
0x00000000, // DB_SRESULTS_COMPARE_STATE1 |
0x00000000, // DB_PRELOAD_CONTROL |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_0 |
0x00000000, // VGT_STRMOUT_BUFFER_BASE_0 |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_1 |
0x00000000, // VGT_STRMOUT_BUFFER_BASE_1 |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_2 |
0x00000000, // VGT_STRMOUT_BUFFER_BASE_2 |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_3 |
0x00000000, // VGT_STRMOUT_BUFFER_BASE_3 |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_0 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_1 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_2 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_3 |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE |
0, // HOLE |
0x00000000, // VGT_GS_MAX_VERT_OUT |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_0 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_1 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_2 |
0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_3 |
0x00000000, // VGT_SHADER_STAGES_EN |
0x00000000, // VGT_LS_HS_CONFIG |
0x00000000, // VGT_LS_SIZE |
0x00000000, // VGT_HS_SIZE |
0x00000000, // VGT_LS_HS_ALLOC |
0x00000000, // VGT_HS_PATCH_CONST |
0x00000000, // VGT_TF_PARAM |
0x00000000, // DB_ALPHA_TO_MASK |
}; |
static const u32 SECT_CONTEXT_def_7[] = |
{ |
0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL |
0x00000000, // PA_SU_POLY_OFFSET_CLAMP |
0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE |
0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET |
0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE |
0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET |
0x00000000, // VGT_GS_INSTANCE_CNT |
0x00000000, // VGT_STRMOUT_CONFIG |
0x00000000, // VGT_STRMOUT_BUFFER_CONFIG |
0x00000000, // CB_IMMED0_BASE |
0x00000000, // CB_IMMED1_BASE |
0x00000000, // CB_IMMED2_BASE |
0x00000000, // CB_IMMED3_BASE |
0x00000000, // CB_IMMED4_BASE |
0x00000000, // CB_IMMED5_BASE |
0x00000000, // CB_IMMED6_BASE |
0x00000000, // CB_IMMED7_BASE |
0x00000000, // CB_IMMED8_BASE |
0x00000000, // CB_IMMED9_BASE |
0x00000000, // CB_IMMED10_BASE |
0x00000000, // CB_IMMED11_BASE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00001000, // PA_SC_LINE_CNTL |
0x00000000, // PA_SC_AA_CONFIG |
0x00000005, // PA_SU_VTX_CNTL |
0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ |
0x3f800000, // PA_CL_GB_VERT_DISC_ADJ |
0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ |
0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_4 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_5 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_6 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_7 |
0xffffffff, // PA_SC_AA_MASK |
0x00000000, // CB_CLRCMP_CONTROL |
0x00000000, // CB_CLRCMP_SRC |
0x00000000, // CB_CLRCMP_DST |
0x00000000, // CB_CLRCMP_MSK |
0, // HOLE |
0, // HOLE |
0x0000000e, // VGT_VERTEX_REUSE_BLOCK_CNTL |
0x00000010, // VGT_OUT_DEALLOC_CNTL |
0x00000000, // CB_COLOR0_BASE |
0x00000000, // CB_COLOR0_PITCH |
0x00000000, // CB_COLOR0_SLICE |
0x00000000, // CB_COLOR0_VIEW |
0x00000000, // CB_COLOR0_INFO |
0x00000000, // CB_COLOR0_ATTRIB |
0x00000000, // CB_COLOR0_DIM |
0x00000000, // CB_COLOR0_CMASK |
0x00000000, // CB_COLOR0_CMASK_SLICE |
0x00000000, // CB_COLOR0_FMASK |
0x00000000, // CB_COLOR0_FMASK_SLICE |
0x00000000, // CB_COLOR0_CLEAR_WORD0 |
0x00000000, // CB_COLOR0_CLEAR_WORD1 |
0x00000000, // CB_COLOR0_CLEAR_WORD2 |
0x00000000, // CB_COLOR0_CLEAR_WORD3 |
0x00000000, // CB_COLOR1_BASE |
0x00000000, // CB_COLOR1_PITCH |
0x00000000, // CB_COLOR1_SLICE |
0x00000000, // CB_COLOR1_VIEW |
0x00000000, // CB_COLOR1_INFO |
0x00000000, // CB_COLOR1_ATTRIB |
0x00000000, // CB_COLOR1_DIM |
0x00000000, // CB_COLOR1_CMASK |
0x00000000, // CB_COLOR1_CMASK_SLICE |
0x00000000, // CB_COLOR1_FMASK |
0x00000000, // CB_COLOR1_FMASK_SLICE |
0x00000000, // CB_COLOR1_CLEAR_WORD0 |
0x00000000, // CB_COLOR1_CLEAR_WORD1 |
0x00000000, // CB_COLOR1_CLEAR_WORD2 |
0x00000000, // CB_COLOR1_CLEAR_WORD3 |
0x00000000, // CB_COLOR2_BASE |
0x00000000, // CB_COLOR2_PITCH |
0x00000000, // CB_COLOR2_SLICE |
0x00000000, // CB_COLOR2_VIEW |
0x00000000, // CB_COLOR2_INFO |
0x00000000, // CB_COLOR2_ATTRIB |
0x00000000, // CB_COLOR2_DIM |
0x00000000, // CB_COLOR2_CMASK |
0x00000000, // CB_COLOR2_CMASK_SLICE |
0x00000000, // CB_COLOR2_FMASK |
0x00000000, // CB_COLOR2_FMASK_SLICE |
0x00000000, // CB_COLOR2_CLEAR_WORD0 |
0x00000000, // CB_COLOR2_CLEAR_WORD1 |
0x00000000, // CB_COLOR2_CLEAR_WORD2 |
0x00000000, // CB_COLOR2_CLEAR_WORD3 |
0x00000000, // CB_COLOR3_BASE |
0x00000000, // CB_COLOR3_PITCH |
0x00000000, // CB_COLOR3_SLICE |
0x00000000, // CB_COLOR3_VIEW |
0x00000000, // CB_COLOR3_INFO |
0x00000000, // CB_COLOR3_ATTRIB |
0x00000000, // CB_COLOR3_DIM |
0x00000000, // CB_COLOR3_CMASK |
0x00000000, // CB_COLOR3_CMASK_SLICE |
0x00000000, // CB_COLOR3_FMASK |
0x00000000, // CB_COLOR3_FMASK_SLICE |
0x00000000, // CB_COLOR3_CLEAR_WORD0 |
0x00000000, // CB_COLOR3_CLEAR_WORD1 |
0x00000000, // CB_COLOR3_CLEAR_WORD2 |
0x00000000, // CB_COLOR3_CLEAR_WORD3 |
0x00000000, // CB_COLOR4_BASE |
0x00000000, // CB_COLOR4_PITCH |
0x00000000, // CB_COLOR4_SLICE |
0x00000000, // CB_COLOR4_VIEW |
0x00000000, // CB_COLOR4_INFO |
0x00000000, // CB_COLOR4_ATTRIB |
0x00000000, // CB_COLOR4_DIM |
0x00000000, // CB_COLOR4_CMASK |
0x00000000, // CB_COLOR4_CMASK_SLICE |
0x00000000, // CB_COLOR4_FMASK |
0x00000000, // CB_COLOR4_FMASK_SLICE |
0x00000000, // CB_COLOR4_CLEAR_WORD0 |
0x00000000, // CB_COLOR4_CLEAR_WORD1 |
0x00000000, // CB_COLOR4_CLEAR_WORD2 |
0x00000000, // CB_COLOR4_CLEAR_WORD3 |
0x00000000, // CB_COLOR5_BASE |
0x00000000, // CB_COLOR5_PITCH |
0x00000000, // CB_COLOR5_SLICE |
0x00000000, // CB_COLOR5_VIEW |
0x00000000, // CB_COLOR5_INFO |
0x00000000, // CB_COLOR5_ATTRIB |
0x00000000, // CB_COLOR5_DIM |
0x00000000, // CB_COLOR5_CMASK |
0x00000000, // CB_COLOR5_CMASK_SLICE |
0x00000000, // CB_COLOR5_FMASK |
0x00000000, // CB_COLOR5_FMASK_SLICE |
0x00000000, // CB_COLOR5_CLEAR_WORD0 |
0x00000000, // CB_COLOR5_CLEAR_WORD1 |
0x00000000, // CB_COLOR5_CLEAR_WORD2 |
0x00000000, // CB_COLOR5_CLEAR_WORD3 |
0x00000000, // CB_COLOR6_BASE |
0x00000000, // CB_COLOR6_PITCH |
0x00000000, // CB_COLOR6_SLICE |
0x00000000, // CB_COLOR6_VIEW |
0x00000000, // CB_COLOR6_INFO |
0x00000000, // CB_COLOR6_ATTRIB |
0x00000000, // CB_COLOR6_DIM |
0x00000000, // CB_COLOR6_CMASK |
0x00000000, // CB_COLOR6_CMASK_SLICE |
0x00000000, // CB_COLOR6_FMASK |
0x00000000, // CB_COLOR6_FMASK_SLICE |
0x00000000, // CB_COLOR6_CLEAR_WORD0 |
0x00000000, // CB_COLOR6_CLEAR_WORD1 |
0x00000000, // CB_COLOR6_CLEAR_WORD2 |
0x00000000, // CB_COLOR6_CLEAR_WORD3 |
0x00000000, // CB_COLOR7_BASE |
0x00000000, // CB_COLOR7_PITCH |
0x00000000, // CB_COLOR7_SLICE |
0x00000000, // CB_COLOR7_VIEW |
0x00000000, // CB_COLOR7_INFO |
0x00000000, // CB_COLOR7_ATTRIB |
0x00000000, // CB_COLOR7_DIM |
0x00000000, // CB_COLOR7_CMASK |
0x00000000, // CB_COLOR7_CMASK_SLICE |
0x00000000, // CB_COLOR7_FMASK |
0x00000000, // CB_COLOR7_FMASK_SLICE |
0x00000000, // CB_COLOR7_CLEAR_WORD0 |
0x00000000, // CB_COLOR7_CLEAR_WORD1 |
0x00000000, // CB_COLOR7_CLEAR_WORD2 |
0x00000000, // CB_COLOR7_CLEAR_WORD3 |
0x00000000, // CB_COLOR8_BASE |
0x00000000, // CB_COLOR8_PITCH |
0x00000000, // CB_COLOR8_SLICE |
0x00000000, // CB_COLOR8_VIEW |
0x00000000, // CB_COLOR8_INFO |
0x00000000, // CB_COLOR8_ATTRIB |
0x00000000, // CB_COLOR8_DIM |
0x00000000, // CB_COLOR9_BASE |
0x00000000, // CB_COLOR9_PITCH |
0x00000000, // CB_COLOR9_SLICE |
0x00000000, // CB_COLOR9_VIEW |
0x00000000, // CB_COLOR9_INFO |
0x00000000, // CB_COLOR9_ATTRIB |
0x00000000, // CB_COLOR9_DIM |
0x00000000, // CB_COLOR10_BASE |
0x00000000, // CB_COLOR10_PITCH |
0x00000000, // CB_COLOR10_SLICE |
0x00000000, // CB_COLOR10_VIEW |
0x00000000, // CB_COLOR10_INFO |
0x00000000, // CB_COLOR10_ATTRIB |
0x00000000, // CB_COLOR10_DIM |
0x00000000, // CB_COLOR11_BASE |
0x00000000, // CB_COLOR11_PITCH |
0x00000000, // CB_COLOR11_SLICE |
0x00000000, // CB_COLOR11_VIEW |
0x00000000, // CB_COLOR11_INFO |
0x00000000, // CB_COLOR11_ATTRIB |
0x00000000, // CB_COLOR11_DIM |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SQ_ALU_CONST_CACHE_HS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_HS_15 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_0 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_1 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_2 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_3 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_4 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_5 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_6 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_7 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_8 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_9 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_10 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_11 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_12 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_13 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_14 |
0x00000000, // SQ_ALU_CONST_CACHE_LS_15 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_15 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_0 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_1 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_2 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_3 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_4 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_5 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_6 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_7 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_8 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_9 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_10 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_11 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_12 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_13 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_14 |
0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_15 |
}; |
static const struct cs_extent_def SECT_CONTEXT_defs[] = |
{ |
{SECT_CONTEXT_def_1, 0x0000a000, 488 }, |
{SECT_CONTEXT_def_2, 0x0000a1f5, 6 }, |
{SECT_CONTEXT_def_3, 0x0000a200, 55 }, |
{SECT_CONTEXT_def_4, 0x0000a23a, 98 }, |
{SECT_CONTEXT_def_5, 0x0000a29e, 5 }, |
{SECT_CONTEXT_def_6, 0x0000a2a5, 56 }, |
{SECT_CONTEXT_def_7, 0x0000a2de, 290 }, |
{ 0, 0, 0 } |
}; |
static const u32 SECT_CLEAR_def_1[] = |
{ |
0xffffffff, // SQ_TEX_SAMPLER_CLEAR |
0xffffffff, // SQ_TEX_RESOURCE_CLEAR |
0xffffffff, // SQ_LOOP_BOOL_CLEAR |
}; |
static const struct cs_extent_def SECT_CLEAR_defs[] = |
{ |
{SECT_CLEAR_def_1, 0x0000ffc0, 3 }, |
{ 0, 0, 0 } |
}; |
static const u32 SECT_CTRLCONST_def_1[] = |
{ |
0x00000000, // SQ_VTX_BASE_VTX_LOC |
0x00000000, // SQ_VTX_START_INST_LOC |
}; |
static const struct cs_extent_def SECT_CTRLCONST_defs[] = |
{ |
{SECT_CTRLCONST_def_1, 0x0000f3fc, 2 }, |
{ 0, 0, 0 } |
}; |
static const struct cs_section_def evergreen_cs_data[] = { |
{ SECT_CONTEXT_defs, SECT_CONTEXT }, |
{ SECT_CLEAR_defs, SECT_CLEAR }, |
{ SECT_CTRLCONST_defs, SECT_CTRLCONST }, |
{ 0, SECT_NONE } |
}; |
/drivers/video/drm/radeon/clearstate_si.h |
---|
0,0 → 1,941 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
static const u32 si_SECT_CONTEXT_def_1[] = |
{ |
0x00000000, // DB_RENDER_CONTROL |
0x00000000, // DB_COUNT_CONTROL |
0x00000000, // DB_DEPTH_VIEW |
0x00000000, // DB_RENDER_OVERRIDE |
0x00000000, // DB_RENDER_OVERRIDE2 |
0x00000000, // DB_HTILE_DATA_BASE |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_DEPTH_BOUNDS_MIN |
0x00000000, // DB_DEPTH_BOUNDS_MAX |
0x00000000, // DB_STENCIL_CLEAR |
0x00000000, // DB_DEPTH_CLEAR |
0x00000000, // PA_SC_SCREEN_SCISSOR_TL |
0x40004000, // PA_SC_SCREEN_SCISSOR_BR |
0, // HOLE |
0x00000000, // DB_DEPTH_INFO |
0x00000000, // DB_Z_INFO |
0x00000000, // DB_STENCIL_INFO |
0x00000000, // DB_Z_READ_BASE |
0x00000000, // DB_STENCIL_READ_BASE |
0x00000000, // DB_Z_WRITE_BASE |
0x00000000, // DB_STENCIL_WRITE_BASE |
0x00000000, // DB_DEPTH_SIZE |
0x00000000, // DB_DEPTH_SLICE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // TA_BC_BASE_ADDR |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // COHER_DEST_BASE_2 |
0x00000000, // COHER_DEST_BASE_3 |
0x00000000, // PA_SC_WINDOW_OFFSET |
0x80000000, // PA_SC_WINDOW_SCISSOR_TL |
0x40004000, // PA_SC_WINDOW_SCISSOR_BR |
0x0000ffff, // PA_SC_CLIPRECT_RULE |
0x00000000, // PA_SC_CLIPRECT_0_TL |
0x40004000, // PA_SC_CLIPRECT_0_BR |
0x00000000, // PA_SC_CLIPRECT_1_TL |
0x40004000, // PA_SC_CLIPRECT_1_BR |
0x00000000, // PA_SC_CLIPRECT_2_TL |
0x40004000, // PA_SC_CLIPRECT_2_BR |
0x00000000, // PA_SC_CLIPRECT_3_TL |
0x40004000, // PA_SC_CLIPRECT_3_BR |
0xaa99aaaa, // PA_SC_EDGERULE |
0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET |
0xffffffff, // CB_TARGET_MASK |
0xffffffff, // CB_SHADER_MASK |
0x80000000, // PA_SC_GENERIC_SCISSOR_TL |
0x40004000, // PA_SC_GENERIC_SCISSOR_BR |
0x00000000, // COHER_DEST_BASE_0 |
0x00000000, // COHER_DEST_BASE_1 |
0x80000000, // PA_SC_VPORT_SCISSOR_0_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_0_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_1_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_1_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_2_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_2_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_3_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_3_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_4_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_4_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_5_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_5_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_6_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_6_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_7_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_7_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_8_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_8_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_9_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_9_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_10_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_10_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_11_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_11_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_12_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_12_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_13_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_13_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_14_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_14_BR |
0x80000000, // PA_SC_VPORT_SCISSOR_15_TL |
0x40004000, // PA_SC_VPORT_SCISSOR_15_BR |
0x00000000, // PA_SC_VPORT_ZMIN_0 |
0x3f800000, // PA_SC_VPORT_ZMAX_0 |
0x00000000, // PA_SC_VPORT_ZMIN_1 |
0x3f800000, // PA_SC_VPORT_ZMAX_1 |
0x00000000, // PA_SC_VPORT_ZMIN_2 |
0x3f800000, // PA_SC_VPORT_ZMAX_2 |
0x00000000, // PA_SC_VPORT_ZMIN_3 |
0x3f800000, // PA_SC_VPORT_ZMAX_3 |
0x00000000, // PA_SC_VPORT_ZMIN_4 |
0x3f800000, // PA_SC_VPORT_ZMAX_4 |
0x00000000, // PA_SC_VPORT_ZMIN_5 |
0x3f800000, // PA_SC_VPORT_ZMAX_5 |
0x00000000, // PA_SC_VPORT_ZMIN_6 |
0x3f800000, // PA_SC_VPORT_ZMAX_6 |
0x00000000, // PA_SC_VPORT_ZMIN_7 |
0x3f800000, // PA_SC_VPORT_ZMAX_7 |
0x00000000, // PA_SC_VPORT_ZMIN_8 |
0x3f800000, // PA_SC_VPORT_ZMAX_8 |
0x00000000, // PA_SC_VPORT_ZMIN_9 |
0x3f800000, // PA_SC_VPORT_ZMAX_9 |
0x00000000, // PA_SC_VPORT_ZMIN_10 |
0x3f800000, // PA_SC_VPORT_ZMAX_10 |
0x00000000, // PA_SC_VPORT_ZMIN_11 |
0x3f800000, // PA_SC_VPORT_ZMAX_11 |
0x00000000, // PA_SC_VPORT_ZMIN_12 |
0x3f800000, // PA_SC_VPORT_ZMAX_12 |
0x00000000, // PA_SC_VPORT_ZMIN_13 |
0x3f800000, // PA_SC_VPORT_ZMAX_13 |
0x00000000, // PA_SC_VPORT_ZMIN_14 |
0x3f800000, // PA_SC_VPORT_ZMAX_14 |
0x00000000, // PA_SC_VPORT_ZMIN_15 |
0x3f800000, // PA_SC_VPORT_ZMAX_15 |
}; |
static const u32 si_SECT_CONTEXT_def_2[] = |
{ |
0x00000000, // CP_PERFMON_CNTX_CNTL |
0x00000000, // CP_RINGID |
0x00000000, // CP_VMID |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0xffffffff, // VGT_MAX_VTX_INDX |
0x00000000, // VGT_MIN_VTX_INDX |
0x00000000, // VGT_INDX_OFFSET |
0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX |
0, // HOLE |
0x00000000, // CB_BLEND_RED |
0x00000000, // CB_BLEND_GREEN |
0x00000000, // CB_BLEND_BLUE |
0x00000000, // CB_BLEND_ALPHA |
0, // HOLE |
0, // HOLE |
0x00000000, // DB_STENCIL_CONTROL |
0x00000000, // DB_STENCILREFMASK |
0x00000000, // DB_STENCILREFMASK_BF |
0, // HOLE |
0x00000000, // PA_CL_VPORT_XSCALE |
0x00000000, // PA_CL_VPORT_XOFFSET |
0x00000000, // PA_CL_VPORT_YSCALE |
0x00000000, // PA_CL_VPORT_YOFFSET |
0x00000000, // PA_CL_VPORT_ZSCALE |
0x00000000, // PA_CL_VPORT_ZOFFSET |
0x00000000, // PA_CL_VPORT_XSCALE_1 |
0x00000000, // PA_CL_VPORT_XOFFSET_1 |
0x00000000, // PA_CL_VPORT_YSCALE_1 |
0x00000000, // PA_CL_VPORT_YOFFSET_1 |
0x00000000, // PA_CL_VPORT_ZSCALE_1 |
0x00000000, // PA_CL_VPORT_ZOFFSET_1 |
0x00000000, // PA_CL_VPORT_XSCALE_2 |
0x00000000, // PA_CL_VPORT_XOFFSET_2 |
0x00000000, // PA_CL_VPORT_YSCALE_2 |
0x00000000, // PA_CL_VPORT_YOFFSET_2 |
0x00000000, // PA_CL_VPORT_ZSCALE_2 |
0x00000000, // PA_CL_VPORT_ZOFFSET_2 |
0x00000000, // PA_CL_VPORT_XSCALE_3 |
0x00000000, // PA_CL_VPORT_XOFFSET_3 |
0x00000000, // PA_CL_VPORT_YSCALE_3 |
0x00000000, // PA_CL_VPORT_YOFFSET_3 |
0x00000000, // PA_CL_VPORT_ZSCALE_3 |
0x00000000, // PA_CL_VPORT_ZOFFSET_3 |
0x00000000, // PA_CL_VPORT_XSCALE_4 |
0x00000000, // PA_CL_VPORT_XOFFSET_4 |
0x00000000, // PA_CL_VPORT_YSCALE_4 |
0x00000000, // PA_CL_VPORT_YOFFSET_4 |
0x00000000, // PA_CL_VPORT_ZSCALE_4 |
0x00000000, // PA_CL_VPORT_ZOFFSET_4 |
0x00000000, // PA_CL_VPORT_XSCALE_5 |
0x00000000, // PA_CL_VPORT_XOFFSET_5 |
0x00000000, // PA_CL_VPORT_YSCALE_5 |
0x00000000, // PA_CL_VPORT_YOFFSET_5 |
0x00000000, // PA_CL_VPORT_ZSCALE_5 |
0x00000000, // PA_CL_VPORT_ZOFFSET_5 |
0x00000000, // PA_CL_VPORT_XSCALE_6 |
0x00000000, // PA_CL_VPORT_XOFFSET_6 |
0x00000000, // PA_CL_VPORT_YSCALE_6 |
0x00000000, // PA_CL_VPORT_YOFFSET_6 |
0x00000000, // PA_CL_VPORT_ZSCALE_6 |
0x00000000, // PA_CL_VPORT_ZOFFSET_6 |
0x00000000, // PA_CL_VPORT_XSCALE_7 |
0x00000000, // PA_CL_VPORT_XOFFSET_7 |
0x00000000, // PA_CL_VPORT_YSCALE_7 |
0x00000000, // PA_CL_VPORT_YOFFSET_7 |
0x00000000, // PA_CL_VPORT_ZSCALE_7 |
0x00000000, // PA_CL_VPORT_ZOFFSET_7 |
0x00000000, // PA_CL_VPORT_XSCALE_8 |
0x00000000, // PA_CL_VPORT_XOFFSET_8 |
0x00000000, // PA_CL_VPORT_YSCALE_8 |
0x00000000, // PA_CL_VPORT_YOFFSET_8 |
0x00000000, // PA_CL_VPORT_ZSCALE_8 |
0x00000000, // PA_CL_VPORT_ZOFFSET_8 |
0x00000000, // PA_CL_VPORT_XSCALE_9 |
0x00000000, // PA_CL_VPORT_XOFFSET_9 |
0x00000000, // PA_CL_VPORT_YSCALE_9 |
0x00000000, // PA_CL_VPORT_YOFFSET_9 |
0x00000000, // PA_CL_VPORT_ZSCALE_9 |
0x00000000, // PA_CL_VPORT_ZOFFSET_9 |
0x00000000, // PA_CL_VPORT_XSCALE_10 |
0x00000000, // PA_CL_VPORT_XOFFSET_10 |
0x00000000, // PA_CL_VPORT_YSCALE_10 |
0x00000000, // PA_CL_VPORT_YOFFSET_10 |
0x00000000, // PA_CL_VPORT_ZSCALE_10 |
0x00000000, // PA_CL_VPORT_ZOFFSET_10 |
0x00000000, // PA_CL_VPORT_XSCALE_11 |
0x00000000, // PA_CL_VPORT_XOFFSET_11 |
0x00000000, // PA_CL_VPORT_YSCALE_11 |
0x00000000, // PA_CL_VPORT_YOFFSET_11 |
0x00000000, // PA_CL_VPORT_ZSCALE_11 |
0x00000000, // PA_CL_VPORT_ZOFFSET_11 |
0x00000000, // PA_CL_VPORT_XSCALE_12 |
0x00000000, // PA_CL_VPORT_XOFFSET_12 |
0x00000000, // PA_CL_VPORT_YSCALE_12 |
0x00000000, // PA_CL_VPORT_YOFFSET_12 |
0x00000000, // PA_CL_VPORT_ZSCALE_12 |
0x00000000, // PA_CL_VPORT_ZOFFSET_12 |
0x00000000, // PA_CL_VPORT_XSCALE_13 |
0x00000000, // PA_CL_VPORT_XOFFSET_13 |
0x00000000, // PA_CL_VPORT_YSCALE_13 |
0x00000000, // PA_CL_VPORT_YOFFSET_13 |
0x00000000, // PA_CL_VPORT_ZSCALE_13 |
0x00000000, // PA_CL_VPORT_ZOFFSET_13 |
0x00000000, // PA_CL_VPORT_XSCALE_14 |
0x00000000, // PA_CL_VPORT_XOFFSET_14 |
0x00000000, // PA_CL_VPORT_YSCALE_14 |
0x00000000, // PA_CL_VPORT_YOFFSET_14 |
0x00000000, // PA_CL_VPORT_ZSCALE_14 |
0x00000000, // PA_CL_VPORT_ZOFFSET_14 |
0x00000000, // PA_CL_VPORT_XSCALE_15 |
0x00000000, // PA_CL_VPORT_XOFFSET_15 |
0x00000000, // PA_CL_VPORT_YSCALE_15 |
0x00000000, // PA_CL_VPORT_YOFFSET_15 |
0x00000000, // PA_CL_VPORT_ZSCALE_15 |
0x00000000, // PA_CL_VPORT_ZOFFSET_15 |
0x00000000, // PA_CL_UCP_0_X |
0x00000000, // PA_CL_UCP_0_Y |
0x00000000, // PA_CL_UCP_0_Z |
0x00000000, // PA_CL_UCP_0_W |
0x00000000, // PA_CL_UCP_1_X |
0x00000000, // PA_CL_UCP_1_Y |
0x00000000, // PA_CL_UCP_1_Z |
0x00000000, // PA_CL_UCP_1_W |
0x00000000, // PA_CL_UCP_2_X |
0x00000000, // PA_CL_UCP_2_Y |
0x00000000, // PA_CL_UCP_2_Z |
0x00000000, // PA_CL_UCP_2_W |
0x00000000, // PA_CL_UCP_3_X |
0x00000000, // PA_CL_UCP_3_Y |
0x00000000, // PA_CL_UCP_3_Z |
0x00000000, // PA_CL_UCP_3_W |
0x00000000, // PA_CL_UCP_4_X |
0x00000000, // PA_CL_UCP_4_Y |
0x00000000, // PA_CL_UCP_4_Z |
0x00000000, // PA_CL_UCP_4_W |
0x00000000, // PA_CL_UCP_5_X |
0x00000000, // PA_CL_UCP_5_Y |
0x00000000, // PA_CL_UCP_5_Z |
0x00000000, // PA_CL_UCP_5_W |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SPI_PS_INPUT_CNTL_0 |
0x00000000, // SPI_PS_INPUT_CNTL_1 |
0x00000000, // SPI_PS_INPUT_CNTL_2 |
0x00000000, // SPI_PS_INPUT_CNTL_3 |
0x00000000, // SPI_PS_INPUT_CNTL_4 |
0x00000000, // SPI_PS_INPUT_CNTL_5 |
0x00000000, // SPI_PS_INPUT_CNTL_6 |
0x00000000, // SPI_PS_INPUT_CNTL_7 |
0x00000000, // SPI_PS_INPUT_CNTL_8 |
0x00000000, // SPI_PS_INPUT_CNTL_9 |
0x00000000, // SPI_PS_INPUT_CNTL_10 |
0x00000000, // SPI_PS_INPUT_CNTL_11 |
0x00000000, // SPI_PS_INPUT_CNTL_12 |
0x00000000, // SPI_PS_INPUT_CNTL_13 |
0x00000000, // SPI_PS_INPUT_CNTL_14 |
0x00000000, // SPI_PS_INPUT_CNTL_15 |
0x00000000, // SPI_PS_INPUT_CNTL_16 |
0x00000000, // SPI_PS_INPUT_CNTL_17 |
0x00000000, // SPI_PS_INPUT_CNTL_18 |
0x00000000, // SPI_PS_INPUT_CNTL_19 |
0x00000000, // SPI_PS_INPUT_CNTL_20 |
0x00000000, // SPI_PS_INPUT_CNTL_21 |
0x00000000, // SPI_PS_INPUT_CNTL_22 |
0x00000000, // SPI_PS_INPUT_CNTL_23 |
0x00000000, // SPI_PS_INPUT_CNTL_24 |
0x00000000, // SPI_PS_INPUT_CNTL_25 |
0x00000000, // SPI_PS_INPUT_CNTL_26 |
0x00000000, // SPI_PS_INPUT_CNTL_27 |
0x00000000, // SPI_PS_INPUT_CNTL_28 |
0x00000000, // SPI_PS_INPUT_CNTL_29 |
0x00000000, // SPI_PS_INPUT_CNTL_30 |
0x00000000, // SPI_PS_INPUT_CNTL_31 |
0x00000000, // SPI_VS_OUT_CONFIG |
0, // HOLE |
0x00000000, // SPI_PS_INPUT_ENA |
0x00000000, // SPI_PS_INPUT_ADDR |
0x00000000, // SPI_INTERP_CONTROL_0 |
0x00000002, // SPI_PS_IN_CONTROL |
0, // HOLE |
0x00000000, // SPI_BARYC_CNTL |
0, // HOLE |
0x00000000, // SPI_TMPRING_SIZE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // SPI_WAVE_MGMT_1 |
0x00000000, // SPI_WAVE_MGMT_2 |
0x00000000, // SPI_SHADER_POS_FORMAT |
0x00000000, // SPI_SHADER_Z_FORMAT |
0x00000000, // SPI_SHADER_COL_FORMAT |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_BLEND0_CONTROL |
0x00000000, // CB_BLEND1_CONTROL |
0x00000000, // CB_BLEND2_CONTROL |
0x00000000, // CB_BLEND3_CONTROL |
0x00000000, // CB_BLEND4_CONTROL |
0x00000000, // CB_BLEND5_CONTROL |
0x00000000, // CB_BLEND6_CONTROL |
0x00000000, // CB_BLEND7_CONTROL |
}; |
static const u32 si_SECT_CONTEXT_def_3[] = |
{ |
0x00000000, // PA_CL_POINT_X_RAD |
0x00000000, // PA_CL_POINT_Y_RAD |
0x00000000, // PA_CL_POINT_SIZE |
0x00000000, // PA_CL_POINT_CULL_RAD |
0x00000000, // VGT_DMA_BASE_HI |
0x00000000, // VGT_DMA_BASE |
}; |
static const u32 si_SECT_CONTEXT_def_4[] = |
{ |
0x00000000, // DB_DEPTH_CONTROL |
0x00000000, // DB_EQAA |
0x00000000, // CB_COLOR_CONTROL |
0x00000000, // DB_SHADER_CONTROL |
0x00090000, // PA_CL_CLIP_CNTL |
0x00000004, // PA_SU_SC_MODE_CNTL |
0x00000000, // PA_CL_VTE_CNTL |
0x00000000, // PA_CL_VS_OUT_CNTL |
0x00000000, // PA_CL_NANINF_CNTL |
0x00000000, // PA_SU_LINE_STIPPLE_CNTL |
0x00000000, // PA_SU_LINE_STIPPLE_SCALE |
0x00000000, // PA_SU_PRIM_FILTER_CNTL |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // PA_SU_POINT_SIZE |
0x00000000, // PA_SU_POINT_MINMAX |
0x00000000, // PA_SU_LINE_CNTL |
0x00000000, // PA_SC_LINE_STIPPLE |
0x00000000, // VGT_OUTPUT_PATH_CNTL |
0x00000000, // VGT_HOS_CNTL |
0x00000000, // VGT_HOS_MAX_TESS_LEVEL |
0x00000000, // VGT_HOS_MIN_TESS_LEVEL |
0x00000000, // VGT_HOS_REUSE_DEPTH |
0x00000000, // VGT_GROUP_PRIM_TYPE |
0x00000000, // VGT_GROUP_FIRST_DECR |
0x00000000, // VGT_GROUP_DECR |
0x00000000, // VGT_GROUP_VECT_0_CNTL |
0x00000000, // VGT_GROUP_VECT_1_CNTL |
0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL |
0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL |
0x00000000, // VGT_GS_MODE |
0, // HOLE |
0x00000000, // PA_SC_MODE_CNTL_0 |
0x00000000, // PA_SC_MODE_CNTL_1 |
0x00000000, // VGT_ENHANCE |
0x00000100, // VGT_GS_PER_ES |
0x00000080, // VGT_ES_PER_GS |
0x00000002, // VGT_GS_PER_VS |
0x00000000, // VGT_GSVS_RING_OFFSET_1 |
0x00000000, // VGT_GSVS_RING_OFFSET_2 |
0x00000000, // VGT_GSVS_RING_OFFSET_3 |
0x00000000, // VGT_GS_OUT_PRIM_TYPE |
0x00000000, // IA_ENHANCE |
}; |
static const u32 si_SECT_CONTEXT_def_5[] = |
{ |
0x00000000, // VGT_PRIMITIVEID_EN |
}; |
static const u32 si_SECT_CONTEXT_def_6[] = |
{ |
0x00000000, // VGT_PRIMITIVEID_RESET |
}; |
static const u32 si_SECT_CONTEXT_def_7[] = |
{ |
0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_INSTANCE_STEP_RATE_0 |
0x00000000, // VGT_INSTANCE_STEP_RATE_1 |
0x000000ff, // IA_MULTI_VGT_PARAM |
0x00000000, // VGT_ESGS_RING_ITEMSIZE |
0x00000000, // VGT_GSVS_RING_ITEMSIZE |
0x00000000, // VGT_REUSE_OFF |
0x00000000, // VGT_VTX_CNT_EN |
0x00000000, // DB_HTILE_SURFACE |
0x00000000, // DB_SRESULTS_COMPARE_STATE0 |
0x00000000, // DB_SRESULTS_COMPARE_STATE1 |
0x00000000, // DB_PRELOAD_CONTROL |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_0 |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_1 |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_2 |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2 |
0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3 |
0x00000000, // VGT_STRMOUT_VTX_STRIDE_3 |
0, // HOLE |
0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3 |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE |
0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE |
0, // HOLE |
0x00000000, // VGT_GS_MAX_VERT_OUT |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // VGT_SHADER_STAGES_EN |
0x00000000, // VGT_LS_HS_CONFIG |
0x00000000, // VGT_GS_VERT_ITEMSIZE |
0x00000000, // VGT_GS_VERT_ITEMSIZE_1 |
0x00000000, // VGT_GS_VERT_ITEMSIZE_2 |
0x00000000, // VGT_GS_VERT_ITEMSIZE_3 |
0x00000000, // VGT_TF_PARAM |
0x00000000, // DB_ALPHA_TO_MASK |
0, // HOLE |
0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL |
0x00000000, // PA_SU_POLY_OFFSET_CLAMP |
0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE |
0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET |
0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE |
0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET |
0x00000000, // VGT_GS_INSTANCE_CNT |
0x00000000, // VGT_STRMOUT_CONFIG |
0x00000000, // VGT_STRMOUT_BUFFER_CONFIG |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x00000000, // PA_SC_CENTROID_PRIORITY_0 |
0x00000000, // PA_SC_CENTROID_PRIORITY_1 |
0x00001000, // PA_SC_LINE_CNTL |
0x00000000, // PA_SC_AA_CONFIG |
0x00000005, // PA_SU_VTX_CNTL |
0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ |
0x3f800000, // PA_CL_GB_VERT_DISC_ADJ |
0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ |
0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_2 |
0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_3 |
0xffffffff, // PA_SC_AA_MASK_X0Y0_X1Y0 |
0xffffffff, // PA_SC_AA_MASK_X0Y1_X1Y1 |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0, // HOLE |
0x0000000e, // VGT_VERTEX_REUSE_BLOCK_CNTL |
0x00000010, // VGT_OUT_DEALLOC_CNTL |
0x00000000, // CB_COLOR0_BASE |
0x00000000, // CB_COLOR0_PITCH |
0x00000000, // CB_COLOR0_SLICE |
0x00000000, // CB_COLOR0_VIEW |
0x00000000, // CB_COLOR0_INFO |
0x00000000, // CB_COLOR0_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR0_CMASK |
0x00000000, // CB_COLOR0_CMASK_SLICE |
0x00000000, // CB_COLOR0_FMASK |
0x00000000, // CB_COLOR0_FMASK_SLICE |
0x00000000, // CB_COLOR0_CLEAR_WORD0 |
0x00000000, // CB_COLOR0_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR1_BASE |
0x00000000, // CB_COLOR1_PITCH |
0x00000000, // CB_COLOR1_SLICE |
0x00000000, // CB_COLOR1_VIEW |
0x00000000, // CB_COLOR1_INFO |
0x00000000, // CB_COLOR1_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR1_CMASK |
0x00000000, // CB_COLOR1_CMASK_SLICE |
0x00000000, // CB_COLOR1_FMASK |
0x00000000, // CB_COLOR1_FMASK_SLICE |
0x00000000, // CB_COLOR1_CLEAR_WORD0 |
0x00000000, // CB_COLOR1_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR2_BASE |
0x00000000, // CB_COLOR2_PITCH |
0x00000000, // CB_COLOR2_SLICE |
0x00000000, // CB_COLOR2_VIEW |
0x00000000, // CB_COLOR2_INFO |
0x00000000, // CB_COLOR2_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR2_CMASK |
0x00000000, // CB_COLOR2_CMASK_SLICE |
0x00000000, // CB_COLOR2_FMASK |
0x00000000, // CB_COLOR2_FMASK_SLICE |
0x00000000, // CB_COLOR2_CLEAR_WORD0 |
0x00000000, // CB_COLOR2_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR3_BASE |
0x00000000, // CB_COLOR3_PITCH |
0x00000000, // CB_COLOR3_SLICE |
0x00000000, // CB_COLOR3_VIEW |
0x00000000, // CB_COLOR3_INFO |
0x00000000, // CB_COLOR3_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR3_CMASK |
0x00000000, // CB_COLOR3_CMASK_SLICE |
0x00000000, // CB_COLOR3_FMASK |
0x00000000, // CB_COLOR3_FMASK_SLICE |
0x00000000, // CB_COLOR3_CLEAR_WORD0 |
0x00000000, // CB_COLOR3_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR4_BASE |
0x00000000, // CB_COLOR4_PITCH |
0x00000000, // CB_COLOR4_SLICE |
0x00000000, // CB_COLOR4_VIEW |
0x00000000, // CB_COLOR4_INFO |
0x00000000, // CB_COLOR4_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR4_CMASK |
0x00000000, // CB_COLOR4_CMASK_SLICE |
0x00000000, // CB_COLOR4_FMASK |
0x00000000, // CB_COLOR4_FMASK_SLICE |
0x00000000, // CB_COLOR4_CLEAR_WORD0 |
0x00000000, // CB_COLOR4_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR5_BASE |
0x00000000, // CB_COLOR5_PITCH |
0x00000000, // CB_COLOR5_SLICE |
0x00000000, // CB_COLOR5_VIEW |
0x00000000, // CB_COLOR5_INFO |
0x00000000, // CB_COLOR5_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR5_CMASK |
0x00000000, // CB_COLOR5_CMASK_SLICE |
0x00000000, // CB_COLOR5_FMASK |
0x00000000, // CB_COLOR5_FMASK_SLICE |
0x00000000, // CB_COLOR5_CLEAR_WORD0 |
0x00000000, // CB_COLOR5_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR6_BASE |
0x00000000, // CB_COLOR6_PITCH |
0x00000000, // CB_COLOR6_SLICE |
0x00000000, // CB_COLOR6_VIEW |
0x00000000, // CB_COLOR6_INFO |
0x00000000, // CB_COLOR6_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR6_CMASK |
0x00000000, // CB_COLOR6_CMASK_SLICE |
0x00000000, // CB_COLOR6_FMASK |
0x00000000, // CB_COLOR6_FMASK_SLICE |
0x00000000, // CB_COLOR6_CLEAR_WORD0 |
0x00000000, // CB_COLOR6_CLEAR_WORD1 |
0, // HOLE |
0, // HOLE |
0x00000000, // CB_COLOR7_BASE |
0x00000000, // CB_COLOR7_PITCH |
0x00000000, // CB_COLOR7_SLICE |
0x00000000, // CB_COLOR7_VIEW |
0x00000000, // CB_COLOR7_INFO |
0x00000000, // CB_COLOR7_ATTRIB |
0, // HOLE |
0x00000000, // CB_COLOR7_CMASK |
0x00000000, // CB_COLOR7_CMASK_SLICE |
0x00000000, // CB_COLOR7_FMASK |
0x00000000, // CB_COLOR7_FMASK_SLICE |
0x00000000, // CB_COLOR7_CLEAR_WORD0 |
0x00000000, // CB_COLOR7_CLEAR_WORD1 |
}; |
static const struct cs_extent_def si_SECT_CONTEXT_defs[] = |
{ |
{si_SECT_CONTEXT_def_1, 0x0000a000, 212 }, |
{si_SECT_CONTEXT_def_2, 0x0000a0d8, 272 }, |
{si_SECT_CONTEXT_def_3, 0x0000a1f5, 6 }, |
{si_SECT_CONTEXT_def_4, 0x0000a200, 157 }, |
{si_SECT_CONTEXT_def_5, 0x0000a2a1, 1 }, |
{si_SECT_CONTEXT_def_6, 0x0000a2a3, 1 }, |
{si_SECT_CONTEXT_def_7, 0x0000a2a5, 233 }, |
{ NULL, 0, 0 } |
}; |
static const struct cs_section_def si_cs_data[] = { |
{ si_SECT_CONTEXT_defs, SECT_CONTEXT }, |
{ NULL, SECT_NONE } |
}; |
/drivers/video/drm/radeon/cmdline.c |
---|
2,7 → 2,7 |
#include <drm/drmP.h> |
#include <drm.h> |
#include <drm_mm.h> |
#include "radeon_drm.h" |
#include <drm/radeon_drm.h> |
#include "radeon.h" |
#include "radeon_object.h" |
/drivers/video/drm/radeon/cypress_dpm.c |
---|
0,0 → 1,2162 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "evergreend.h" |
#include "r600_dpm.h" |
#include "cypress_dpm.h" |
#include "atom.h" |
#define SMC_RAM_END 0x8000 |
#define MC_CG_ARB_FREQ_F0 0x0a |
#define MC_CG_ARB_FREQ_F1 0x0b |
#define MC_CG_ARB_FREQ_F2 0x0c |
#define MC_CG_ARB_FREQ_F3 0x0d |
#define MC_CG_SEQ_DRAMCONF_S0 0x05 |
#define MC_CG_SEQ_DRAMCONF_S1 0x06 |
#define MC_CG_SEQ_YCLK_SUSPEND 0x04 |
#define MC_CG_SEQ_YCLK_RESUME 0x0a |
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); |
static void cypress_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp, bif; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if (enable) { |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) { |
if (!pi->boot_in_gen2) { |
bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK; |
bif |= CG_CLIENT_REQ(0xd); |
WREG32(CG_BIF_REQ_AND_RSP, bif); |
tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); |
tmp |= LC_GEN2_EN_STRAP; |
tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
udelay(10); |
tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
} |
} else { |
if (!pi->boot_in_gen2) { |
tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
tmp &= ~LC_GEN2_EN_STRAP; |
} |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) || |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
} |
static void cypress_enable_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
cypress_enable_bif_dynamic_pcie_gen2(rdev, enable); |
if (enable) |
WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE); |
} |
#if 0 |
static int cypress_enter_ulp_state(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (pi->gfx_clock_gating) { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); |
RREG32(GB_ADDR_CONFIG); |
} |
WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower), |
~HOST_SMC_MSG_MASK); |
udelay(7000); |
return 0; |
} |
#endif |
static void cypress_gfx_clock_gating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (enable) { |
if (eg_pi->light_sleep) { |
WREG32(GRBM_GFX_INDEX, 0xC0000000); |
WREG32_CG(CG_CGLS_TILE_0, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_1, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_2, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_3, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_4, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_5, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_6, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_7, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_8, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_9, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_10, 0xFFFFFFFF); |
WREG32_CG(CG_CGLS_TILE_11, 0xFFFFFFFF); |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_LIGHT_SLEEP_EN, ~DYN_LIGHT_SLEEP_EN); |
} |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); |
} else { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); |
RREG32(GB_ADDR_CONFIG); |
if (eg_pi->light_sleep) { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_LIGHT_SLEEP_EN); |
WREG32(GRBM_GFX_INDEX, 0xC0000000); |
WREG32_CG(CG_CGLS_TILE_0, 0); |
WREG32_CG(CG_CGLS_TILE_1, 0); |
WREG32_CG(CG_CGLS_TILE_2, 0); |
WREG32_CG(CG_CGLS_TILE_3, 0); |
WREG32_CG(CG_CGLS_TILE_4, 0); |
WREG32_CG(CG_CGLS_TILE_5, 0); |
WREG32_CG(CG_CGLS_TILE_6, 0); |
WREG32_CG(CG_CGLS_TILE_7, 0); |
WREG32_CG(CG_CGLS_TILE_8, 0); |
WREG32_CG(CG_CGLS_TILE_9, 0); |
WREG32_CG(CG_CGLS_TILE_10, 0); |
WREG32_CG(CG_CGLS_TILE_11, 0); |
} |
} |
} |
static void cypress_mg_clock_gating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (enable) { |
u32 cgts_sm_ctrl_reg; |
if (rdev->family == CHIP_CEDAR) |
cgts_sm_ctrl_reg = CEDAR_MGCGCGTSSMCTRL_DFLT; |
else if (rdev->family == CHIP_REDWOOD) |
cgts_sm_ctrl_reg = REDWOOD_MGCGCGTSSMCTRL_DFLT; |
else |
cgts_sm_ctrl_reg = CYPRESS_MGCGCGTSSMCTRL_DFLT; |
WREG32(GRBM_GFX_INDEX, 0xC0000000); |
WREG32_CG(CG_CGTT_LOCAL_0, CYPRESS_MGCGTTLOCAL0_DFLT); |
WREG32_CG(CG_CGTT_LOCAL_1, CYPRESS_MGCGTTLOCAL1_DFLT & 0xFFFFCFFF); |
WREG32_CG(CG_CGTT_LOCAL_2, CYPRESS_MGCGTTLOCAL2_DFLT); |
WREG32_CG(CG_CGTT_LOCAL_3, CYPRESS_MGCGTTLOCAL3_DFLT); |
if (pi->mgcgtssm) |
WREG32(CGTS_SM_CTRL_REG, cgts_sm_ctrl_reg); |
if (eg_pi->mcls) { |
WREG32_P(MC_CITF_MISC_RD_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE); |
WREG32_P(MC_CITF_MISC_WR_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE); |
WREG32_P(MC_CITF_MISC_VM_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE); |
WREG32_P(MC_HUB_MISC_HUB_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE); |
WREG32_P(MC_HUB_MISC_VM_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE); |
WREG32_P(MC_HUB_MISC_SIP_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE); |
WREG32_P(MC_XPB_CLK_GAT, MEM_LS_ENABLE, ~MEM_LS_ENABLE); |
WREG32_P(VM_L2_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE); |
} |
} else { |
WREG32(GRBM_GFX_INDEX, 0xC0000000); |
WREG32_CG(CG_CGTT_LOCAL_0, 0xFFFFFFFF); |
WREG32_CG(CG_CGTT_LOCAL_1, 0xFFFFFFFF); |
WREG32_CG(CG_CGTT_LOCAL_2, 0xFFFFFFFF); |
WREG32_CG(CG_CGTT_LOCAL_3, 0xFFFFFFFF); |
if (pi->mgcgtssm) |
WREG32(CGTS_SM_CTRL_REG, 0x81f44bc0); |
} |
} |
void cypress_enable_spread_spectrum(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (enable) { |
if (pi->sclk_ss) |
WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); |
if (pi->mclk_ss) |
WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN); |
} else { |
WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN); |
WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); |
WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN); |
WREG32_P(MPLL_CNTL_MODE, 0, ~SS_DSMODE_EN); |
} |
} |
void cypress_start_dpm(struct radeon_device *rdev) |
{ |
WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN); |
} |
void cypress_enable_sclk_control(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF); |
else |
WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF); |
} |
void cypress_enable_mclk_control(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF); |
else |
WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF); |
} |
int cypress_notify_smc_display_change(struct radeon_device *rdev, |
bool has_display) |
{ |
PPSMC_Msg msg = has_display ? |
(PPSMC_Msg)PPSMC_MSG_HasDisplay : (PPSMC_Msg)PPSMC_MSG_NoDisplay; |
if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
void cypress_program_response_times(struct radeon_device *rdev) |
{ |
u32 reference_clock; |
u32 mclk_switch_limit; |
reference_clock = radeon_get_xclk(rdev); |
mclk_switch_limit = (460 * reference_clock) / 100; |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_mclk_switch_lim, |
mclk_switch_limit); |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_mvdd_chg_time, 1); |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_mc_block_delay, 0xAA); |
rv770_program_response_times(rdev); |
if (ASIC_IS_LOMBOK(rdev)) |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_is_asic_lombok, 1); |
} |
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); |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) && (tmp & LC_CURRENT_DATA_RATE)) |
return 0; |
#if defined(CONFIG_ACPI) |
if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) || |
(perf_req == PCIE_PERF_REQ_PECI_GEN2)) { |
eg_pi->pcie_performance_request_registered = true; |
return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise); |
} else if ((perf_req == PCIE_PERF_REQ_REMOVE_REGISTRY) && |
eg_pi->pcie_performance_request_registered) { |
eg_pi->pcie_performance_request_registered = false; |
return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise); |
} |
#endif |
return 0; |
} |
void cypress_advertise_gen2_capability(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp; |
#if defined(CONFIG_ACPI) |
radeon_acpi_pcie_notify_device_ready(rdev); |
#endif |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) |
pi->pcie_gen2 = true; |
else |
pi->pcie_gen2 = false; |
if (!pi->pcie_gen2) |
cypress_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, true); |
} |
static enum radeon_pcie_gen cypress_get_maximum_link_speed(struct radeon_ps *radeon_state) |
{ |
struct rv7xx_ps *state = rv770_get_ps(radeon_state); |
if (state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) |
return 1; |
return 0; |
} |
void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
enum radeon_pcie_gen pcie_link_speed_target = |
cypress_get_maximum_link_speed(radeon_new_state); |
enum radeon_pcie_gen pcie_link_speed_current = |
cypress_get_maximum_link_speed(radeon_current_state); |
u8 request; |
if (pcie_link_speed_target < pcie_link_speed_current) { |
if (pcie_link_speed_target == RADEON_PCIE_GEN1) |
request = PCIE_PERF_REQ_PECI_GEN1; |
else if (pcie_link_speed_target == RADEON_PCIE_GEN2) |
request = PCIE_PERF_REQ_PECI_GEN2; |
else |
request = PCIE_PERF_REQ_PECI_GEN3; |
cypress_pcie_performance_request(rdev, request, false); |
} |
} |
void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
enum radeon_pcie_gen pcie_link_speed_target = |
cypress_get_maximum_link_speed(radeon_new_state); |
enum radeon_pcie_gen pcie_link_speed_current = |
cypress_get_maximum_link_speed(radeon_current_state); |
u8 request; |
if (pcie_link_speed_target > pcie_link_speed_current) { |
if (pcie_link_speed_target == RADEON_PCIE_GEN1) |
request = PCIE_PERF_REQ_PECI_GEN1; |
else if (pcie_link_speed_target == RADEON_PCIE_GEN2) |
request = PCIE_PERF_REQ_PECI_GEN2; |
else |
request = PCIE_PERF_REQ_PECI_GEN3; |
cypress_pcie_performance_request(rdev, request, false); |
} |
} |
static int cypress_populate_voltage_value(struct radeon_device *rdev, |
struct atom_voltage_table *table, |
u16 value, RV770_SMC_VOLTAGE_VALUE *voltage) |
{ |
unsigned int i; |
for (i = 0; i < table->count; i++) { |
if (value <= table->entries[i].value) { |
voltage->index = (u8)i; |
voltage->value = cpu_to_be16(table->entries[i].value); |
break; |
} |
} |
if (i == table->count) |
return -EINVAL; |
return 0; |
} |
u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u8 result = 0; |
bool strobe_mode = false; |
if (pi->mem_gddr5) { |
if (mclk <= pi->mclk_strobe_mode_threshold) |
strobe_mode = true; |
result = cypress_get_mclk_frequency_ratio(rdev, mclk, strobe_mode); |
if (strobe_mode) |
result |= SMC_STROBE_ENABLE; |
} |
return result; |
} |
u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf) |
{ |
u32 ref_clk = rdev->clock.mpll.reference_freq; |
u32 vco = clkf * ref_clk; |
/* 100 Mhz ref clk */ |
if (ref_clk == 10000) { |
if (vco > 500000) |
return 0xC6; |
if (vco > 400000) |
return 0x9D; |
if (vco > 330000) |
return 0x6C; |
if (vco > 250000) |
return 0x2B; |
if (vco > 160000) |
return 0x5B; |
if (vco > 120000) |
return 0x0A; |
return 0x4B; |
} |
/* 27 Mhz ref clk */ |
if (vco > 250000) |
return 0x8B; |
if (vco > 200000) |
return 0xCC; |
if (vco > 150000) |
return 0x9B; |
return 0x6B; |
} |
static int cypress_populate_mclk_value(struct radeon_device *rdev, |
u32 engine_clock, u32 memory_clock, |
RV7XX_SMC_MCLK_VALUE *mclk, |
bool strobe_mode, bool dll_state_on) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 mpll_ad_func_cntl = |
pi->clk_regs.rv770.mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2 = |
pi->clk_regs.rv770.mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl = |
pi->clk_regs.rv770.mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2 = |
pi->clk_regs.rv770.mpll_dq_func_cntl_2; |
u32 mclk_pwrmgt_cntl = |
pi->clk_regs.rv770.mclk_pwrmgt_cntl; |
u32 dll_cntl = |
pi->clk_regs.rv770.dll_cntl; |
u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1; |
u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2; |
struct atom_clock_dividers dividers; |
u32 ibias; |
u32 dll_speed; |
int ret; |
u32 mc_seq_misc7; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, |
memory_clock, strobe_mode, ÷rs); |
if (ret) |
return ret; |
if (!strobe_mode) { |
mc_seq_misc7 = RREG32(MC_SEQ_MISC7); |
if(mc_seq_misc7 & 0x8000000) |
dividers.post_div = 1; |
} |
ibias = cypress_map_clkf_to_ibias(rdev, dividers.whole_fb_div); |
mpll_ad_func_cntl &= ~(CLKR_MASK | |
YCLK_POST_DIV_MASK | |
CLKF_MASK | |
CLKFRAC_MASK | |
IBIAS_MASK); |
mpll_ad_func_cntl |= CLKR(dividers.ref_div); |
mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div); |
mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div); |
mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div); |
mpll_ad_func_cntl |= IBIAS(ibias); |
if (dividers.vco_mode) |
mpll_ad_func_cntl_2 |= VCO_MODE; |
else |
mpll_ad_func_cntl_2 &= ~VCO_MODE; |
if (pi->mem_gddr5) { |
mpll_dq_func_cntl &= ~(CLKR_MASK | |
YCLK_POST_DIV_MASK | |
CLKF_MASK | |
CLKFRAC_MASK | |
IBIAS_MASK); |
mpll_dq_func_cntl |= CLKR(dividers.ref_div); |
mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div); |
mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div); |
mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div); |
mpll_dq_func_cntl |= IBIAS(ibias); |
if (strobe_mode) |
mpll_dq_func_cntl &= ~PDNB; |
else |
mpll_dq_func_cntl |= PDNB; |
if (dividers.vco_mode) |
mpll_dq_func_cntl_2 |= VCO_MODE; |
else |
mpll_dq_func_cntl_2 &= ~VCO_MODE; |
} |
if (pi->mclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = memory_clock * dividers.post_div; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, vco_freq)) { |
u32 reference_clock = rdev->clock.mpll.reference_freq; |
u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div); |
u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
u32 clk_v = ss.percentage * |
(0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625); |
mpll_ss1 &= ~CLKV_MASK; |
mpll_ss1 |= CLKV(clk_v); |
mpll_ss2 &= ~CLKS_MASK; |
mpll_ss2 |= CLKS(clk_s); |
} |
} |
dll_speed = rv740_get_dll_speed(pi->mem_gddr5, |
memory_clock); |
mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK; |
mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed); |
if (dll_state_on) |
mclk_pwrmgt_cntl |= (MRDCKA0_PDNB | |
MRDCKA1_PDNB | |
MRDCKB0_PDNB | |
MRDCKB1_PDNB | |
MRDCKC0_PDNB | |
MRDCKC1_PDNB | |
MRDCKD0_PDNB | |
MRDCKD1_PDNB); |
else |
mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB | |
MRDCKA1_PDNB | |
MRDCKB0_PDNB | |
MRDCKB1_PDNB | |
MRDCKC0_PDNB | |
MRDCKC1_PDNB | |
MRDCKD0_PDNB | |
MRDCKD1_PDNB); |
mclk->mclk770.mclk_value = cpu_to_be32(memory_clock); |
mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); |
mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); |
mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); |
mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); |
mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl); |
mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1); |
mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2); |
return 0; |
} |
u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev, |
u32 memory_clock, bool strobe_mode) |
{ |
u8 mc_para_index; |
if (rdev->family >= CHIP_BARTS) { |
if (strobe_mode) { |
if (memory_clock < 10000) |
mc_para_index = 0x00; |
else if (memory_clock > 47500) |
mc_para_index = 0x0f; |
else |
mc_para_index = (u8)((memory_clock - 10000) / 2500); |
} else { |
if (memory_clock < 65000) |
mc_para_index = 0x00; |
else if (memory_clock > 135000) |
mc_para_index = 0x0f; |
else |
mc_para_index = (u8)((memory_clock - 60000) / 5000); |
} |
} else { |
if (strobe_mode) { |
if (memory_clock < 10000) |
mc_para_index = 0x00; |
else if (memory_clock > 47500) |
mc_para_index = 0x0f; |
else |
mc_para_index = (u8)((memory_clock - 10000) / 2500); |
} else { |
if (memory_clock < 40000) |
mc_para_index = 0x00; |
else if (memory_clock > 115000) |
mc_para_index = 0x0f; |
else |
mc_para_index = (u8)((memory_clock - 40000) / 5000); |
} |
} |
return mc_para_index; |
} |
static int cypress_populate_mvdd_value(struct radeon_device *rdev, |
u32 mclk, |
RV770_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (!pi->mvdd_control) { |
voltage->index = eg_pi->mvdd_high_index; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
return 0; |
} |
if (mclk <= pi->mvdd_split_frequency) { |
voltage->index = eg_pi->mvdd_low_index; |
voltage->value = cpu_to_be16(MVDD_LOW_VALUE); |
} else { |
voltage->index = eg_pi->mvdd_high_index; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
} |
return 0; |
} |
int cypress_convert_power_level_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
RV770_SMC_HW_PERFORMANCE_LEVEL *level, |
u8 watermark_level) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
int ret; |
bool dll_state_on; |
level->gen2PCIE = pi->pcie_gen2 ? |
((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0; |
level->gen2XSP = (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0; |
level->backbias = (pl->flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? 1 : 0; |
level->displayWatermark = watermark_level; |
ret = rv740_populate_sclk_value(rdev, pl->sclk, &level->sclk); |
if (ret) |
return ret; |
level->mcFlags = 0; |
if (pi->mclk_stutter_mode_threshold && |
(pl->mclk <= pi->mclk_stutter_mode_threshold) && |
!eg_pi->uvd_enabled) { |
level->mcFlags |= SMC_MC_STUTTER_EN; |
if (eg_pi->sclk_deep_sleep) |
level->stateFlags |= PPSMC_STATEFLAG_AUTO_PULSE_SKIP; |
else |
level->stateFlags &= ~PPSMC_STATEFLAG_AUTO_PULSE_SKIP; |
} |
if (pi->mem_gddr5) { |
if (pl->mclk > pi->mclk_edc_enable_threshold) |
level->mcFlags |= SMC_MC_EDC_RD_FLAG; |
if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold) |
level->mcFlags |= SMC_MC_EDC_WR_FLAG; |
level->strobeMode = cypress_get_strobe_mode_settings(rdev, pl->mclk); |
if (level->strobeMode & SMC_STROBE_ENABLE) { |
if (cypress_get_mclk_frequency_ratio(rdev, pl->mclk, true) >= |
((RREG32(MC_SEQ_MISC7) >> 16) & 0xf)) |
dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false; |
else |
dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false; |
} else |
dll_state_on = eg_pi->dll_default_on; |
ret = cypress_populate_mclk_value(rdev, |
pl->sclk, |
pl->mclk, |
&level->mclk, |
(level->strobeMode & SMC_STROBE_ENABLE) != 0, |
dll_state_on); |
} else { |
ret = cypress_populate_mclk_value(rdev, |
pl->sclk, |
pl->mclk, |
&level->mclk, |
true, |
true); |
} |
if (ret) |
return ret; |
ret = cypress_populate_voltage_value(rdev, |
&eg_pi->vddc_voltage_table, |
pl->vddc, |
&level->vddc); |
if (ret) |
return ret; |
if (eg_pi->vddci_control) { |
ret = cypress_populate_voltage_value(rdev, |
&eg_pi->vddci_voltage_table, |
pl->vddci, |
&level->vddci); |
if (ret) |
return ret; |
} |
ret = cypress_populate_mvdd_value(rdev, pl->mclk, &level->mvdd); |
return ret; |
} |
static int cypress_convert_power_state_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
RV770_SMC_SWSTATE *smc_state) |
{ |
struct rv7xx_ps *state = rv770_get_ps(radeon_state); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
int ret; |
if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC)) |
smc_state->flags |= PPSMC_SWSTATE_FLAG_DC; |
ret = cypress_convert_power_level_to_smc(rdev, |
&state->low, |
&smc_state->levels[0], |
PPSMC_DISPLAY_WATERMARK_LOW); |
if (ret) |
return ret; |
ret = cypress_convert_power_level_to_smc(rdev, |
&state->medium, |
&smc_state->levels[1], |
PPSMC_DISPLAY_WATERMARK_LOW); |
if (ret) |
return ret; |
ret = cypress_convert_power_level_to_smc(rdev, |
&state->high, |
&smc_state->levels[2], |
PPSMC_DISPLAY_WATERMARK_HIGH); |
if (ret) |
return ret; |
smc_state->levels[0].arbValue = MC_CG_ARB_FREQ_F1; |
smc_state->levels[1].arbValue = MC_CG_ARB_FREQ_F2; |
smc_state->levels[2].arbValue = MC_CG_ARB_FREQ_F3; |
if (eg_pi->dynamic_ac_timing) { |
smc_state->levels[0].ACIndex = 2; |
smc_state->levels[1].ACIndex = 3; |
smc_state->levels[2].ACIndex = 4; |
} else { |
smc_state->levels[0].ACIndex = 0; |
smc_state->levels[1].ACIndex = 0; |
smc_state->levels[2].ACIndex = 0; |
} |
rv770_populate_smc_sp(rdev, radeon_state, smc_state); |
return rv770_populate_smc_t(rdev, radeon_state, smc_state); |
} |
static void cypress_convert_mc_registers(struct evergreen_mc_reg_entry *entry, |
SMC_Evergreen_MCRegisterSet *data, |
u32 num_entries, u32 valid_flag) |
{ |
u32 i, j; |
for (i = 0, j = 0; j < num_entries; j++) { |
if (valid_flag & (1 << j)) { |
data->value[i] = cpu_to_be32(entry->mc_data[j]); |
i++; |
} |
} |
} |
static void cypress_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
SMC_Evergreen_MCRegisterSet *mc_reg_table_data) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 i = 0; |
for (i = 0; i < eg_pi->mc_reg_table.num_entries; i++) { |
if (pl->mclk <= |
eg_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max) |
break; |
} |
if ((i == eg_pi->mc_reg_table.num_entries) && (i > 0)) |
--i; |
cypress_convert_mc_registers(&eg_pi->mc_reg_table.mc_reg_table_entry[i], |
mc_reg_table_data, |
eg_pi->mc_reg_table.last, |
eg_pi->mc_reg_table.valid_flag); |
} |
static void cypress_convert_mc_reg_table_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
SMC_Evergreen_MCRegisters *mc_reg_table) |
{ |
struct rv7xx_ps *state = rv770_get_ps(radeon_state); |
cypress_convert_mc_reg_table_entry_to_smc(rdev, |
&state->low, |
&mc_reg_table->data[2]); |
cypress_convert_mc_reg_table_entry_to_smc(rdev, |
&state->medium, |
&mc_reg_table->data[3]); |
cypress_convert_mc_reg_table_entry_to_smc(rdev, |
&state->high, |
&mc_reg_table->data[4]); |
} |
int cypress_upload_sw_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u16 address = pi->state_table_start + |
offsetof(RV770_SMC_STATETABLE, driverState); |
RV770_SMC_SWSTATE state = { 0 }; |
int ret; |
ret = cypress_convert_power_state_to_smc(rdev, radeon_new_state, &state); |
if (ret) |
return ret; |
return rv770_copy_bytes_to_smc(rdev, address, (u8 *)&state, |
sizeof(RV770_SMC_SWSTATE), |
pi->sram_end); |
} |
int cypress_upload_mc_reg_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
SMC_Evergreen_MCRegisters mc_reg_table = { 0 }; |
u16 address; |
cypress_convert_mc_reg_table_to_smc(rdev, radeon_new_state, &mc_reg_table); |
address = eg_pi->mc_reg_table_start + |
(u16)offsetof(SMC_Evergreen_MCRegisters, data[2]); |
return rv770_copy_bytes_to_smc(rdev, address, |
(u8 *)&mc_reg_table.data[2], |
sizeof(SMC_Evergreen_MCRegisterSet) * 3, |
pi->sram_end); |
} |
u32 cypress_calculate_burst_time(struct radeon_device *rdev, |
u32 engine_clock, u32 memory_clock) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 multiplier = pi->mem_gddr5 ? 1 : 2; |
u32 result = (4 * multiplier * engine_clock) / (memory_clock / 2); |
u32 burst_time; |
if (result <= 4) |
burst_time = 0; |
else if (result < 8) |
burst_time = result - 4; |
else { |
burst_time = result / 2 ; |
if (burst_time > 18) |
burst_time = 18; |
} |
return burst_time; |
} |
void cypress_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state); |
u32 mc_arb_burst_time = RREG32(MC_ARB_BURST_TIME); |
mc_arb_burst_time &= ~(STATE1_MASK | STATE2_MASK | STATE3_MASK); |
mc_arb_burst_time |= STATE1(cypress_calculate_burst_time(rdev, |
new_state->low.sclk, |
new_state->low.mclk)); |
mc_arb_burst_time |= STATE2(cypress_calculate_burst_time(rdev, |
new_state->medium.sclk, |
new_state->medium.mclk)); |
mc_arb_burst_time |= STATE3(cypress_calculate_burst_time(rdev, |
new_state->high.sclk, |
new_state->high.mclk)); |
rv730_program_memory_timing_parameters(rdev, radeon_new_state); |
WREG32(MC_ARB_BURST_TIME, mc_arb_burst_time); |
} |
static void cypress_populate_mc_reg_addresses(struct radeon_device *rdev, |
SMC_Evergreen_MCRegisters *mc_reg_table) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 i, j; |
for (i = 0, j = 0; j < eg_pi->mc_reg_table.last; j++) { |
if (eg_pi->mc_reg_table.valid_flag & (1 << j)) { |
mc_reg_table->address[i].s0 = |
cpu_to_be16(eg_pi->mc_reg_table.mc_reg_address[j].s0); |
mc_reg_table->address[i].s1 = |
cpu_to_be16(eg_pi->mc_reg_table.mc_reg_address[j].s1); |
i++; |
} |
} |
mc_reg_table->last = (u8)i; |
} |
static void cypress_set_mc_reg_address_table(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 i = 0; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RAS_TIMING_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RAS_TIMING >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_CAS_TIMING_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_CAS_TIMING >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC_TIMING_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC_TIMING >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC_TIMING2_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC_TIMING2 >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RD_CTL_D0_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RD_CTL_D0 >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RD_CTL_D1_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RD_CTL_D1 >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_WR_CTL_D0_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_WR_CTL_D0 >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_WR_CTL_D1_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_WR_CTL_D1 >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_EMRS >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_MRS >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_MRS1 >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC1 >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC1 >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RESERVE_M >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RESERVE_M >> 2; |
i++; |
eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC3 >> 2; |
eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC3 >> 2; |
i++; |
eg_pi->mc_reg_table.last = (u8)i; |
} |
static void cypress_retrieve_ac_timing_for_one_entry(struct radeon_device *rdev, |
struct evergreen_mc_reg_entry *entry) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 i; |
for (i = 0; i < eg_pi->mc_reg_table.last; i++) |
entry->mc_data[i] = |
RREG32(eg_pi->mc_reg_table.mc_reg_address[i].s1 << 2); |
} |
static void cypress_retrieve_ac_timing_for_all_ranges(struct radeon_device *rdev, |
struct atom_memory_clock_range_table *range_table) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 i, j; |
for (i = 0; i < range_table->num_entries; i++) { |
eg_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max = |
range_table->mclk[i]; |
radeon_atom_set_ac_timing(rdev, range_table->mclk[i]); |
cypress_retrieve_ac_timing_for_one_entry(rdev, |
&eg_pi->mc_reg_table.mc_reg_table_entry[i]); |
} |
eg_pi->mc_reg_table.num_entries = range_table->num_entries; |
eg_pi->mc_reg_table.valid_flag = 0; |
for (i = 0; i < eg_pi->mc_reg_table.last; i++) { |
for (j = 1; j < range_table->num_entries; j++) { |
if (eg_pi->mc_reg_table.mc_reg_table_entry[j-1].mc_data[i] != |
eg_pi->mc_reg_table.mc_reg_table_entry[j].mc_data[i]) { |
eg_pi->mc_reg_table.valid_flag |= (1 << i); |
break; |
} |
} |
} |
} |
static int cypress_initialize_mc_reg_table(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u8 module_index = rv770_get_memory_module_index(rdev); |
struct atom_memory_clock_range_table range_table = { 0 }; |
int ret; |
ret = radeon_atom_get_mclk_range_table(rdev, |
pi->mem_gddr5, |
module_index, &range_table); |
if (ret) |
return ret; |
cypress_retrieve_ac_timing_for_all_ranges(rdev, &range_table); |
return 0; |
} |
static void cypress_wait_for_mc_sequencer(struct radeon_device *rdev, u8 value) |
{ |
u32 i, j; |
u32 channels = 2; |
if ((rdev->family == CHIP_CYPRESS) || |
(rdev->family == CHIP_HEMLOCK)) |
channels = 4; |
else if (rdev->family == CHIP_CEDAR) |
channels = 1; |
for (i = 0; i < channels; i++) { |
if ((rdev->family == CHIP_CYPRESS) || |
(rdev->family == CHIP_HEMLOCK)) { |
WREG32_P(MC_CONFIG_MCD, MC_RD_ENABLE_MCD(i), ~MC_RD_ENABLE_MCD_MASK); |
WREG32_P(MC_CG_CONFIG_MCD, MC_RD_ENABLE_MCD(i), ~MC_RD_ENABLE_MCD_MASK); |
} else { |
WREG32_P(MC_CONFIG, MC_RD_ENABLE(i), ~MC_RD_ENABLE_MASK); |
WREG32_P(MC_CG_CONFIG, MC_RD_ENABLE(i), ~MC_RD_ENABLE_MASK); |
} |
for (j = 0; j < rdev->usec_timeout; j++) { |
if (((RREG32(MC_SEQ_CG) & CG_SEQ_RESP_MASK) >> CG_SEQ_RESP_SHIFT) == value) |
break; |
udelay(1); |
} |
} |
} |
static void cypress_force_mc_use_s1(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state); |
u32 strobe_mode; |
u32 mc_seq_cg; |
int i; |
if (RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE) |
return; |
radeon_atom_set_ac_timing(rdev, boot_state->low.mclk); |
radeon_mc_wait_for_idle(rdev); |
if ((rdev->family == CHIP_CYPRESS) || |
(rdev->family == CHIP_HEMLOCK)) { |
WREG32(MC_CONFIG_MCD, 0xf); |
WREG32(MC_CG_CONFIG_MCD, 0xf); |
} else { |
WREG32(MC_CONFIG, 0xf); |
WREG32(MC_CG_CONFIG, 0xf); |
} |
for (i = 0; i < rdev->num_crtc; i++) |
radeon_wait_for_vblank(rdev, i); |
WREG32(MC_SEQ_CG, MC_CG_SEQ_YCLK_SUSPEND); |
cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_SUSPEND); |
strobe_mode = cypress_get_strobe_mode_settings(rdev, |
boot_state->low.mclk); |
mc_seq_cg = CG_SEQ_REQ(MC_CG_SEQ_DRAMCONF_S1); |
mc_seq_cg |= SEQ_CG_RESP(strobe_mode); |
WREG32(MC_SEQ_CG, mc_seq_cg); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE) |
break; |
udelay(1); |
} |
mc_seq_cg &= ~CG_SEQ_REQ_MASK; |
mc_seq_cg |= CG_SEQ_REQ(MC_CG_SEQ_YCLK_RESUME); |
WREG32(MC_SEQ_CG, mc_seq_cg); |
cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_RESUME); |
} |
static void cypress_copy_ac_timing_from_s1_to_s0(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 value; |
u32 i; |
for (i = 0; i < eg_pi->mc_reg_table.last; i++) { |
value = RREG32(eg_pi->mc_reg_table.mc_reg_address[i].s1 << 2); |
WREG32(eg_pi->mc_reg_table.mc_reg_address[i].s0 << 2, value); |
} |
} |
static void cypress_force_mc_use_s0(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state); |
u32 strobe_mode; |
u32 mc_seq_cg; |
int i; |
cypress_copy_ac_timing_from_s1_to_s0(rdev); |
radeon_mc_wait_for_idle(rdev); |
if ((rdev->family == CHIP_CYPRESS) || |
(rdev->family == CHIP_HEMLOCK)) { |
WREG32(MC_CONFIG_MCD, 0xf); |
WREG32(MC_CG_CONFIG_MCD, 0xf); |
} else { |
WREG32(MC_CONFIG, 0xf); |
WREG32(MC_CG_CONFIG, 0xf); |
} |
for (i = 0; i < rdev->num_crtc; i++) |
radeon_wait_for_vblank(rdev, i); |
WREG32(MC_SEQ_CG, MC_CG_SEQ_YCLK_SUSPEND); |
cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_SUSPEND); |
strobe_mode = cypress_get_strobe_mode_settings(rdev, |
boot_state->low.mclk); |
mc_seq_cg = CG_SEQ_REQ(MC_CG_SEQ_DRAMCONF_S0); |
mc_seq_cg |= SEQ_CG_RESP(strobe_mode); |
WREG32(MC_SEQ_CG, mc_seq_cg); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (!(RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE)) |
break; |
udelay(1); |
} |
mc_seq_cg &= ~CG_SEQ_REQ_MASK; |
mc_seq_cg |= CG_SEQ_REQ(MC_CG_SEQ_YCLK_RESUME); |
WREG32(MC_SEQ_CG, mc_seq_cg); |
cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_RESUME); |
} |
static int cypress_populate_initial_mvdd_value(struct radeon_device *rdev, |
RV770_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
voltage->index = eg_pi->mvdd_high_index; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
return 0; |
} |
int cypress_populate_smc_initial_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_initial_state, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_ps *initial_state = rv770_get_ps(radeon_initial_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 a_t; |
table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl); |
table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = |
cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl_2); |
table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl); |
table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = |
cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl_2); |
table->initialState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.mclk_pwrmgt_cntl); |
table->initialState.levels[0].mclk.mclk770.vDLL_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.dll_cntl); |
table->initialState.levels[0].mclk.mclk770.vMPLL_SS = |
cpu_to_be32(pi->clk_regs.rv770.mpll_ss1); |
table->initialState.levels[0].mclk.mclk770.vMPLL_SS2 = |
cpu_to_be32(pi->clk_regs.rv770.mpll_ss2); |
table->initialState.levels[0].mclk.mclk770.mclk_value = |
cpu_to_be32(initial_state->low.mclk); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_2); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_3); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum_2); |
table->initialState.levels[0].sclk.sclk_value = |
cpu_to_be32(initial_state->low.sclk); |
table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0; |
table->initialState.levels[0].ACIndex = 0; |
cypress_populate_voltage_value(rdev, |
&eg_pi->vddc_voltage_table, |
initial_state->low.vddc, |
&table->initialState.levels[0].vddc); |
if (eg_pi->vddci_control) |
cypress_populate_voltage_value(rdev, |
&eg_pi->vddci_voltage_table, |
initial_state->low.vddci, |
&table->initialState.levels[0].vddci); |
cypress_populate_initial_mvdd_value(rdev, |
&table->initialState.levels[0].mvdd); |
a_t = CG_R(0xffff) | CG_L(0); |
table->initialState.levels[0].aT = cpu_to_be32(a_t); |
table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp); |
if (pi->boot_in_gen2) |
table->initialState.levels[0].gen2PCIE = 1; |
else |
table->initialState.levels[0].gen2PCIE = 0; |
if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) |
table->initialState.levels[0].gen2XSP = 1; |
else |
table->initialState.levels[0].gen2XSP = 0; |
if (pi->mem_gddr5) { |
table->initialState.levels[0].strobeMode = |
cypress_get_strobe_mode_settings(rdev, |
initial_state->low.mclk); |
if (initial_state->low.mclk > pi->mclk_edc_enable_threshold) |
table->initialState.levels[0].mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG; |
else |
table->initialState.levels[0].mcFlags = 0; |
} |
table->initialState.levels[1] = table->initialState.levels[0]; |
table->initialState.levels[2] = table->initialState.levels[0]; |
table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC; |
return 0; |
} |
int cypress_populate_smc_acpi_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 mpll_ad_func_cntl = |
pi->clk_regs.rv770.mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2 = |
pi->clk_regs.rv770.mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl = |
pi->clk_regs.rv770.mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2 = |
pi->clk_regs.rv770.mpll_dq_func_cntl_2; |
u32 spll_func_cntl = |
pi->clk_regs.rv770.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = |
pi->clk_regs.rv770.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = |
pi->clk_regs.rv770.cg_spll_func_cntl_3; |
u32 mclk_pwrmgt_cntl = |
pi->clk_regs.rv770.mclk_pwrmgt_cntl; |
u32 dll_cntl = |
pi->clk_regs.rv770.dll_cntl; |
table->ACPIState = table->initialState; |
table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC; |
if (pi->acpi_vddc) { |
cypress_populate_voltage_value(rdev, |
&eg_pi->vddc_voltage_table, |
pi->acpi_vddc, |
&table->ACPIState.levels[0].vddc); |
if (pi->pcie_gen2) { |
if (pi->acpi_pcie_gen2) |
table->ACPIState.levels[0].gen2PCIE = 1; |
else |
table->ACPIState.levels[0].gen2PCIE = 0; |
} else |
table->ACPIState.levels[0].gen2PCIE = 0; |
if (pi->acpi_pcie_gen2) |
table->ACPIState.levels[0].gen2XSP = 1; |
else |
table->ACPIState.levels[0].gen2XSP = 0; |
} else { |
cypress_populate_voltage_value(rdev, |
&eg_pi->vddc_voltage_table, |
pi->min_vddc_in_table, |
&table->ACPIState.levels[0].vddc); |
table->ACPIState.levels[0].gen2PCIE = 0; |
} |
if (eg_pi->acpi_vddci) { |
if (eg_pi->vddci_control) { |
cypress_populate_voltage_value(rdev, |
&eg_pi->vddci_voltage_table, |
eg_pi->acpi_vddci, |
&table->ACPIState.levels[0].vddci); |
} |
} |
mpll_ad_func_cntl &= ~PDNB; |
mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN; |
if (pi->mem_gddr5) |
mpll_dq_func_cntl &= ~PDNB; |
mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN | BYPASS; |
mclk_pwrmgt_cntl |= (MRDCKA0_RESET | |
MRDCKA1_RESET | |
MRDCKB0_RESET | |
MRDCKB1_RESET | |
MRDCKC0_RESET | |
MRDCKC1_RESET | |
MRDCKD0_RESET | |
MRDCKD1_RESET); |
mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB | |
MRDCKA1_PDNB | |
MRDCKB0_PDNB | |
MRDCKB1_PDNB | |
MRDCKC0_PDNB | |
MRDCKC1_PDNB | |
MRDCKD0_PDNB | |
MRDCKD1_PDNB); |
dll_cntl |= (MRDCKA0_BYPASS | |
MRDCKA1_BYPASS | |
MRDCKB0_BYPASS | |
MRDCKB1_BYPASS | |
MRDCKC0_BYPASS | |
MRDCKC1_BYPASS | |
MRDCKD0_BYPASS | |
MRDCKD1_BYPASS); |
/* evergreen only */ |
if (rdev->family <= CHIP_HEMLOCK) |
spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN; |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(4); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = |
cpu_to_be32(mpll_ad_func_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = |
cpu_to_be32(mpll_ad_func_cntl_2); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = |
cpu_to_be32(mpll_dq_func_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = |
cpu_to_be32(mpll_dq_func_cntl_2); |
table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = |
cpu_to_be32(mclk_pwrmgt_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl); |
table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0; |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = |
cpu_to_be32(spll_func_cntl); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = |
cpu_to_be32(spll_func_cntl_2); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = |
cpu_to_be32(spll_func_cntl_3); |
table->ACPIState.levels[0].sclk.sclk_value = 0; |
cypress_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd); |
if (eg_pi->dynamic_ac_timing) |
table->ACPIState.levels[0].ACIndex = 1; |
table->ACPIState.levels[1] = table->ACPIState.levels[0]; |
table->ACPIState.levels[2] = table->ACPIState.levels[0]; |
return 0; |
} |
static void cypress_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev, |
struct atom_voltage_table *voltage_table) |
{ |
unsigned int i, diff; |
if (voltage_table->count <= MAX_NO_VREG_STEPS) |
return; |
diff = voltage_table->count - MAX_NO_VREG_STEPS; |
for (i= 0; i < MAX_NO_VREG_STEPS; i++) |
voltage_table->entries[i] = voltage_table->entries[i + diff]; |
voltage_table->count = MAX_NO_VREG_STEPS; |
} |
int cypress_construct_voltage_tables(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
int ret; |
ret = radeon_atom_get_voltage_table(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0, |
&eg_pi->vddc_voltage_table); |
if (ret) |
return ret; |
if (eg_pi->vddc_voltage_table.count > MAX_NO_VREG_STEPS) |
cypress_trim_voltage_table_to_fit_state_table(rdev, |
&eg_pi->vddc_voltage_table); |
if (eg_pi->vddci_control) { |
ret = radeon_atom_get_voltage_table(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0, |
&eg_pi->vddci_voltage_table); |
if (ret) |
return ret; |
if (eg_pi->vddci_voltage_table.count > MAX_NO_VREG_STEPS) |
cypress_trim_voltage_table_to_fit_state_table(rdev, |
&eg_pi->vddci_voltage_table); |
} |
return 0; |
} |
static void cypress_populate_smc_voltage_table(struct radeon_device *rdev, |
struct atom_voltage_table *voltage_table, |
RV770_SMC_STATETABLE *table) |
{ |
unsigned int i; |
for (i = 0; i < voltage_table->count; i++) { |
table->highSMIO[i] = 0; |
table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low); |
} |
} |
int cypress_populate_smc_voltage_tables(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
unsigned char i; |
if (eg_pi->vddc_voltage_table.count) { |
cypress_populate_smc_voltage_table(rdev, |
&eg_pi->vddc_voltage_table, |
table); |
table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDC] = 0; |
table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDC] = |
cpu_to_be32(eg_pi->vddc_voltage_table.mask_low); |
for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) { |
if (pi->max_vddc_in_table <= |
eg_pi->vddc_voltage_table.entries[i].value) { |
table->maxVDDCIndexInPPTable = i; |
break; |
} |
} |
} |
if (eg_pi->vddci_voltage_table.count) { |
cypress_populate_smc_voltage_table(rdev, |
&eg_pi->vddci_voltage_table, |
table); |
table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDCI] = 0; |
table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDCI] = |
cpu_to_be32(eg_pi->vddci_voltage_table.mask_low); |
} |
return 0; |
} |
static u32 cypress_get_mclk_split_point(struct atom_memory_info *memory_info) |
{ |
if ((memory_info->mem_type == MEM_TYPE_GDDR3) || |
(memory_info->mem_type == MEM_TYPE_DDR3)) |
return 30000; |
return 0; |
} |
int cypress_get_mvdd_configuration(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u8 module_index; |
struct atom_memory_info memory_info; |
u32 tmp = RREG32(GENERAL_PWRMGT); |
if (!(tmp & BACKBIAS_PAD_EN)) { |
eg_pi->mvdd_high_index = 0; |
eg_pi->mvdd_low_index = 1; |
pi->mvdd_control = false; |
return 0; |
} |
if (tmp & BACKBIAS_VALUE) |
eg_pi->mvdd_high_index = 1; |
else |
eg_pi->mvdd_high_index = 0; |
eg_pi->mvdd_low_index = |
(eg_pi->mvdd_high_index == 0) ? 1 : 0; |
module_index = rv770_get_memory_module_index(rdev); |
if (radeon_atom_get_memory_info(rdev, module_index, &memory_info)) { |
pi->mvdd_control = false; |
return 0; |
} |
pi->mvdd_split_frequency = |
cypress_get_mclk_split_point(&memory_info); |
if (pi->mvdd_split_frequency == 0) { |
pi->mvdd_control = false; |
return 0; |
} |
return 0; |
} |
static int cypress_init_smc_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
RV770_SMC_STATETABLE *table = &pi->smc_statetable; |
int ret; |
memset(table, 0, sizeof(RV770_SMC_STATETABLE)); |
cypress_populate_smc_voltage_tables(rdev, table); |
switch (rdev->pm.int_thermal_type) { |
case THERMAL_TYPE_EVERGREEN: |
case THERMAL_TYPE_EMC2103_WITH_INTERNAL: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL; |
break; |
case THERMAL_TYPE_NONE: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE; |
break; |
default: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL; |
break; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT) |
table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; |
if (pi->mem_gddr5) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5; |
ret = cypress_populate_smc_initial_state(rdev, radeon_boot_state, table); |
if (ret) |
return ret; |
ret = cypress_populate_smc_acpi_state(rdev, table); |
if (ret) |
return ret; |
table->driverState = table->initialState; |
return rv770_copy_bytes_to_smc(rdev, |
pi->state_table_start, |
(u8 *)table, sizeof(RV770_SMC_STATETABLE), |
pi->sram_end); |
} |
int cypress_populate_mc_reg_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state); |
SMC_Evergreen_MCRegisters mc_reg_table = { 0 }; |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_seq_index, 1); |
cypress_populate_mc_reg_addresses(rdev, &mc_reg_table); |
cypress_convert_mc_reg_table_entry_to_smc(rdev, |
&boot_state->low, |
&mc_reg_table.data[0]); |
cypress_convert_mc_registers(&eg_pi->mc_reg_table.mc_reg_table_entry[0], |
&mc_reg_table.data[1], eg_pi->mc_reg_table.last, |
eg_pi->mc_reg_table.valid_flag); |
cypress_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, &mc_reg_table); |
return rv770_copy_bytes_to_smc(rdev, eg_pi->mc_reg_table_start, |
(u8 *)&mc_reg_table, sizeof(SMC_Evergreen_MCRegisters), |
pi->sram_end); |
} |
int cypress_get_table_locations(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = rv770_read_smc_sram_dword(rdev, |
EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION + |
EVERGREEN_SMC_FIRMWARE_HEADER_stateTable, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->state_table_start = (u16)tmp; |
ret = rv770_read_smc_sram_dword(rdev, |
EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION + |
EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->soft_regs_start = (u16)tmp; |
ret = rv770_read_smc_sram_dword(rdev, |
EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION + |
EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
eg_pi->mc_reg_table_start = (u16)tmp; |
return 0; |
} |
void cypress_enable_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); |
tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK); |
tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) | |
DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE)); |
tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); |
tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) | |
DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE)); |
WREG32(CG_DISPLAY_GAP_CNTL, tmp); |
} |
static void cypress_program_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp, pipe; |
int i; |
tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK); |
if (rdev->pm.dpm.new_active_crtc_count > 0) |
tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); |
else |
tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE); |
if (rdev->pm.dpm.new_active_crtc_count > 1) |
tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); |
else |
tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE); |
WREG32(CG_DISPLAY_GAP_CNTL, tmp); |
tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG); |
pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT; |
if ((rdev->pm.dpm.new_active_crtc_count > 0) && |
(!(rdev->pm.dpm.new_active_crtcs & (1 << pipe)))) { |
/* find the first active crtc */ |
for (i = 0; i < rdev->num_crtc; i++) { |
if (rdev->pm.dpm.new_active_crtcs & (1 << i)) |
break; |
} |
if (i == rdev->num_crtc) |
pipe = 0; |
else |
pipe = i; |
tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK; |
tmp |= DCCG_DISP1_SLOW_SELECT(pipe); |
WREG32(DCCG_DISP_SLOW_SELECT_REG, tmp); |
} |
cypress_notify_smc_display_change(rdev, rdev->pm.dpm.new_active_crtc_count > 0); |
} |
void cypress_dpm_setup_asic(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
rv740_read_clock_registers(rdev); |
rv770_read_voltage_smio_registers(rdev); |
rv770_get_max_vddc(rdev); |
rv770_get_memory_type(rdev); |
if (eg_pi->pcie_performance_request) |
eg_pi->pcie_performance_request_registered = false; |
if (eg_pi->pcie_performance_request) |
cypress_advertise_gen2_capability(rdev); |
rv770_get_pcie_gen2_status(rdev); |
rv770_enable_acpi_pm(rdev); |
} |
int cypress_dpm_enable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
int ret; |
if (pi->gfx_clock_gating) |
rv770_restore_cgcg(rdev); |
if (rv770_dpm_enabled(rdev)) |
return -EINVAL; |
if (pi->voltage_control) { |
rv770_enable_voltage_control(rdev, true); |
ret = cypress_construct_voltage_tables(rdev); |
if (ret) { |
DRM_ERROR("cypress_construct_voltage_tables failed\n"); |
return ret; |
} |
} |
if (pi->mvdd_control) { |
ret = cypress_get_mvdd_configuration(rdev); |
if (ret) { |
DRM_ERROR("cypress_get_mvdd_configuration failed\n"); |
return ret; |
} |
} |
if (eg_pi->dynamic_ac_timing) { |
cypress_set_mc_reg_address_table(rdev); |
cypress_force_mc_use_s0(rdev, boot_ps); |
ret = cypress_initialize_mc_reg_table(rdev); |
if (ret) |
eg_pi->dynamic_ac_timing = false; |
cypress_force_mc_use_s1(rdev, boot_ps); |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) |
rv770_enable_backbias(rdev, true); |
if (pi->dynamic_ss) |
cypress_enable_spread_spectrum(rdev, true); |
if (pi->thermal_protection) |
rv770_enable_thermal_protection(rdev, true); |
rv770_setup_bsp(rdev); |
rv770_program_git(rdev); |
rv770_program_tp(rdev); |
rv770_program_tpp(rdev); |
rv770_program_sstp(rdev); |
rv770_program_engine_speed_parameters(rdev); |
cypress_enable_display_gap(rdev); |
rv770_program_vc(rdev); |
if (pi->dynamic_pcie_gen2) |
cypress_enable_dynamic_pcie_gen2(rdev, true); |
ret = rv770_upload_firmware(rdev); |
if (ret) { |
DRM_ERROR("rv770_upload_firmware failed\n"); |
return ret; |
} |
ret = cypress_get_table_locations(rdev); |
if (ret) { |
DRM_ERROR("cypress_get_table_locations failed\n"); |
return ret; |
} |
ret = cypress_init_smc_table(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("cypress_init_smc_table failed\n"); |
return ret; |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = cypress_populate_mc_reg_table(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("cypress_populate_mc_reg_table failed\n"); |
return ret; |
} |
} |
cypress_program_response_times(rdev); |
r7xx_start_smc(rdev); |
ret = cypress_notify_smc_display_change(rdev, false); |
if (ret) { |
DRM_ERROR("cypress_notify_smc_display_change failed\n"); |
return ret; |
} |
cypress_enable_sclk_control(rdev, true); |
if (eg_pi->memory_transition) |
cypress_enable_mclk_control(rdev, true); |
cypress_start_dpm(rdev); |
if (pi->gfx_clock_gating) |
cypress_gfx_clock_gating_enable(rdev, true); |
if (pi->mg_clock_gating) |
cypress_mg_clock_gating_enable(rdev, true); |
rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); |
return 0; |
} |
void cypress_dpm_disable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
if (!rv770_dpm_enabled(rdev)) |
return; |
rv770_clear_vc(rdev); |
if (pi->thermal_protection) |
rv770_enable_thermal_protection(rdev, false); |
if (pi->dynamic_pcie_gen2) |
cypress_enable_dynamic_pcie_gen2(rdev, false); |
if (rdev->irq.installed && |
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { |
rdev->irq.dpm_thermal = false; |
radeon_irq_set(rdev); |
} |
if (pi->gfx_clock_gating) |
cypress_gfx_clock_gating_enable(rdev, false); |
if (pi->mg_clock_gating) |
cypress_mg_clock_gating_enable(rdev, false); |
rv770_stop_dpm(rdev); |
r7xx_stop_smc(rdev); |
cypress_enable_spread_spectrum(rdev, false); |
if (eg_pi->dynamic_ac_timing) |
cypress_force_mc_use_s1(rdev, boot_ps); |
rv770_reset_smio_status(rdev); |
} |
int cypress_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; |
struct radeon_ps *old_ps = rdev->pm.dpm.current_ps; |
int ret; |
ret = rv770_restrict_performance_levels_before_switch(rdev); |
if (ret) { |
DRM_ERROR("rv770_restrict_performance_levels_before_switch failed\n"); |
return ret; |
} |
if (eg_pi->pcie_performance_request) |
cypress_notify_link_speed_change_before_state_change(rdev, new_ps, old_ps); |
rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
ret = rv770_halt_smc(rdev); |
if (ret) { |
DRM_ERROR("rv770_halt_smc failed\n"); |
return ret; |
} |
ret = cypress_upload_sw_state(rdev, new_ps); |
if (ret) { |
DRM_ERROR("cypress_upload_sw_state failed\n"); |
return ret; |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = cypress_upload_mc_reg_table(rdev, new_ps); |
if (ret) { |
DRM_ERROR("cypress_upload_mc_reg_table failed\n"); |
return ret; |
} |
} |
cypress_program_memory_timing_parameters(rdev, new_ps); |
ret = rv770_resume_smc(rdev); |
if (ret) { |
DRM_ERROR("rv770_resume_smc failed\n"); |
return ret; |
} |
ret = rv770_set_sw_state(rdev); |
if (ret) { |
DRM_ERROR("rv770_set_sw_state failed\n"); |
return ret; |
} |
rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
if (eg_pi->pcie_performance_request) |
cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps); |
return 0; |
} |
void cypress_dpm_reset_asic(struct radeon_device *rdev) |
{ |
rv770_restrict_performance_levels_before_switch(rdev); |
rv770_set_boot_state(rdev); |
} |
void cypress_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
cypress_program_display_gap(rdev); |
} |
int cypress_dpm_init(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi; |
struct evergreen_power_info *eg_pi; |
struct atom_clock_dividers dividers; |
int ret; |
eg_pi = kzalloc(sizeof(struct evergreen_power_info), GFP_KERNEL); |
if (eg_pi == NULL) |
return -ENOMEM; |
rdev->pm.dpm.priv = eg_pi; |
pi = &eg_pi->rv7xx; |
rv770_get_max_vddc(rdev); |
eg_pi->ulv.supported = false; |
pi->acpi_vddc = 0; |
eg_pi->acpi_vddci = 0; |
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; |
if (rdev->pm.dpm.voltage_response_time == 0) |
rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; |
if (rdev->pm.dpm.backbias_response_time == 0) |
rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
0, false, ÷rs); |
if (ret) |
pi->ref_div = dividers.ref_div + 1; |
else |
pi->ref_div = R600_REFERENCEDIVIDER_DFLT; |
pi->mclk_strobe_mode_threshold = 40000; |
pi->mclk_edc_enable_threshold = 40000; |
eg_pi->mclk_edc_wr_enable_threshold = 40000; |
pi->rlp = RV770_RLP_DFLT; |
pi->rmp = RV770_RMP_DFLT; |
pi->lhp = RV770_LHP_DFLT; |
pi->lmp = RV770_LMP_DFLT; |
pi->voltage_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0); |
pi->mvdd_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0); |
eg_pi->vddci_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0); |
rv770_get_engine_memory_ss(rdev); |
pi->asi = RV770_ASI_DFLT; |
pi->pasi = CYPRESS_HASI_DFLT; |
pi->vrc = CYPRESS_VRC_DFLT; |
pi->power_gating = false; |
if ((rdev->family == CHIP_CYPRESS) || |
(rdev->family == CHIP_HEMLOCK)) |
pi->gfx_clock_gating = false; |
else |
pi->gfx_clock_gating = true; |
pi->mg_clock_gating = true; |
pi->mgcgtssm = true; |
eg_pi->ls_clock_gating = false; |
eg_pi->sclk_deep_sleep = false; |
pi->dynamic_pcie_gen2 = true; |
if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) |
pi->thermal_protection = true; |
else |
pi->thermal_protection = false; |
pi->display_gap = true; |
if (rdev->flags & RADEON_IS_MOBILITY) |
pi->dcodt = true; |
else |
pi->dcodt = false; |
pi->ulps = true; |
eg_pi->dynamic_ac_timing = true; |
eg_pi->abm = true; |
eg_pi->mcls = true; |
eg_pi->light_sleep = true; |
eg_pi->memory_transition = true; |
#if defined(CONFIG_ACPI) |
eg_pi->pcie_performance_request = |
radeon_acpi_is_pcie_performance_request_supported(rdev); |
#else |
eg_pi->pcie_performance_request = false; |
#endif |
if ((rdev->family == CHIP_CYPRESS) || |
(rdev->family == CHIP_HEMLOCK) || |
(rdev->family == CHIP_JUNIPER)) |
eg_pi->dll_default_on = true; |
else |
eg_pi->dll_default_on = false; |
eg_pi->sclk_deep_sleep = false; |
pi->mclk_stutter_mode_threshold = 0; |
pi->sram_end = SMC_RAM_END; |
return 0; |
} |
void cypress_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
} |
bool cypress_dpm_vblank_too_short(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 vblank_time = r600_dpm_get_vblank_time(rdev); |
/* we never hit the non-gddr5 limit so disable it */ |
u32 switch_limit = pi->mem_gddr5 ? 450 : 0; |
if (vblank_time < switch_limit) |
return true; |
else |
return false; |
} |
/drivers/video/drm/radeon/cypress_dpm.h |
---|
0,0 → 1,160 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __CYPRESS_DPM_H__ |
#define __CYPRESS_DPM_H__ |
#include "rv770_dpm.h" |
#include "evergreen_smc.h" |
struct evergreen_mc_reg_entry { |
u32 mclk_max; |
u32 mc_data[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE]; |
}; |
struct evergreen_mc_reg_table { |
u8 last; |
u8 num_entries; |
u16 valid_flag; |
struct evergreen_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES]; |
SMC_Evergreen_MCRegisterAddress mc_reg_address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE]; |
}; |
struct evergreen_ulv_param { |
bool supported; |
struct rv7xx_pl *pl; |
}; |
struct evergreen_arb_registers { |
u32 mc_arb_dram_timing; |
u32 mc_arb_dram_timing2; |
u32 mc_arb_rfsh_rate; |
u32 mc_arb_burst_time; |
}; |
struct at { |
u32 rlp; |
u32 rmp; |
u32 lhp; |
u32 lmp; |
}; |
struct evergreen_power_info { |
/* must be first! */ |
struct rv7xx_power_info rv7xx; |
/* flags */ |
bool vddci_control; |
bool dynamic_ac_timing; |
bool abm; |
bool mcls; |
bool light_sleep; |
bool memory_transition; |
bool pcie_performance_request; |
bool pcie_performance_request_registered; |
bool sclk_deep_sleep; |
bool dll_default_on; |
bool ls_clock_gating; |
bool smu_uvd_hs; |
bool uvd_enabled; |
/* stored values */ |
u16 acpi_vddci; |
u8 mvdd_high_index; |
u8 mvdd_low_index; |
u32 mclk_edc_wr_enable_threshold; |
struct evergreen_mc_reg_table mc_reg_table; |
struct atom_voltage_table vddc_voltage_table; |
struct atom_voltage_table vddci_voltage_table; |
struct evergreen_arb_registers bootup_arb_registers; |
struct evergreen_ulv_param ulv; |
struct at ats[2]; |
/* smc offsets */ |
u16 mc_reg_table_start; |
struct radeon_ps current_rps; |
struct rv7xx_ps current_ps; |
struct radeon_ps requested_rps; |
struct rv7xx_ps requested_ps; |
}; |
#define CYPRESS_HASI_DFLT 400000 |
#define CYPRESS_MGCGTTLOCAL0_DFLT 0x00000000 |
#define CYPRESS_MGCGTTLOCAL1_DFLT 0x00000000 |
#define CYPRESS_MGCGTTLOCAL2_DFLT 0x00000000 |
#define CYPRESS_MGCGTTLOCAL3_DFLT 0x00000000 |
#define CYPRESS_MGCGCGTSSMCTRL_DFLT 0x81944bc0 |
#define REDWOOD_MGCGCGTSSMCTRL_DFLT 0x6e944040 |
#define CEDAR_MGCGCGTSSMCTRL_DFLT 0x46944040 |
#define CYPRESS_VRC_DFLT 0xC00033 |
#define PCIE_PERF_REQ_REMOVE_REGISTRY 0 |
#define PCIE_PERF_REQ_FORCE_LOWPOWER 1 |
#define PCIE_PERF_REQ_PECI_GEN1 2 |
#define PCIE_PERF_REQ_PECI_GEN2 3 |
#define PCIE_PERF_REQ_PECI_GEN3 4 |
int cypress_convert_power_level_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
RV770_SMC_HW_PERFORMANCE_LEVEL *level, |
u8 watermark_level); |
int cypress_populate_smc_acpi_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table); |
int cypress_populate_smc_voltage_tables(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table); |
int cypress_populate_smc_initial_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_initial_state, |
RV770_SMC_STATETABLE *table); |
u32 cypress_calculate_burst_time(struct radeon_device *rdev, |
u32 engine_clock, u32 memory_clock); |
void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state); |
int cypress_upload_sw_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state); |
int cypress_upload_mc_reg_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state); |
void cypress_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state); |
void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state); |
int cypress_construct_voltage_tables(struct radeon_device *rdev); |
int cypress_get_mvdd_configuration(struct radeon_device *rdev); |
void cypress_enable_spread_spectrum(struct radeon_device *rdev, |
bool enable); |
void cypress_enable_display_gap(struct radeon_device *rdev); |
int cypress_get_table_locations(struct radeon_device *rdev); |
int cypress_populate_mc_reg_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state); |
void cypress_program_response_times(struct radeon_device *rdev); |
int cypress_notify_smc_display_change(struct radeon_device *rdev, |
bool has_display); |
void cypress_enable_sclk_control(struct radeon_device *rdev, |
bool enable); |
void cypress_enable_mclk_control(struct radeon_device *rdev, |
bool enable); |
void cypress_start_dpm(struct radeon_device *rdev); |
void cypress_advertise_gen2_capability(struct radeon_device *rdev); |
u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf); |
u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev, |
u32 memory_clock, bool strobe_mode); |
u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk); |
#endif |
/drivers/video/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); |
} |
/drivers/video/drm/radeon/dce6_afmt.c |
---|
0,0 → 1,356 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include <linux/hdmi.h> |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "sid.h" |
static u32 dce6_endpoint_rreg(struct radeon_device *rdev, |
u32 block_offset, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->end_idx_lock, flags); |
WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg); |
r = RREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset); |
spin_unlock_irqrestore(&rdev->end_idx_lock, flags); |
return r; |
} |
static void dce6_endpoint_wreg(struct radeon_device *rdev, |
u32 block_offset, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->end_idx_lock, flags); |
if (ASIC_IS_DCE8(rdev)) |
WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg); |
else |
WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, |
AZ_ENDPOINT_REG_WRITE_EN | AZ_ENDPOINT_REG_INDEX(reg)); |
WREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset, v); |
spin_unlock_irqrestore(&rdev->end_idx_lock, flags); |
} |
#define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg)) |
#define WREG32_ENDPOINT(block, reg, v) dce6_endpoint_wreg(rdev, (block), (reg), (v)) |
static void dce6_afmt_get_connected_pins(struct radeon_device *rdev) |
{ |
int i; |
u32 offset, tmp; |
for (i = 0; i < rdev->audio.num_pins; i++) { |
offset = rdev->audio.pin[i].offset; |
tmp = RREG32_ENDPOINT(offset, |
AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT); |
if (((tmp & PORT_CONNECTIVITY_MASK) >> PORT_CONNECTIVITY_SHIFT) == 1) |
rdev->audio.pin[i].connected = false; |
else |
rdev->audio.pin[i].connected = true; |
} |
} |
struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev) |
{ |
int i; |
dce6_afmt_get_connected_pins(rdev); |
for (i = 0; i < rdev->audio.num_pins; i++) { |
if (rdev->audio.pin[i].connected) |
return &rdev->audio.pin[i]; |
} |
DRM_ERROR("No connected audio pins found!\n"); |
return NULL; |
} |
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; |
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(0) | AUDIO_LIPSYNC(0); |
} else { |
if (connector->latency_present[0]) |
tmp = VIDEO_LIPSYNC(connector->video_latency[0]) | |
AUDIO_LIPSYNC(connector->audio_latency[0]); |
else |
tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0); |
} |
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; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector = NULL; |
u32 offset, tmp; |
u8 *sadb; |
int sad_count; |
if (!dig || !dig->afmt || !dig->afmt->pin) |
return; |
offset = dig->afmt->pin->offset; |
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { |
if (connector->encoder == encoder) { |
radeon_connector = to_radeon_connector(connector); |
break; |
} |
} |
if (!radeon_connector) { |
DRM_ERROR("Couldn't find encoder's connector\n"); |
return; |
} |
sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); |
if (sad_count <= 0) { |
DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); |
return; |
} |
/* program the speaker allocation */ |
tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_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_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp); |
kfree(sadb); |
} |
void dce6_afmt_write_sad_regs(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; |
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_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP }, |
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO }, |
}; |
if (!dig || !dig->afmt || !dig->afmt->pin) |
return; |
offset = dig->afmt->pin->offset; |
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { |
if (connector->encoder == encoder) { |
radeon_connector = to_radeon_connector(connector); |
break; |
} |
} |
if (!radeon_connector) { |
DRM_ERROR("Couldn't find encoder's connector\n"); |
return; |
} |
sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); |
if (sad_count <= 0) { |
DRM_ERROR("Couldn't read SADs: %d\n", sad_count); |
return; |
} |
BUG_ON(!sads); |
for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { |
u32 value = 0; |
u8 stereo_freqs = 0; |
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_ENDPOINT(offset, eld_reg_to_type[i][0], value); |
} |
kfree(sads); |
} |
static int dce6_audio_chipset_supported(struct radeon_device *rdev) |
{ |
return !ASIC_IS_NODCE(rdev); |
} |
void dce6_audio_enable(struct radeon_device *rdev, |
struct r600_audio_pin *pin, |
bool enable) |
{ |
if (!pin) |
return; |
WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL, |
enable ? AUDIO_ENABLED : 0); |
} |
static const u32 pin_offsets[7] = |
{ |
(0x5e00 - 0x5e00), |
(0x5e18 - 0x5e00), |
(0x5e30 - 0x5e00), |
(0x5e48 - 0x5e00), |
(0x5e60 - 0x5e00), |
(0x5e78 - 0x5e00), |
(0x5e90 - 0x5e00), |
}; |
int dce6_audio_init(struct radeon_device *rdev) |
{ |
int i; |
if (!radeon_audio || !dce6_audio_chipset_supported(rdev)) |
return 0; |
rdev->audio.enabled = true; |
if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */ |
rdev->audio.num_pins = 7; |
else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */ |
rdev->audio.num_pins = 3; |
else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */ |
rdev->audio.num_pins = 7; |
else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */ |
rdev->audio.num_pins = 6; |
else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */ |
rdev->audio.num_pins = 2; |
else /* SI: 6 streams, 6 endpoints */ |
rdev->audio.num_pins = 6; |
for (i = 0; i < rdev->audio.num_pins; i++) { |
rdev->audio.pin[i].channels = -1; |
rdev->audio.pin[i].rate = -1; |
rdev->audio.pin[i].bits_per_sample = -1; |
rdev->audio.pin[i].status_bits = 0; |
rdev->audio.pin[i].category_code = 0; |
rdev->audio.pin[i].connected = false; |
rdev->audio.pin[i].offset = pin_offsets[i]; |
rdev->audio.pin[i].id = i; |
/* disable audio. it will be set up later */ |
dce6_audio_enable(rdev, &rdev->audio.pin[i], false); |
} |
return 0; |
} |
void dce6_audio_fini(struct radeon_device *rdev) |
{ |
int i; |
if (!rdev->audio.enabled) |
return; |
for (i = 0; i < rdev->audio.num_pins; i++) |
dce6_audio_enable(rdev, &rdev->audio.pin[i], false); |
rdev->audio.enabled = false; |
} |
/drivers/video/drm/radeon/display.h |
---|
47,7 → 47,7 |
}; |
extern display_t *rdisplay; |
extern display_t *os_display; |
int init_cursor(cursor_t *cursor); |
void __stdcall restore_cursor(int x, int y); |
/drivers/video/drm/radeon/evergreen.c |
---|
33,10 → 33,8 |
#include "avivod.h" |
#include "evergreen_reg.h" |
#include "evergreen_blit_shaders.h" |
#include "radeon_ucode.h" |
#define EVERGREEN_PFP_UCODE_SIZE 1120 |
#define EVERGREEN_PM4_UCODE_SIZE 1376 |
static const u32 crtc_offsets[6] = |
{ |
EVERGREEN_CRTC0_REGISTER_OFFSET, |
47,12 → 45,109 |
EVERGREEN_CRTC5_REGISTER_OFFSET |
}; |
#include "clearstate_evergreen.h" |
static const u32 sumo_rlc_save_restore_register_list[] = |
{ |
0x98fc, |
0x9830, |
0x9834, |
0x9838, |
0x9870, |
0x9874, |
0x8a14, |
0x8b24, |
0x8bcc, |
0x8b10, |
0x8d00, |
0x8d04, |
0x8c00, |
0x8c04, |
0x8c08, |
0x8c0c, |
0x8d8c, |
0x8c20, |
0x8c24, |
0x8c28, |
0x8c18, |
0x8c1c, |
0x8cf0, |
0x8e2c, |
0x8e38, |
0x8c30, |
0x9508, |
0x9688, |
0x9608, |
0x960c, |
0x9610, |
0x9614, |
0x88c4, |
0x88d4, |
0xa008, |
0x900c, |
0x9100, |
0x913c, |
0x98f8, |
0x98f4, |
0x9b7c, |
0x3f8c, |
0x8950, |
0x8954, |
0x8a18, |
0x8b28, |
0x9144, |
0x9148, |
0x914c, |
0x3f90, |
0x3f94, |
0x915c, |
0x9160, |
0x9178, |
0x917c, |
0x9180, |
0x918c, |
0x9190, |
0x9194, |
0x9198, |
0x919c, |
0x91a8, |
0x91ac, |
0x91b0, |
0x91b4, |
0x91b8, |
0x91c4, |
0x91c8, |
0x91cc, |
0x91d0, |
0x91d4, |
0x91e0, |
0x91e4, |
0x91ec, |
0x91f0, |
0x91f4, |
0x9200, |
0x9204, |
0x929c, |
0x9150, |
0x802c, |
}; |
static void evergreen_gpu_init(struct radeon_device *rdev); |
void evergreen_fini(struct radeon_device *rdev); |
void evergreen_pcie_gen2_enable(struct radeon_device *rdev); |
void evergreen_program_aspm(struct radeon_device *rdev); |
extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev, |
int ring, u32 cp_int_cntl); |
extern void cayman_vm_decode_fault(struct radeon_device *rdev, |
u32 status, u32 addr); |
void cik_init_cp_pg_table(struct radeon_device *rdev); |
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[] = |
{ |
0x3f90, 0xffff0000, 0xff000000, |
94,7 → 189,7 |
0x8c1c, 0xffffffff, 0x00001010, |
0x28350, 0xffffffff, 0x00000000, |
0xa008, 0xffffffff, 0x00010000, |
0x5cc, 0xffffffff, 0x00000001, |
0x5c4, 0xffffffff, 0x00000001, |
0x9508, 0xffffffff, 0x00000002, |
0x913c, 0x0000000f, 0x0000000a |
}; |
381,7 → 476,7 |
0x8c1c, 0xffffffff, 0x00001010, |
0x28350, 0xffffffff, 0x00000000, |
0xa008, 0xffffffff, 0x00010000, |
0x5cc, 0xffffffff, 0x00000001, |
0x5c4, 0xffffffff, 0x00000001, |
0x9508, 0xffffffff, 0x00000002 |
}; |
540,7 → 635,7 |
static const u32 supersumo_golden_registers[] = |
{ |
0x5eb4, 0xffffffff, 0x00000002, |
0x5cc, 0xffffffff, 0x00000001, |
0x5c4, 0xffffffff, 0x00000001, |
0x7030, 0xffffffff, 0x00000011, |
0x7c30, 0xffffffff, 0x00000011, |
0x6104, 0x01000300, 0x00000000, |
624,7 → 719,7 |
static const u32 wrestler_golden_registers[] = |
{ |
0x5eb4, 0xffffffff, 0x00000002, |
0x5cc, 0xffffffff, 0x00000001, |
0x5c4, 0xffffffff, 0x00000001, |
0x7030, 0xffffffff, 0x00000011, |
0x7c30, 0xffffffff, 0x00000011, |
0x6104, 0x01000300, 0x00000000, |
1080,25 → 1175,74 |
void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev) |
{ |
u16 ctl, v; |
int err; |
int readrq; |
u16 v; |
err = pcie_capability_read_word(rdev->pdev, PCI_EXP_DEVCTL, &ctl); |
if (err) |
return; |
v = (ctl & PCI_EXP_DEVCTL_READRQ) >> 12; |
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) |
{ |
if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK) |
1156,7 → 1300,6 |
} |
} |
/** |
* evergreen_page_flip - pageflip callback. |
* |
1170,7 → 1313,7 |
* 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); |
1202,9 → 1345,23 |
/* 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 */ |
1388,8 → 1545,8 |
struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; |
if (voltage->type == VOLTAGE_SW) { |
/* 0xff01 is a flag rather then an actual voltage */ |
if (voltage->voltage == 0xff01) |
/* 0xff0x are flags rather then an actual voltage */ |
if ((voltage->voltage & 0xff00) == 0xff00) |
return; |
if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) { |
radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); |
1409,8 → 1566,8 |
voltage = &rdev->pm.power_state[req_ps_idx]. |
clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].voltage; |
/* 0xff01 is a flag rather then an actual voltage */ |
if (voltage->vddci == 0xff01) |
/* 0xff0x are flags rather then an actual voltage */ |
if ((voltage->vddci & 0xff00) == 0xff00) |
return; |
if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) { |
radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI); |
1689,7 → 1846,8 |
struct drm_display_mode *mode, |
struct drm_display_mode *other_mode) |
{ |
u32 tmp; |
u32 tmp, buffer_alloc, i; |
u32 pipe_offset = radeon_crtc->crtc_id * 0x20; |
/* |
* Line Buffer Setup |
* There are 3 line buffers, each one shared by 2 display controllers. |
1712,12 → 1870,17 |
* non-linked crtcs for maximum line buffer allocation. |
*/ |
if (radeon_crtc->base.enabled && mode) { |
if (other_mode) |
if (other_mode) { |
tmp = 0; /* 1/2 */ |
else |
buffer_alloc = 1; |
} else { |
tmp = 2; /* whole */ |
} else |
buffer_alloc = 2; |
} |
} else { |
tmp = 0; |
buffer_alloc = 0; |
} |
/* second controller of the pair uses second half of the lb */ |
if (radeon_crtc->crtc_id % 2) |
1724,6 → 1887,17 |
tmp += 4; |
WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp); |
if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { |
WREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset, |
DMIF_BUFFERS_ALLOCATED(buffer_alloc)); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset) & |
DMIF_BUFFERS_ALLOCATED_COMPLETED) |
break; |
udelay(1); |
} |
} |
if (radeon_crtc->base.enabled && mode) { |
switch (tmp) { |
case 0: |
2007,7 → 2181,8 |
u32 lb_size, u32 num_heads) |
{ |
struct drm_display_mode *mode = &radeon_crtc->base.mode; |
struct evergreen_wm_params wm; |
struct evergreen_wm_params wm_low, wm_high; |
u32 dram_channels; |
u32 pixel_period; |
u32 line_time = 0; |
u32 latency_watermark_a = 0, latency_watermark_b = 0; |
2023,39 → 2198,81 |
line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535); |
priority_a_cnt = 0; |
priority_b_cnt = 0; |
dram_channels = evergreen_get_number_of_dram_channels(rdev); |
wm.yclk = rdev->pm.current_mclk * 10; |
wm.sclk = rdev->pm.current_sclk * 10; |
wm.disp_clk = mode->clock; |
wm.src_width = mode->crtc_hdisplay; |
wm.active_time = mode->crtc_hdisplay * pixel_period; |
wm.blank_time = line_time - wm.active_time; |
wm.interlaced = false; |
/* watermark for high clocks */ |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { |
wm_high.yclk = |
radeon_dpm_get_mclk(rdev, false) * 10; |
wm_high.sclk = |
radeon_dpm_get_sclk(rdev, false) * 10; |
} else { |
wm_high.yclk = rdev->pm.current_mclk * 10; |
wm_high.sclk = rdev->pm.current_sclk * 10; |
} |
wm_high.disp_clk = mode->clock; |
wm_high.src_width = mode->crtc_hdisplay; |
wm_high.active_time = mode->crtc_hdisplay * pixel_period; |
wm_high.blank_time = line_time - wm_high.active_time; |
wm_high.interlaced = false; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
wm.interlaced = true; |
wm.vsc = radeon_crtc->vsc; |
wm.vtaps = 1; |
wm_high.interlaced = true; |
wm_high.vsc = radeon_crtc->vsc; |
wm_high.vtaps = 1; |
if (radeon_crtc->rmx_type != RMX_OFF) |
wm.vtaps = 2; |
wm.bytes_per_pixel = 4; /* XXX: get this from fb config */ |
wm.lb_size = lb_size; |
wm.dram_channels = evergreen_get_number_of_dram_channels(rdev); |
wm.num_heads = num_heads; |
wm_high.vtaps = 2; |
wm_high.bytes_per_pixel = 4; /* XXX: get this from fb config */ |
wm_high.lb_size = lb_size; |
wm_high.dram_channels = dram_channels; |
wm_high.num_heads = num_heads; |
/* watermark for low clocks */ |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { |
wm_low.yclk = |
radeon_dpm_get_mclk(rdev, true) * 10; |
wm_low.sclk = |
radeon_dpm_get_sclk(rdev, true) * 10; |
} else { |
wm_low.yclk = rdev->pm.current_mclk * 10; |
wm_low.sclk = rdev->pm.current_sclk * 10; |
} |
wm_low.disp_clk = mode->clock; |
wm_low.src_width = mode->crtc_hdisplay; |
wm_low.active_time = mode->crtc_hdisplay * pixel_period; |
wm_low.blank_time = line_time - wm_low.active_time; |
wm_low.interlaced = false; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
wm_low.interlaced = true; |
wm_low.vsc = radeon_crtc->vsc; |
wm_low.vtaps = 1; |
if (radeon_crtc->rmx_type != RMX_OFF) |
wm_low.vtaps = 2; |
wm_low.bytes_per_pixel = 4; /* XXX: get this from fb config */ |
wm_low.lb_size = lb_size; |
wm_low.dram_channels = dram_channels; |
wm_low.num_heads = num_heads; |
/* set for high clocks */ |
latency_watermark_a = min(evergreen_latency_watermark(&wm), (u32)65535); |
latency_watermark_a = min(evergreen_latency_watermark(&wm_high), (u32)65535); |
/* set for low clocks */ |
/* wm.yclk = low clk; wm.sclk = low clk */ |
latency_watermark_b = min(evergreen_latency_watermark(&wm), (u32)65535); |
latency_watermark_b = min(evergreen_latency_watermark(&wm_low), (u32)65535); |
/* possibly force display priority to high */ |
/* should really do this at mode validation time... */ |
if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm) || |
!evergreen_average_bandwidth_vs_available_bandwidth(&wm) || |
!evergreen_check_latency_hiding(&wm) || |
if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) || |
!evergreen_average_bandwidth_vs_available_bandwidth(&wm_high) || |
!evergreen_check_latency_hiding(&wm_high) || |
(rdev->disp_priority == 2)) { |
DRM_DEBUG_KMS("force priority to high\n"); |
DRM_DEBUG_KMS("force priority a to high\n"); |
priority_a_cnt |= PRIORITY_ALWAYS_ON; |
} |
if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) || |
!evergreen_average_bandwidth_vs_available_bandwidth(&wm_low) || |
!evergreen_check_latency_hiding(&wm_low) || |
(rdev->disp_priority == 2)) { |
DRM_DEBUG_KMS("force priority b to high\n"); |
priority_b_cnt |= PRIORITY_ALWAYS_ON; |
} |
2108,6 → 2325,10 |
WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt); |
WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt); |
/* save values for DPM */ |
radeon_crtc->line_time = line_time; |
radeon_crtc->wm_high = latency_watermark_a; |
radeon_crtc->wm_low = latency_watermark_b; |
} |
/** |
2203,7 → 2424,6 |
r = radeon_gart_table_vram_pin(rdev); |
if (r) |
return r; |
radeon_gart_restore(rdev); |
/* Setup L2 cache */ |
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | |
ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE | |
2421,8 → 2641,9 |
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]); |
2455,7 → 2676,7 |
if (save->crtc_enabled[i]) { |
if (ASIC_IS_DCE6(rdev)) { |
tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); |
tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; |
tmp &= ~EVERGREEN_CRTC_BLANK_DATA_EN; |
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); |
WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); |
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); |
2648,7 → 2869,7 |
radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, 0); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
cp_me = 0xff; |
WREG32(CP_ME_CNTL, cp_me); |
2691,7 → 2912,7 |
radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ |
radeon_ring_write(ring, 0x00000010); /* */ |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
return 0; |
} |
2716,8 → 2937,8 |
RREG32(GRBM_SOFT_RESET); |
/* Set ring buffer size */ |
rb_bufsz = drm_order(ring->ring_size / 8); |
tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
rb_bufsz = order_base_2(ring->ring_size / 8); |
tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
#ifdef __BIG_ENDIAN |
tmp |= BUF_SWAP_32BIT; |
#endif |
2753,8 → 2974,6 |
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); |
2944,7 → 3163,7 |
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; |
3091,10 → 3310,8 |
u32 efuse_straps_4; |
u32 efuse_straps_3; |
WREG32(RCU_IND_INDEX, 0x204); |
efuse_straps_4 = RREG32(RCU_IND_DATA); |
WREG32(RCU_IND_INDEX, 0x203); |
efuse_straps_3 = RREG32(RCU_IND_DATA); |
efuse_straps_4 = RREG32_RCU(0x204); |
efuse_straps_3 = RREG32_RCU(0x203); |
tmp = (((efuse_straps_4 & 0xf) << 4) | |
((efuse_straps_3 & 0xf0000000) >> 28)); |
} else { |
3120,6 → 3337,18 |
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); |
3450,7 → 3679,7 |
return true; |
} |
static u32 evergreen_gpu_check_soft_reset(struct radeon_device *rdev) |
u32 evergreen_gpu_check_soft_reset(struct radeon_device *rdev) |
{ |
u32 reset_mask = 0; |
u32 tmp; |
3633,6 → 3862,48 |
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; |
3642,10 → 3913,17 |
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); |
3668,36 → 3946,356 |
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); |
} |
/** |
* evergreen_dma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up. |
* Returns true if the engine appears to be locked up, false if not. |
/* |
* RLC |
*/ |
bool evergreen_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) |
#define RLC_SAVE_RESTORE_LIST_END_MARKER 0x00000000 |
#define RLC_CLEAR_STATE_END_MARKER 0x00000001 |
void sumo_rlc_fini(struct radeon_device *rdev) |
{ |
u32 reset_mask = evergreen_gpu_check_soft_reset(rdev); |
int r; |
if (!(reset_mask & RADEON_RESET_DMA)) { |
radeon_ring_lockup_update(ring); |
return false; |
/* save restore block */ |
if (rdev->rlc.save_restore_obj) { |
r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false); |
if (unlikely(r != 0)) |
dev_warn(rdev->dev, "(%d) reserve RLC sr bo failed\n", r); |
radeon_bo_unpin(rdev->rlc.save_restore_obj); |
radeon_bo_unreserve(rdev->rlc.save_restore_obj); |
radeon_bo_unref(&rdev->rlc.save_restore_obj); |
rdev->rlc.save_restore_obj = NULL; |
} |
/* force ring activities */ |
radeon_ring_force_activity(rdev, ring); |
return radeon_ring_test_lockup(rdev, ring); |
/* clear state block */ |
if (rdev->rlc.clear_state_obj) { |
r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false); |
if (unlikely(r != 0)) |
dev_warn(rdev->dev, "(%d) reserve RLC c bo failed\n", r); |
radeon_bo_unpin(rdev->rlc.clear_state_obj); |
radeon_bo_unreserve(rdev->rlc.clear_state_obj); |
radeon_bo_unref(&rdev->rlc.clear_state_obj); |
rdev->rlc.clear_state_obj = NULL; |
} |
/* clear state block */ |
if (rdev->rlc.cp_table_obj) { |
r = radeon_bo_reserve(rdev->rlc.cp_table_obj, false); |
if (unlikely(r != 0)) |
dev_warn(rdev->dev, "(%d) reserve RLC cp table bo failed\n", r); |
radeon_bo_unpin(rdev->rlc.cp_table_obj); |
radeon_bo_unreserve(rdev->rlc.cp_table_obj); |
radeon_bo_unref(&rdev->rlc.cp_table_obj); |
rdev->rlc.cp_table_obj = NULL; |
} |
} |
#define CP_ME_TABLE_SIZE 96 |
int sumo_rlc_init(struct radeon_device *rdev) |
{ |
const u32 *src_ptr; |
volatile u32 *dst_ptr; |
u32 dws, data, i, j, k, reg_num; |
u32 reg_list_num, reg_list_hdr_blk_index, reg_list_blk_index = 0; |
u64 reg_list_mc_addr; |
const struct cs_section_def *cs_data; |
int r; |
src_ptr = rdev->rlc.reg_list; |
dws = rdev->rlc.reg_list_size; |
if (rdev->family >= CHIP_BONAIRE) { |
dws += (5 * 16) + 48 + 48 + 64; |
} |
cs_data = rdev->rlc.cs_data; |
if (src_ptr) { |
/* save restore block */ |
if (rdev->rlc.save_restore_obj == NULL) { |
r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, 0, NULL, |
&rdev->rlc.save_restore_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r); |
return r; |
} |
} |
r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false); |
if (unlikely(r != 0)) { |
sumo_rlc_fini(rdev); |
return r; |
} |
r = radeon_bo_pin(rdev->rlc.save_restore_obj, RADEON_GEM_DOMAIN_VRAM, |
&rdev->rlc.save_restore_gpu_addr); |
if (r) { |
radeon_bo_unreserve(rdev->rlc.save_restore_obj); |
dev_warn(rdev->dev, "(%d) pin RLC sr bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
r = radeon_bo_kmap(rdev->rlc.save_restore_obj, (void **)&rdev->rlc.sr_ptr); |
if (r) { |
dev_warn(rdev->dev, "(%d) map RLC sr bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
/* write the sr buffer */ |
dst_ptr = rdev->rlc.sr_ptr; |
if (rdev->family >= CHIP_TAHITI) { |
/* SI */ |
for (i = 0; i < rdev->rlc.reg_list_size; i++) |
dst_ptr[i] = cpu_to_le32(src_ptr[i]); |
} else { |
/* ON/LN/TN */ |
/* format: |
* dw0: (reg2 << 16) | reg1 |
* dw1: reg1 save space |
* dw2: reg2 save space |
*/ |
for (i = 0; i < dws; i++) { |
data = src_ptr[i] >> 2; |
i++; |
if (i < dws) |
data |= (src_ptr[i] >> 2) << 16; |
j = (((i - 1) * 3) / 2); |
dst_ptr[j] = cpu_to_le32(data); |
} |
j = ((i * 3) / 2); |
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); |
} |
if (cs_data) { |
/* clear state block */ |
if (rdev->family >= CHIP_BONAIRE) { |
rdev->rlc.clear_state_size = dws = cik_get_csb_size(rdev); |
} else if (rdev->family >= CHIP_TAHITI) { |
rdev->rlc.clear_state_size = si_get_csb_size(rdev); |
dws = rdev->rlc.clear_state_size + (256 / 4); |
} else { |
reg_list_num = 0; |
dws = 0; |
for (i = 0; cs_data[i].section != NULL; i++) { |
for (j = 0; cs_data[i].section[j].extent != NULL; j++) { |
reg_list_num++; |
dws += cs_data[i].section[j].reg_count; |
} |
} |
reg_list_blk_index = (3 * reg_list_num + 2); |
dws += reg_list_blk_index; |
rdev->rlc.clear_state_size = dws; |
} |
if (rdev->rlc.clear_state_obj == NULL) { |
r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, 0, NULL, |
&rdev->rlc.clear_state_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
} |
r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false); |
if (unlikely(r != 0)) { |
sumo_rlc_fini(rdev); |
return r; |
} |
r = radeon_bo_pin(rdev->rlc.clear_state_obj, RADEON_GEM_DOMAIN_VRAM, |
&rdev->rlc.clear_state_gpu_addr); |
if (r) { |
radeon_bo_unreserve(rdev->rlc.clear_state_obj); |
dev_warn(rdev->dev, "(%d) pin RLC c bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
r = radeon_bo_kmap(rdev->rlc.clear_state_obj, (void **)&rdev->rlc.cs_ptr); |
if (r) { |
dev_warn(rdev->dev, "(%d) map RLC c bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
/* set up the cs buffer */ |
dst_ptr = rdev->rlc.cs_ptr; |
if (rdev->family >= CHIP_BONAIRE) { |
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] = 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] = 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] = 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] = cpu_to_le32(data); |
reg_list_hdr_blk_index++; |
data = 0x08000000 | (reg_num * 4); |
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] = cpu_to_le32(data); |
} |
reg_list_mc_addr += reg_num * 4; |
reg_list_blk_index += reg_num; |
} |
} |
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); |
} |
if (rdev->rlc.cp_table_size) { |
if (rdev->rlc.cp_table_obj == NULL) { |
r = radeon_bo_create(rdev, rdev->rlc.cp_table_size, |
PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, 0, NULL, |
&rdev->rlc.cp_table_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) create RLC cp table bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
} |
r = radeon_bo_reserve(rdev->rlc.cp_table_obj, false); |
if (unlikely(r != 0)) { |
dev_warn(rdev->dev, "(%d) reserve RLC cp table bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
r = radeon_bo_pin(rdev->rlc.cp_table_obj, RADEON_GEM_DOMAIN_VRAM, |
&rdev->rlc.cp_table_gpu_addr); |
if (r) { |
radeon_bo_unreserve(rdev->rlc.cp_table_obj); |
dev_warn(rdev->dev, "(%d) pin RLC cp_table bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
r = radeon_bo_kmap(rdev->rlc.cp_table_obj, (void **)&rdev->rlc.cp_table_ptr); |
if (r) { |
dev_warn(rdev->dev, "(%d) map RLC cp table bo failed\n", r); |
sumo_rlc_fini(rdev); |
return r; |
} |
cik_init_cp_pg_table(rdev); |
radeon_bo_kunmap(rdev->rlc.cp_table_obj); |
radeon_bo_unreserve(rdev->rlc.cp_table_obj); |
} |
return 0; |
} |
static void evergreen_rlc_start(struct radeon_device *rdev) |
{ |
u32 mask = RLC_ENABLE; |
if (rdev->flags & RADEON_IS_IGP) { |
mask |= GFX_POWER_GATING_ENABLE | GFX_POWER_GATING_SRC; |
} |
WREG32(RLC_CNTL, mask); |
} |
int evergreen_rlc_resume(struct radeon_device *rdev) |
{ |
u32 i; |
const __be32 *fw_data; |
if (!rdev->rlc_fw) |
return -EINVAL; |
r600_rlc_stop(rdev); |
WREG32(RLC_HB_CNTL, 0); |
if (rdev->flags & RADEON_IS_IGP) { |
if (rdev->family == CHIP_ARUBA) { |
u32 always_on_bitmap = |
3 | (3 << (16 * rdev->config.cayman.max_shader_engines)); |
/* find out the number of active simds */ |
u32 tmp = (RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffff0000) >> 16; |
tmp |= 0xffffffff << rdev->config.cayman.max_simds_per_se; |
tmp = hweight32(~tmp); |
if (tmp == rdev->config.cayman.max_simds_per_se) { |
WREG32(TN_RLC_LB_ALWAYS_ACTIVE_SIMD_MASK, always_on_bitmap); |
WREG32(TN_RLC_LB_PARAMS, 0x00601004); |
WREG32(TN_RLC_LB_INIT_SIMD_MASK, 0xffffffff); |
WREG32(TN_RLC_LB_CNTR_INIT, 0x00000000); |
WREG32(TN_RLC_LB_CNTR_MAX, 0x00002000); |
} |
} else { |
WREG32(RLC_HB_WPTR_LSB_ADDR, 0); |
WREG32(RLC_HB_WPTR_MSB_ADDR, 0); |
} |
WREG32(TN_RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8); |
WREG32(TN_RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8); |
} else { |
WREG32(RLC_HB_BASE, 0); |
WREG32(RLC_HB_RPTR, 0); |
WREG32(RLC_HB_WPTR, 0); |
WREG32(RLC_HB_WPTR_LSB_ADDR, 0); |
WREG32(RLC_HB_WPTR_MSB_ADDR, 0); |
} |
WREG32(RLC_MC_CNTL, 0); |
WREG32(RLC_UCODE_CNTL, 0); |
fw_data = (const __be32 *)rdev->rlc_fw->data; |
if (rdev->family >= CHIP_ARUBA) { |
for (i = 0; i < ARUBA_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
} else if (rdev->family >= CHIP_CAYMAN) { |
for (i = 0; i < CAYMAN_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
} else { |
for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
} |
WREG32(RLC_UCODE_ADDR, 0); |
evergreen_rlc_start(rdev); |
return 0; |
} |
/* Interrupts */ |
u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc) |
3746,8 → 4344,8 |
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); |
3773,9 → 4371,9 |
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; |
if (!rdev->irq.installed) { |
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
3795,6 → 4393,12 |
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; |
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; |
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; |
if (rdev->family == CHIP_ARUBA) |
thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) & |
~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); |
else |
thermal_int = RREG32(CG_THERMAL_INT) & |
~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); |
afmt1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK; |
afmt2 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK; |
3840,6 → 4444,11 |
} |
} |
if (rdev->irq.dpm_thermal) { |
DRM_DEBUG("dpm thermal\n"); |
thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; |
} |
if (rdev->irq.crtc_vblank_int[0] || |
atomic_read(&rdev->irq.pflip[0])) { |
DRM_DEBUG("evergreen_irq_set: vblank 0\n"); |
3944,15 → 4553,21 |
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); |
3961,6 → 4576,10 |
WREG32(DC_HPD4_INT_CONTROL, hpd4); |
WREG32(DC_HPD5_INT_CONTROL, hpd5); |
WREG32(DC_HPD6_INT_CONTROL, hpd6); |
if (rdev->family == CHIP_ARUBA) |
WREG32(TN_CG_THERMAL_INT_CTRL, thermal_int); |
else |
WREG32(CG_THERMAL_INT, thermal_int); |
WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, afmt1); |
WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, afmt2); |
4140,6 → 4759,7 |
tmp = RREG32(IH_RB_CNTL); |
tmp |= IH_WPTR_OVERFLOW_CLEAR; |
WREG32(IH_RB_CNTL, tmp); |
wptr &= ~RB_OVERFLOW; |
} |
return (wptr & rdev->ih.ptr_mask); |
} |
4152,6 → 4772,8 |
u32 ring_index; |
bool queue_hotplug = false; |
bool queue_hdmi = false; |
bool queue_thermal = false; |
u32 status, addr; |
if (!rdev->ih.enabled || rdev->shutdown) |
return IRQ_NONE; |
4335,6 → 4957,14 |
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); |
break; |
case 42: /* HPD hotplug */ |
switch (src_data) { |
case 0: |
4438,13 → 5068,18 |
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", |
RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); |
addr); |
dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", |
RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); |
/* reset addr and status */ |
WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); |
status); |
cayman_vm_decode_fault(rdev, status, addr); |
break; |
case 176: /* CP_INT in ring buffer */ |
case 177: /* CP_INT in IB1 */ |
4473,6 → 5108,16 |
DRM_DEBUG("IH: DMA trap\n"); |
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX); |
break; |
case 230: /* thermal low to high */ |
DRM_DEBUG("IH: thermal low to high\n"); |
rdev->pm.dpm.thermal.high_to_low = false; |
queue_thermal = true; |
break; |
case 231: /* thermal high to low */ |
DRM_DEBUG("IH: thermal high to low\n"); |
rdev->pm.dpm.thermal.high_to_low = true; |
queue_thermal = true; |
break; |
case 233: /* GUI IDLE */ |
DRM_DEBUG("IH: GUI idle\n"); |
break; |
4503,143 → 5148,6 |
return IRQ_HANDLED; |
} |
/** |
* evergreen_dma_fence_ring_emit - emit a fence on the DMA ring |
* |
* @rdev: radeon_device pointer |
* @fence: radeon fence object |
* |
* Add a DMA fence packet to the ring to write |
* the fence seq number and DMA trap packet to generate |
* an interrupt if needed (evergreen-SI). |
*/ |
void evergreen_dma_fence_ring_emit(struct radeon_device *rdev, |
struct radeon_fence *fence) |
{ |
struct radeon_ring *ring = &rdev->ring[fence->ring]; |
u64 addr = rdev->fence_drv[fence->ring].gpu_addr; |
/* write the fence */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0)); |
radeon_ring_write(ring, addr & 0xfffffffc); |
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff)); |
radeon_ring_write(ring, fence->seq); |
/* generate an interrupt */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0)); |
/* flush HDP */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2)); |
radeon_ring_write(ring, 1); |
} |
/** |
* evergreen_dma_ring_ib_execute - schedule an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to schedule |
* |
* Schedule an IB in the DMA ring (evergreen). |
*/ |
void evergreen_dma_ring_ib_execute(struct radeon_device *rdev, |
struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
if (rdev->wb.enabled) { |
u32 next_rptr = ring->wptr + 4; |
while ((next_rptr & 7) != 5) |
next_rptr++; |
next_rptr += 3; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 1)); |
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff); |
radeon_ring_write(ring, next_rptr); |
} |
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring. |
* Pad as necessary with NOPs. |
*/ |
while ((ring->wptr & 7) != 5) |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0)); |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_INDIRECT_BUFFER, 0, 0)); |
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0)); |
radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF)); |
} |
/** |
* evergreen_copy_dma - copy pages using the 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 DMA engine (evergreen-cayman). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int evergreen_copy_dma(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.dma_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_dw, cur_size_in_dw; |
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_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; |
num_loops = DIV_ROUND_UP(size_in_dw, 0xfffff); |
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11); |
if (r) { |
DRM_ERROR("radeon: moving bo (%d).\n", r); |
radeon_semaphore_free(rdev, &sem, NULL); |
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); |
} |
for (i = 0; i < num_loops; i++) { |
cur_size_in_dw = size_in_dw; |
if (cur_size_in_dw > 0xFFFFF) |
cur_size_in_dw = 0xFFFFF; |
size_in_dw -= cur_size_in_dw; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, cur_size_in_dw)); |
radeon_ring_write(ring, dst_offset & 0xfffffffc); |
radeon_ring_write(ring, src_offset & 0xfffffffc); |
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_dw * 4; |
dst_offset += cur_size_in_dw * 4; |
} |
r = radeon_fence_emit(rdev, fence, ring->idx); |
if (r) { |
radeon_ring_unlock_undo(rdev, ring); |
return r; |
} |
radeon_ring_unlock_commit(rdev, ring); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
static int evergreen_startup(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring; |
4647,35 → 5155,24 |
/* enable pcie gen2 link */ |
evergreen_pcie_gen2_enable(rdev); |
/* enable aspm */ |
evergreen_program_aspm(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"); |
/* scratch needs to be initialized before MC */ |
r = r600_vram_scratch_init(rdev); |
if (r) |
return r; |
} |
} |
evergreen_mc_program(rdev); |
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; |
} |
} |
} |
r = r600_vram_scratch_init(rdev); |
if (r) |
return r; |
evergreen_mc_program(rdev); |
if (rdev->flags & RADEON_IS_AGP) { |
evergreen_agp_enable(rdev); |
} else { |
4685,12 → 5182,18 |
} |
evergreen_gpu_init(rdev); |
r = evergreen_blit_init(rdev); |
/* allocate rlc buffers */ |
if (rdev->flags & RADEON_IS_IGP) { |
rdev->rlc.reg_list = sumo_rlc_save_restore_register_list; |
rdev->rlc.reg_list_size = |
(u32)ARRAY_SIZE(sumo_rlc_save_restore_register_list); |
rdev->rlc.cs_data = evergreen_cs_data; |
r = sumo_rlc_init(rdev); |
if (r) { |
// r600_blit_fini(rdev); |
rdev->asic->copy.copy = NULL; |
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); |
DRM_ERROR("Failed to init rlc BOs!\n"); |
return r; |
} |
} |
/* allocate wb buffer */ |
r = radeon_wb_init(rdev); |
4717,8 → 5220,8 |
// dev_err(rdev->dev, "UVD fences init error (%d).\n", r); |
// } |
// if (r) |
// rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; |
if (r) |
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; |
/* Enable IRQ */ |
if (!rdev->irq.installed) { |
4737,15 → 5240,13 |
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, |
0, 0xfffff, RADEON_CP_PACKET2); |
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, |
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0)); |
DMA_PACKET(DMA_PACKET_NOP, 0, 0)); |
if (r) |
return r; |
4759,19 → 5260,7 |
if (r) |
return r; |
ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
if (ring->ring_size) { |
r = radeon_ring_init(rdev, ring, ring->ring_size, |
R600_WB_UVD_RPTR_OFFSET, |
UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, |
0, 0xfffff, RADEON_CP_PACKET2); |
if (!r) |
r = r600_uvd_init(rdev); |
if (r) |
DRM_ERROR("radeon: error initializing UVD (%d).\n", r); |
} |
r = radeon_ib_pool_init(rdev); |
if (r) { |
dev_err(rdev->dev, "IB initialization failed (%d).\n", r); |
4783,30 → 5272,7 |
#if 0 |
int evergreen_copy_blit(struct radeon_device *rdev, |
uint64_t src_offset, uint64_t dst_offset, |
unsigned num_pages, struct radeon_fence *fence) |
{ |
int r; |
mutex_lock(&rdev->r600_blit.mutex); |
rdev->r600_blit.vb_ib = NULL; |
r = evergreen_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE); |
if (r) { |
if (rdev->r600_blit.vb_ib) |
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib); |
mutex_unlock(&rdev->r600_blit.mutex); |
return r; |
} |
evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE); |
evergreen_blit_done_copy(rdev, fence); |
mutex_unlock(&rdev->r600_blit.mutex); |
return 0; |
} |
#endif |
/* Plan is to move initialization in that function and use |
* helper function so that radeon_device_init pretty much |
* do nothing more than calling asic specific function. This |
4871,6 → 5337,27 |
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); |
4975,3 → 5462,153 |
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); |
} |
} |
void evergreen_program_aspm(struct radeon_device *rdev) |
{ |
u32 data, orig; |
u32 pcie_lc_cntl, pcie_lc_cntl_old; |
bool disable_l0s, disable_l1 = false, disable_plloff_in_l1 = false; |
/* fusion_platform = true |
* if the system is a fusion system |
* (APU or DGPU in a fusion system). |
* todo: check if the system is a fusion platform. |
*/ |
bool fusion_platform = false; |
if (radeon_aspm == 0) |
return; |
if (!(rdev->flags & RADEON_IS_PCIE)) |
return; |
switch (rdev->family) { |
case CHIP_CYPRESS: |
case CHIP_HEMLOCK: |
case CHIP_JUNIPER: |
case CHIP_REDWOOD: |
case CHIP_CEDAR: |
case CHIP_SUMO: |
case CHIP_SUMO2: |
case CHIP_PALM: |
case CHIP_ARUBA: |
disable_l0s = true; |
break; |
default: |
disable_l0s = false; |
break; |
} |
if (rdev->flags & RADEON_IS_IGP) |
fusion_platform = true; /* XXX also dGPUs in a fusion system */ |
data = orig = RREG32_PIF_PHY0(PB0_PIF_PAIRING); |
if (fusion_platform) |
data &= ~MULTI_PIF; |
else |
data |= MULTI_PIF; |
if (data != orig) |
WREG32_PIF_PHY0(PB0_PIF_PAIRING, data); |
data = orig = RREG32_PIF_PHY1(PB1_PIF_PAIRING); |
if (fusion_platform) |
data &= ~MULTI_PIF; |
else |
data |= MULTI_PIF; |
if (data != orig) |
WREG32_PIF_PHY1(PB1_PIF_PAIRING, data); |
pcie_lc_cntl = pcie_lc_cntl_old = RREG32_PCIE_PORT(PCIE_LC_CNTL); |
pcie_lc_cntl &= ~(LC_L0S_INACTIVITY_MASK | LC_L1_INACTIVITY_MASK); |
if (!disable_l0s) { |
if (rdev->family >= CHIP_BARTS) |
pcie_lc_cntl |= LC_L0S_INACTIVITY(7); |
else |
pcie_lc_cntl |= LC_L0S_INACTIVITY(3); |
} |
if (!disable_l1) { |
if (rdev->family >= CHIP_BARTS) |
pcie_lc_cntl |= LC_L1_INACTIVITY(7); |
else |
pcie_lc_cntl |= LC_L1_INACTIVITY(8); |
if (!disable_plloff_in_l1) { |
data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0); |
data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK); |
data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7); |
if (data != orig) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data); |
data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1); |
data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK); |
data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7); |
if (data != orig) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data); |
data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0); |
data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK); |
data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7); |
if (data != orig) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data); |
data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1); |
data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK); |
data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7); |
if (data != orig) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data); |
if (rdev->family >= CHIP_BARTS) { |
data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0); |
data &= ~PLL_RAMP_UP_TIME_0_MASK; |
data |= PLL_RAMP_UP_TIME_0(4); |
if (data != orig) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data); |
data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1); |
data &= ~PLL_RAMP_UP_TIME_1_MASK; |
data |= PLL_RAMP_UP_TIME_1(4); |
if (data != orig) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data); |
data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0); |
data &= ~PLL_RAMP_UP_TIME_0_MASK; |
data |= PLL_RAMP_UP_TIME_0(4); |
if (data != orig) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data); |
data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1); |
data &= ~PLL_RAMP_UP_TIME_1_MASK; |
data |= PLL_RAMP_UP_TIME_1(4); |
if (data != orig) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data); |
} |
data = orig = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL); |
data &= ~LC_DYN_LANES_PWR_STATE_MASK; |
data |= LC_DYN_LANES_PWR_STATE(3); |
if (data != orig) |
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data); |
if (rdev->family >= CHIP_BARTS) { |
data = orig = RREG32_PIF_PHY0(PB0_PIF_CNTL); |
data &= ~LS2_EXIT_TIME_MASK; |
data |= LS2_EXIT_TIME(1); |
if (data != orig) |
WREG32_PIF_PHY0(PB0_PIF_CNTL, data); |
data = orig = RREG32_PIF_PHY1(PB1_PIF_CNTL); |
data &= ~LS2_EXIT_TIME_MASK; |
data |= LS2_EXIT_TIME(1); |
if (data != orig) |
WREG32_PIF_PHY1(PB1_PIF_CNTL, data); |
} |
} |
} |
/* evergreen parts only */ |
if (rdev->family < CHIP_BARTS) |
pcie_lc_cntl |= LC_PMI_TO_L1_DIS; |
if (pcie_lc_cntl != pcie_lc_cntl_old) |
WREG32_PCIE_PORT(PCIE_LC_CNTL, pcie_lc_cntl); |
} |
/drivers/video/drm/radeon/evergreen_blit_shaders.c |
---|
300,58 → 300,4 |
0x00000010, /* */ |
}; |
const u32 evergreen_vs[] = |
{ |
0x00000004, |
0x80800400, |
0x0000a03c, |
0x95000688, |
0x00004000, |
0x15200688, |
0x00000000, |
0x00000000, |
0x3c000000, |
0x67961001, |
#ifdef __BIG_ENDIAN |
0x000a0000, |
#else |
0x00080000, |
#endif |
0x00000000, |
0x1c000000, |
0x67961000, |
#ifdef __BIG_ENDIAN |
0x00020008, |
#else |
0x00000008, |
#endif |
0x00000000, |
}; |
const u32 evergreen_ps[] = |
{ |
0x00000003, |
0xa00c0000, |
0x00000008, |
0x80400000, |
0x00000000, |
0x95200688, |
0x00380400, |
0x00146b10, |
0x00380000, |
0x20146b10, |
0x00380400, |
0x40146b00, |
0x80380000, |
0x60146b00, |
0x00000000, |
0x00000000, |
0x00000010, |
0x000d1000, |
0xb0800000, |
0x00000000, |
}; |
const u32 evergreen_ps_size = ARRAY_SIZE(evergreen_ps); |
const u32 evergreen_vs_size = ARRAY_SIZE(evergreen_vs); |
const u32 evergreen_default_size = ARRAY_SIZE(evergreen_default_state); |
/drivers/video/drm/radeon/evergreen_cs.c |
---|
0,0 → 1,3517 |
/* |
* Copyright 2010 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 "radeon.h" |
#include "evergreend.h" |
#include "evergreen_reg_safe.h" |
#include "cayman_reg_safe.h" |
#define MAX(a,b) (((a)>(b))?(a):(b)) |
#define MIN(a,b) (((a)<(b))?(a):(b)) |
int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, |
struct radeon_cs_reloc **cs_reloc); |
struct evergreen_cs_track { |
u32 group_size; |
u32 nbanks; |
u32 npipes; |
u32 row_size; |
/* value we track */ |
u32 nsamples; /* unused */ |
struct radeon_bo *cb_color_bo[12]; |
u32 cb_color_bo_offset[12]; |
struct radeon_bo *cb_color_fmask_bo[8]; /* unused */ |
struct radeon_bo *cb_color_cmask_bo[8]; /* unused */ |
u32 cb_color_info[12]; |
u32 cb_color_view[12]; |
u32 cb_color_pitch[12]; |
u32 cb_color_slice[12]; |
u32 cb_color_slice_idx[12]; |
u32 cb_color_attrib[12]; |
u32 cb_color_cmask_slice[8];/* unused */ |
u32 cb_color_fmask_slice[8];/* unused */ |
u32 cb_target_mask; |
u32 cb_shader_mask; /* unused */ |
u32 vgt_strmout_config; |
u32 vgt_strmout_buffer_config; |
struct radeon_bo *vgt_strmout_bo[4]; |
u32 vgt_strmout_bo_offset[4]; |
u32 vgt_strmout_size[4]; |
u32 db_depth_control; |
u32 db_depth_view; |
u32 db_depth_slice; |
u32 db_depth_size; |
u32 db_z_info; |
u32 db_z_read_offset; |
u32 db_z_write_offset; |
struct radeon_bo *db_z_read_bo; |
struct radeon_bo *db_z_write_bo; |
u32 db_s_info; |
u32 db_s_read_offset; |
u32 db_s_write_offset; |
struct radeon_bo *db_s_read_bo; |
struct radeon_bo *db_s_write_bo; |
bool sx_misc_kill_all_prims; |
bool cb_dirty; |
bool db_dirty; |
bool streamout_dirty; |
u32 htile_offset; |
u32 htile_surface; |
struct radeon_bo *htile_bo; |
}; |
static u32 evergreen_cs_get_aray_mode(u32 tiling_flags) |
{ |
if (tiling_flags & RADEON_TILING_MACRO) |
return ARRAY_2D_TILED_THIN1; |
else if (tiling_flags & RADEON_TILING_MICRO) |
return ARRAY_1D_TILED_THIN1; |
else |
return ARRAY_LINEAR_GENERAL; |
} |
static u32 evergreen_cs_get_num_banks(u32 nbanks) |
{ |
switch (nbanks) { |
case 2: |
return ADDR_SURF_2_BANK; |
case 4: |
return ADDR_SURF_4_BANK; |
case 8: |
default: |
return ADDR_SURF_8_BANK; |
case 16: |
return ADDR_SURF_16_BANK; |
} |
} |
static void evergreen_cs_track_init(struct evergreen_cs_track *track) |
{ |
int i; |
for (i = 0; i < 8; i++) { |
track->cb_color_fmask_bo[i] = NULL; |
track->cb_color_cmask_bo[i] = NULL; |
track->cb_color_cmask_slice[i] = 0; |
track->cb_color_fmask_slice[i] = 0; |
} |
for (i = 0; i < 12; i++) { |
track->cb_color_bo[i] = NULL; |
track->cb_color_bo_offset[i] = 0xFFFFFFFF; |
track->cb_color_info[i] = 0; |
track->cb_color_view[i] = 0xFFFFFFFF; |
track->cb_color_pitch[i] = 0; |
track->cb_color_slice[i] = 0xfffffff; |
track->cb_color_slice_idx[i] = 0; |
} |
track->cb_target_mask = 0xFFFFFFFF; |
track->cb_shader_mask = 0xFFFFFFFF; |
track->cb_dirty = true; |
track->db_depth_slice = 0xffffffff; |
track->db_depth_view = 0xFFFFC000; |
track->db_depth_size = 0xFFFFFFFF; |
track->db_depth_control = 0xFFFFFFFF; |
track->db_z_info = 0xFFFFFFFF; |
track->db_z_read_offset = 0xFFFFFFFF; |
track->db_z_write_offset = 0xFFFFFFFF; |
track->db_z_read_bo = NULL; |
track->db_z_write_bo = NULL; |
track->db_s_info = 0xFFFFFFFF; |
track->db_s_read_offset = 0xFFFFFFFF; |
track->db_s_write_offset = 0xFFFFFFFF; |
track->db_s_read_bo = NULL; |
track->db_s_write_bo = NULL; |
track->db_dirty = true; |
track->htile_bo = NULL; |
track->htile_offset = 0xFFFFFFFF; |
track->htile_surface = 0; |
for (i = 0; i < 4; i++) { |
track->vgt_strmout_size[i] = 0; |
track->vgt_strmout_bo[i] = NULL; |
track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF; |
} |
track->streamout_dirty = true; |
track->sx_misc_kill_all_prims = false; |
} |
struct eg_surface { |
/* value gathered from cs */ |
unsigned nbx; |
unsigned nby; |
unsigned format; |
unsigned mode; |
unsigned nbanks; |
unsigned bankw; |
unsigned bankh; |
unsigned tsplit; |
unsigned mtilea; |
unsigned nsamples; |
/* output value */ |
unsigned bpe; |
unsigned layer_size; |
unsigned palign; |
unsigned halign; |
unsigned long base_align; |
}; |
static int evergreen_surface_check_linear(struct radeon_cs_parser *p, |
struct eg_surface *surf, |
const char *prefix) |
{ |
surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples; |
surf->base_align = surf->bpe; |
surf->palign = 1; |
surf->halign = 1; |
return 0; |
} |
static int evergreen_surface_check_linear_aligned(struct radeon_cs_parser *p, |
struct eg_surface *surf, |
const char *prefix) |
{ |
struct evergreen_cs_track *track = p->track; |
unsigned palign; |
palign = MAX(64, track->group_size / surf->bpe); |
surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples; |
surf->base_align = track->group_size; |
surf->palign = palign; |
surf->halign = 1; |
if (surf->nbx & (palign - 1)) { |
if (prefix) { |
dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n", |
__func__, __LINE__, prefix, surf->nbx, palign); |
} |
return -EINVAL; |
} |
return 0; |
} |
static int evergreen_surface_check_1d(struct radeon_cs_parser *p, |
struct eg_surface *surf, |
const char *prefix) |
{ |
struct evergreen_cs_track *track = p->track; |
unsigned palign; |
palign = track->group_size / (8 * surf->bpe * surf->nsamples); |
palign = MAX(8, palign); |
surf->layer_size = surf->nbx * surf->nby * surf->bpe; |
surf->base_align = track->group_size; |
surf->palign = palign; |
surf->halign = 8; |
if ((surf->nbx & (palign - 1))) { |
if (prefix) { |
dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d (%d %d %d)\n", |
__func__, __LINE__, prefix, surf->nbx, palign, |
track->group_size, surf->bpe, surf->nsamples); |
} |
return -EINVAL; |
} |
if ((surf->nby & (8 - 1))) { |
if (prefix) { |
dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with 8\n", |
__func__, __LINE__, prefix, surf->nby); |
} |
return -EINVAL; |
} |
return 0; |
} |
static int evergreen_surface_check_2d(struct radeon_cs_parser *p, |
struct eg_surface *surf, |
const char *prefix) |
{ |
struct evergreen_cs_track *track = p->track; |
unsigned palign, halign, tileb, slice_pt; |
unsigned mtile_pr, mtile_ps, mtileb; |
tileb = 64 * surf->bpe * surf->nsamples; |
slice_pt = 1; |
if (tileb > surf->tsplit) { |
slice_pt = tileb / surf->tsplit; |
} |
tileb = tileb / slice_pt; |
/* macro tile width & height */ |
palign = (8 * surf->bankw * track->npipes) * surf->mtilea; |
halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea; |
mtileb = (palign / 8) * (halign / 8) * tileb; |
mtile_pr = surf->nbx / palign; |
mtile_ps = (mtile_pr * surf->nby) / halign; |
surf->layer_size = mtile_ps * mtileb * slice_pt; |
surf->base_align = (palign / 8) * (halign / 8) * tileb; |
surf->palign = palign; |
surf->halign = halign; |
if ((surf->nbx & (palign - 1))) { |
if (prefix) { |
dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n", |
__func__, __LINE__, prefix, surf->nbx, palign); |
} |
return -EINVAL; |
} |
if ((surf->nby & (halign - 1))) { |
if (prefix) { |
dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with %d\n", |
__func__, __LINE__, prefix, surf->nby, halign); |
} |
return -EINVAL; |
} |
return 0; |
} |
static int evergreen_surface_check(struct radeon_cs_parser *p, |
struct eg_surface *surf, |
const char *prefix) |
{ |
/* some common value computed here */ |
surf->bpe = r600_fmt_get_blocksize(surf->format); |
switch (surf->mode) { |
case ARRAY_LINEAR_GENERAL: |
return evergreen_surface_check_linear(p, surf, prefix); |
case ARRAY_LINEAR_ALIGNED: |
return evergreen_surface_check_linear_aligned(p, surf, prefix); |
case ARRAY_1D_TILED_THIN1: |
return evergreen_surface_check_1d(p, surf, prefix); |
case ARRAY_2D_TILED_THIN1: |
return evergreen_surface_check_2d(p, surf, prefix); |
default: |
dev_warn(p->dev, "%s:%d %s invalid array mode %d\n", |
__func__, __LINE__, prefix, surf->mode); |
return -EINVAL; |
} |
return -EINVAL; |
} |
static int evergreen_surface_value_conv_check(struct radeon_cs_parser *p, |
struct eg_surface *surf, |
const char *prefix) |
{ |
switch (surf->mode) { |
case ARRAY_2D_TILED_THIN1: |
break; |
case ARRAY_LINEAR_GENERAL: |
case ARRAY_LINEAR_ALIGNED: |
case ARRAY_1D_TILED_THIN1: |
return 0; |
default: |
dev_warn(p->dev, "%s:%d %s invalid array mode %d\n", |
__func__, __LINE__, prefix, surf->mode); |
return -EINVAL; |
} |
switch (surf->nbanks) { |
case 0: surf->nbanks = 2; break; |
case 1: surf->nbanks = 4; break; |
case 2: surf->nbanks = 8; break; |
case 3: surf->nbanks = 16; break; |
default: |
dev_warn(p->dev, "%s:%d %s invalid number of banks %d\n", |
__func__, __LINE__, prefix, surf->nbanks); |
return -EINVAL; |
} |
switch (surf->bankw) { |
case 0: surf->bankw = 1; break; |
case 1: surf->bankw = 2; break; |
case 2: surf->bankw = 4; break; |
case 3: surf->bankw = 8; break; |
default: |
dev_warn(p->dev, "%s:%d %s invalid bankw %d\n", |
__func__, __LINE__, prefix, surf->bankw); |
return -EINVAL; |
} |
switch (surf->bankh) { |
case 0: surf->bankh = 1; break; |
case 1: surf->bankh = 2; break; |
case 2: surf->bankh = 4; break; |
case 3: surf->bankh = 8; break; |
default: |
dev_warn(p->dev, "%s:%d %s invalid bankh %d\n", |
__func__, __LINE__, prefix, surf->bankh); |
return -EINVAL; |
} |
switch (surf->mtilea) { |
case 0: surf->mtilea = 1; break; |
case 1: surf->mtilea = 2; break; |
case 2: surf->mtilea = 4; break; |
case 3: surf->mtilea = 8; break; |
default: |
dev_warn(p->dev, "%s:%d %s invalid macro tile aspect %d\n", |
__func__, __LINE__, prefix, surf->mtilea); |
return -EINVAL; |
} |
switch (surf->tsplit) { |
case 0: surf->tsplit = 64; break; |
case 1: surf->tsplit = 128; break; |
case 2: surf->tsplit = 256; break; |
case 3: surf->tsplit = 512; break; |
case 4: surf->tsplit = 1024; break; |
case 5: surf->tsplit = 2048; break; |
case 6: surf->tsplit = 4096; break; |
default: |
dev_warn(p->dev, "%s:%d %s invalid tile split %d\n", |
__func__, __LINE__, prefix, surf->tsplit); |
return -EINVAL; |
} |
return 0; |
} |
static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned id) |
{ |
struct evergreen_cs_track *track = p->track; |
struct eg_surface surf; |
unsigned pitch, slice, mslice; |
unsigned long offset; |
int r; |
mslice = G_028C6C_SLICE_MAX(track->cb_color_view[id]) + 1; |
pitch = track->cb_color_pitch[id]; |
slice = track->cb_color_slice[id]; |
surf.nbx = (pitch + 1) * 8; |
surf.nby = ((slice + 1) * 64) / surf.nbx; |
surf.mode = G_028C70_ARRAY_MODE(track->cb_color_info[id]); |
surf.format = G_028C70_FORMAT(track->cb_color_info[id]); |
surf.tsplit = G_028C74_TILE_SPLIT(track->cb_color_attrib[id]); |
surf.nbanks = G_028C74_NUM_BANKS(track->cb_color_attrib[id]); |
surf.bankw = G_028C74_BANK_WIDTH(track->cb_color_attrib[id]); |
surf.bankh = G_028C74_BANK_HEIGHT(track->cb_color_attrib[id]); |
surf.mtilea = G_028C74_MACRO_TILE_ASPECT(track->cb_color_attrib[id]); |
surf.nsamples = 1; |
if (!r600_fmt_is_valid_color(surf.format)) { |
dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08x)\n", |
__func__, __LINE__, surf.format, |
id, track->cb_color_info[id]); |
return -EINVAL; |
} |
r = evergreen_surface_value_conv_check(p, &surf, "cb"); |
if (r) { |
return r; |
} |
r = evergreen_surface_check(p, &surf, "cb"); |
if (r) { |
dev_warn(p->dev, "%s:%d cb[%d] invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n", |
__func__, __LINE__, id, track->cb_color_pitch[id], |
track->cb_color_slice[id], track->cb_color_attrib[id], |
track->cb_color_info[id]); |
return r; |
} |
offset = track->cb_color_bo_offset[id] << 8; |
if (offset & (surf.base_align - 1)) { |
dev_warn(p->dev, "%s:%d cb[%d] bo base %ld not aligned with %ld\n", |
__func__, __LINE__, id, offset, surf.base_align); |
return -EINVAL; |
} |
offset += surf.layer_size * mslice; |
if (offset > radeon_bo_size(track->cb_color_bo[id])) { |
/* old ddx are broken they allocate bo with w*h*bpp but |
* program slice with ALIGN(h, 8), catch this and patch |
* command stream. |
*/ |
if (!surf.mode) { |
volatile u32 *ib = p->ib.ptr; |
unsigned long tmp, nby, bsize, size, min = 0; |
/* find the height the ddx wants */ |
if (surf.nby > 8) { |
min = surf.nby - 8; |
} |
bsize = radeon_bo_size(track->cb_color_bo[id]); |
tmp = track->cb_color_bo_offset[id] << 8; |
for (nby = surf.nby; nby > min; nby--) { |
size = nby * surf.nbx * surf.bpe * surf.nsamples; |
if ((tmp + size * mslice) <= bsize) { |
break; |
} |
} |
if (nby > min) { |
surf.nby = nby; |
slice = ((nby * surf.nbx) / 64) - 1; |
if (!evergreen_surface_check(p, &surf, "cb")) { |
/* check if this one works */ |
tmp += surf.layer_size * mslice; |
if (tmp <= bsize) { |
ib[track->cb_color_slice_idx[id]] = slice; |
goto old_ddx_ok; |
} |
} |
} |
} |
dev_warn(p->dev, "%s:%d cb[%d] bo too small (layer size %d, " |
"offset %d, max layer %d, bo size %ld, slice %d)\n", |
__func__, __LINE__, id, surf.layer_size, |
track->cb_color_bo_offset[id] << 8, mslice, |
radeon_bo_size(track->cb_color_bo[id]), slice); |
dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n", |
__func__, __LINE__, surf.nbx, surf.nby, |
surf.mode, surf.bpe, surf.nsamples, |
surf.bankw, surf.bankh, |
surf.tsplit, surf.mtilea); |
return -EINVAL; |
} |
old_ddx_ok: |
return 0; |
} |
static int evergreen_cs_track_validate_htile(struct radeon_cs_parser *p, |
unsigned nbx, unsigned nby) |
{ |
struct evergreen_cs_track *track = p->track; |
unsigned long size; |
if (track->htile_bo == NULL) { |
dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n", |
__func__, __LINE__, track->db_z_info); |
return -EINVAL; |
} |
if (G_028ABC_LINEAR(track->htile_surface)) { |
/* pitch must be 16 htiles aligned == 16 * 8 pixel aligned */ |
nbx = round_up(nbx, 16 * 8); |
/* height is npipes htiles aligned == npipes * 8 pixel aligned */ |
nby = round_up(nby, track->npipes * 8); |
} else { |
/* always assume 8x8 htile */ |
/* align is htile align * 8, htile align vary according to |
* number of pipe and tile width and nby |
*/ |
switch (track->npipes) { |
case 8: |
/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/ |
nbx = round_up(nbx, 64 * 8); |
nby = round_up(nby, 64 * 8); |
break; |
case 4: |
/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/ |
nbx = round_up(nbx, 64 * 8); |
nby = round_up(nby, 32 * 8); |
break; |
case 2: |
/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/ |
nbx = round_up(nbx, 32 * 8); |
nby = round_up(nby, 32 * 8); |
break; |
case 1: |
/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/ |
nbx = round_up(nbx, 32 * 8); |
nby = round_up(nby, 16 * 8); |
break; |
default: |
dev_warn(p->dev, "%s:%d invalid num pipes %d\n", |
__func__, __LINE__, track->npipes); |
return -EINVAL; |
} |
} |
/* compute number of htile */ |
nbx = nbx >> 3; |
nby = nby >> 3; |
/* size must be aligned on npipes * 2K boundary */ |
size = roundup(nbx * nby * 4, track->npipes * (2 << 10)); |
size += track->htile_offset; |
if (size > radeon_bo_size(track->htile_bo)) { |
dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n", |
__func__, __LINE__, radeon_bo_size(track->htile_bo), |
size, nbx, nby); |
return -EINVAL; |
} |
return 0; |
} |
static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p) |
{ |
struct evergreen_cs_track *track = p->track; |
struct eg_surface surf; |
unsigned pitch, slice, mslice; |
unsigned long offset; |
int r; |
mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1; |
pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size); |
slice = track->db_depth_slice; |
surf.nbx = (pitch + 1) * 8; |
surf.nby = ((slice + 1) * 64) / surf.nbx; |
surf.mode = G_028040_ARRAY_MODE(track->db_z_info); |
surf.format = G_028044_FORMAT(track->db_s_info); |
surf.tsplit = G_028044_TILE_SPLIT(track->db_s_info); |
surf.nbanks = G_028040_NUM_BANKS(track->db_z_info); |
surf.bankw = G_028040_BANK_WIDTH(track->db_z_info); |
surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info); |
surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info); |
surf.nsamples = 1; |
if (surf.format != 1) { |
dev_warn(p->dev, "%s:%d stencil invalid format %d\n", |
__func__, __LINE__, surf.format); |
return -EINVAL; |
} |
/* replace by color format so we can use same code */ |
surf.format = V_028C70_COLOR_8; |
r = evergreen_surface_value_conv_check(p, &surf, "stencil"); |
if (r) { |
return r; |
} |
r = evergreen_surface_check(p, &surf, NULL); |
if (r) { |
/* old userspace doesn't compute proper depth/stencil alignment |
* check that alignment against a bigger byte per elements and |
* only report if that alignment is wrong too. |
*/ |
surf.format = V_028C70_COLOR_8_8_8_8; |
r = evergreen_surface_check(p, &surf, "stencil"); |
if (r) { |
dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n", |
__func__, __LINE__, track->db_depth_size, |
track->db_depth_slice, track->db_s_info, track->db_z_info); |
} |
return r; |
} |
offset = track->db_s_read_offset << 8; |
if (offset & (surf.base_align - 1)) { |
dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n", |
__func__, __LINE__, offset, surf.base_align); |
return -EINVAL; |
} |
offset += surf.layer_size * mslice; |
if (offset > radeon_bo_size(track->db_s_read_bo)) { |
dev_warn(p->dev, "%s:%d stencil read bo too small (layer size %d, " |
"offset %ld, max layer %d, bo size %ld)\n", |
__func__, __LINE__, surf.layer_size, |
(unsigned long)track->db_s_read_offset << 8, mslice, |
radeon_bo_size(track->db_s_read_bo)); |
dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n", |
__func__, __LINE__, track->db_depth_size, |
track->db_depth_slice, track->db_s_info, track->db_z_info); |
return -EINVAL; |
} |
offset = track->db_s_write_offset << 8; |
if (offset & (surf.base_align - 1)) { |
dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n", |
__func__, __LINE__, offset, surf.base_align); |
return -EINVAL; |
} |
offset += surf.layer_size * mslice; |
if (offset > radeon_bo_size(track->db_s_write_bo)) { |
dev_warn(p->dev, "%s:%d stencil write bo too small (layer size %d, " |
"offset %ld, max layer %d, bo size %ld)\n", |
__func__, __LINE__, surf.layer_size, |
(unsigned long)track->db_s_write_offset << 8, mslice, |
radeon_bo_size(track->db_s_write_bo)); |
return -EINVAL; |
} |
/* hyperz */ |
if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) { |
r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby); |
if (r) { |
return r; |
} |
} |
return 0; |
} |
static int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p) |
{ |
struct evergreen_cs_track *track = p->track; |
struct eg_surface surf; |
unsigned pitch, slice, mslice; |
unsigned long offset; |
int r; |
mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1; |
pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size); |
slice = track->db_depth_slice; |
surf.nbx = (pitch + 1) * 8; |
surf.nby = ((slice + 1) * 64) / surf.nbx; |
surf.mode = G_028040_ARRAY_MODE(track->db_z_info); |
surf.format = G_028040_FORMAT(track->db_z_info); |
surf.tsplit = G_028040_TILE_SPLIT(track->db_z_info); |
surf.nbanks = G_028040_NUM_BANKS(track->db_z_info); |
surf.bankw = G_028040_BANK_WIDTH(track->db_z_info); |
surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info); |
surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info); |
surf.nsamples = 1; |
switch (surf.format) { |
case V_028040_Z_16: |
surf.format = V_028C70_COLOR_16; |
break; |
case V_028040_Z_24: |
case V_028040_Z_32_FLOAT: |
surf.format = V_028C70_COLOR_8_8_8_8; |
break; |
default: |
dev_warn(p->dev, "%s:%d depth invalid format %d\n", |
__func__, __LINE__, surf.format); |
return -EINVAL; |
} |
r = evergreen_surface_value_conv_check(p, &surf, "depth"); |
if (r) { |
dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n", |
__func__, __LINE__, track->db_depth_size, |
track->db_depth_slice, track->db_z_info); |
return r; |
} |
r = evergreen_surface_check(p, &surf, "depth"); |
if (r) { |
dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n", |
__func__, __LINE__, track->db_depth_size, |
track->db_depth_slice, track->db_z_info); |
return r; |
} |
offset = track->db_z_read_offset << 8; |
if (offset & (surf.base_align - 1)) { |
dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n", |
__func__, __LINE__, offset, surf.base_align); |
return -EINVAL; |
} |
offset += surf.layer_size * mslice; |
if (offset > radeon_bo_size(track->db_z_read_bo)) { |
dev_warn(p->dev, "%s:%d depth read bo too small (layer size %d, " |
"offset %ld, max layer %d, bo size %ld)\n", |
__func__, __LINE__, surf.layer_size, |
(unsigned long)track->db_z_read_offset << 8, mslice, |
radeon_bo_size(track->db_z_read_bo)); |
return -EINVAL; |
} |
offset = track->db_z_write_offset << 8; |
if (offset & (surf.base_align - 1)) { |
dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n", |
__func__, __LINE__, offset, surf.base_align); |
return -EINVAL; |
} |
offset += surf.layer_size * mslice; |
if (offset > radeon_bo_size(track->db_z_write_bo)) { |
dev_warn(p->dev, "%s:%d depth write bo too small (layer size %d, " |
"offset %ld, max layer %d, bo size %ld)\n", |
__func__, __LINE__, surf.layer_size, |
(unsigned long)track->db_z_write_offset << 8, mslice, |
radeon_bo_size(track->db_z_write_bo)); |
return -EINVAL; |
} |
/* hyperz */ |
if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) { |
r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby); |
if (r) { |
return r; |
} |
} |
return 0; |
} |
static int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p, |
struct radeon_bo *texture, |
struct radeon_bo *mipmap, |
unsigned idx) |
{ |
struct eg_surface surf; |
unsigned long toffset, moffset; |
unsigned dim, llevel, mslice, width, height, depth, i; |
u32 texdw[8]; |
int r; |
texdw[0] = radeon_get_ib_value(p, idx + 0); |
texdw[1] = radeon_get_ib_value(p, idx + 1); |
texdw[2] = radeon_get_ib_value(p, idx + 2); |
texdw[3] = radeon_get_ib_value(p, idx + 3); |
texdw[4] = radeon_get_ib_value(p, idx + 4); |
texdw[5] = radeon_get_ib_value(p, idx + 5); |
texdw[6] = radeon_get_ib_value(p, idx + 6); |
texdw[7] = radeon_get_ib_value(p, idx + 7); |
dim = G_030000_DIM(texdw[0]); |
llevel = G_030014_LAST_LEVEL(texdw[5]); |
mslice = G_030014_LAST_ARRAY(texdw[5]) + 1; |
width = G_030000_TEX_WIDTH(texdw[0]) + 1; |
height = G_030004_TEX_HEIGHT(texdw[1]) + 1; |
depth = G_030004_TEX_DEPTH(texdw[1]) + 1; |
surf.format = G_03001C_DATA_FORMAT(texdw[7]); |
surf.nbx = (G_030000_PITCH(texdw[0]) + 1) * 8; |
surf.nbx = r600_fmt_get_nblocksx(surf.format, surf.nbx); |
surf.nby = r600_fmt_get_nblocksy(surf.format, height); |
surf.mode = G_030004_ARRAY_MODE(texdw[1]); |
surf.tsplit = G_030018_TILE_SPLIT(texdw[6]); |
surf.nbanks = G_03001C_NUM_BANKS(texdw[7]); |
surf.bankw = G_03001C_BANK_WIDTH(texdw[7]); |
surf.bankh = G_03001C_BANK_HEIGHT(texdw[7]); |
surf.mtilea = G_03001C_MACRO_TILE_ASPECT(texdw[7]); |
surf.nsamples = 1; |
toffset = texdw[2] << 8; |
moffset = texdw[3] << 8; |
if (!r600_fmt_is_valid_texture(surf.format, p->family)) { |
dev_warn(p->dev, "%s:%d texture invalid format %d\n", |
__func__, __LINE__, surf.format); |
return -EINVAL; |
} |
switch (dim) { |
case V_030000_SQ_TEX_DIM_1D: |
case V_030000_SQ_TEX_DIM_2D: |
case V_030000_SQ_TEX_DIM_CUBEMAP: |
case V_030000_SQ_TEX_DIM_1D_ARRAY: |
case V_030000_SQ_TEX_DIM_2D_ARRAY: |
depth = 1; |
break; |
case V_030000_SQ_TEX_DIM_2D_MSAA: |
case V_030000_SQ_TEX_DIM_2D_ARRAY_MSAA: |
surf.nsamples = 1 << llevel; |
llevel = 0; |
depth = 1; |
break; |
case V_030000_SQ_TEX_DIM_3D: |
break; |
default: |
dev_warn(p->dev, "%s:%d texture invalid dimension %d\n", |
__func__, __LINE__, dim); |
return -EINVAL; |
} |
r = evergreen_surface_value_conv_check(p, &surf, "texture"); |
if (r) { |
return r; |
} |
/* align height */ |
evergreen_surface_check(p, &surf, NULL); |
surf.nby = ALIGN(surf.nby, surf.halign); |
r = evergreen_surface_check(p, &surf, "texture"); |
if (r) { |
dev_warn(p->dev, "%s:%d texture invalid 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", |
__func__, __LINE__, texdw[0], texdw[1], texdw[4], |
texdw[5], texdw[6], texdw[7]); |
return r; |
} |
/* check texture size */ |
if (toffset & (surf.base_align - 1)) { |
dev_warn(p->dev, "%s:%d texture bo base %ld not aligned with %ld\n", |
__func__, __LINE__, toffset, surf.base_align); |
return -EINVAL; |
} |
if (surf.nsamples <= 1 && moffset & (surf.base_align - 1)) { |
dev_warn(p->dev, "%s:%d mipmap bo base %ld not aligned with %ld\n", |
__func__, __LINE__, moffset, surf.base_align); |
return -EINVAL; |
} |
if (dim == SQ_TEX_DIM_3D) { |
toffset += surf.layer_size * depth; |
} else { |
toffset += surf.layer_size * mslice; |
} |
if (toffset > radeon_bo_size(texture)) { |
dev_warn(p->dev, "%s:%d texture bo too small (layer size %d, " |
"offset %ld, max layer %d, depth %d, bo size %ld) (%d %d)\n", |
__func__, __LINE__, surf.layer_size, |
(unsigned long)texdw[2] << 8, mslice, |
depth, radeon_bo_size(texture), |
surf.nbx, surf.nby); |
return -EINVAL; |
} |
if (!mipmap) { |
if (llevel) { |
dev_warn(p->dev, "%s:%i got NULL MIP_ADDRESS relocation\n", |
__func__, __LINE__); |
return -EINVAL; |
} else { |
return 0; /* everything's ok */ |
} |
} |
/* check mipmap size */ |
for (i = 1; i <= llevel; i++) { |
unsigned w, h, d; |
w = r600_mip_minify(width, i); |
h = r600_mip_minify(height, i); |
d = r600_mip_minify(depth, i); |
surf.nbx = r600_fmt_get_nblocksx(surf.format, w); |
surf.nby = r600_fmt_get_nblocksy(surf.format, h); |
switch (surf.mode) { |
case ARRAY_2D_TILED_THIN1: |
if (surf.nbx < surf.palign || surf.nby < surf.halign) { |
surf.mode = ARRAY_1D_TILED_THIN1; |
} |
/* recompute alignment */ |
evergreen_surface_check(p, &surf, NULL); |
break; |
case ARRAY_LINEAR_GENERAL: |
case ARRAY_LINEAR_ALIGNED: |
case ARRAY_1D_TILED_THIN1: |
break; |
default: |
dev_warn(p->dev, "%s:%d invalid array mode %d\n", |
__func__, __LINE__, surf.mode); |
return -EINVAL; |
} |
surf.nbx = ALIGN(surf.nbx, surf.palign); |
surf.nby = ALIGN(surf.nby, surf.halign); |
r = evergreen_surface_check(p, &surf, "mipmap"); |
if (r) { |
return r; |
} |
if (dim == SQ_TEX_DIM_3D) { |
moffset += surf.layer_size * d; |
} else { |
moffset += surf.layer_size * mslice; |
} |
if (moffset > radeon_bo_size(mipmap)) { |
dev_warn(p->dev, "%s:%d mipmap [%d] bo too small (layer size %d, " |
"offset %ld, coffset %ld, max layer %d, depth %d, " |
"bo size %ld) level0 (%d %d %d)\n", |
__func__, __LINE__, i, surf.layer_size, |
(unsigned long)texdw[3] << 8, moffset, mslice, |
d, radeon_bo_size(mipmap), |
width, height, depth); |
dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n", |
__func__, __LINE__, surf.nbx, surf.nby, |
surf.mode, surf.bpe, surf.nsamples, |
surf.bankw, surf.bankh, |
surf.tsplit, surf.mtilea); |
return -EINVAL; |
} |
} |
return 0; |
} |
static int evergreen_cs_track_check(struct radeon_cs_parser *p) |
{ |
struct evergreen_cs_track *track = p->track; |
unsigned tmp, i; |
int r; |
unsigned buffer_mask = 0; |
/* check streamout */ |
if (track->streamout_dirty && track->vgt_strmout_config) { |
for (i = 0; i < 4; i++) { |
if (track->vgt_strmout_config & (1 << i)) { |
buffer_mask |= (track->vgt_strmout_buffer_config >> (i * 4)) & 0xf; |
} |
} |
for (i = 0; i < 4; i++) { |
if (buffer_mask & (1 << i)) { |
if (track->vgt_strmout_bo[i]) { |
u64 offset = (u64)track->vgt_strmout_bo_offset[i] + |
(u64)track->vgt_strmout_size[i]; |
if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) { |
DRM_ERROR("streamout %d bo too small: 0x%llx, 0x%lx\n", |
i, offset, |
radeon_bo_size(track->vgt_strmout_bo[i])); |
return -EINVAL; |
} |
} else { |
dev_warn(p->dev, "No buffer for streamout %d\n", i); |
return -EINVAL; |
} |
} |
} |
track->streamout_dirty = false; |
} |
if (track->sx_misc_kill_all_prims) |
return 0; |
/* check that we have a cb for each enabled target |
*/ |
if (track->cb_dirty) { |
tmp = track->cb_target_mask; |
for (i = 0; i < 8; i++) { |
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", |
__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i); |
return -EINVAL; |
} |
/* check cb */ |
r = evergreen_cs_track_validate_cb(p, i); |
if (r) { |
return r; |
} |
} |
} |
track->cb_dirty = false; |
} |
if (track->db_dirty) { |
/* Check stencil buffer */ |
if (G_028044_FORMAT(track->db_s_info) != V_028044_STENCIL_INVALID && |
G_028800_STENCIL_ENABLE(track->db_depth_control)) { |
r = evergreen_cs_track_validate_stencil(p); |
if (r) |
return r; |
} |
/* Check depth buffer */ |
if (G_028040_FORMAT(track->db_z_info) != V_028040_Z_INVALID && |
G_028800_Z_ENABLE(track->db_depth_control)) { |
r = evergreen_cs_track_validate_depth(p); |
if (r) |
return r; |
} |
track->db_dirty = false; |
} |
return 0; |
} |
/** |
* evergreen_cs_packet_parse_vline() - parse userspace VLINE packet |
* @parser: parser structure holding parsing context. |
* |
* This is an Evergreen(+)-specific function for parsing VLINE packets. |
* Real work is done by r600_cs_common_vline_parse function. |
* Here we just set up ASIC-specific register table and call |
* the common implementation function. |
*/ |
static int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p) |
{ |
static uint32_t vline_start_end[6] = { |
EVERGREEN_VLINE_START_END + EVERGREEN_CRTC0_REGISTER_OFFSET, |
EVERGREEN_VLINE_START_END + EVERGREEN_CRTC1_REGISTER_OFFSET, |
EVERGREEN_VLINE_START_END + EVERGREEN_CRTC2_REGISTER_OFFSET, |
EVERGREEN_VLINE_START_END + EVERGREEN_CRTC3_REGISTER_OFFSET, |
EVERGREEN_VLINE_START_END + EVERGREEN_CRTC4_REGISTER_OFFSET, |
EVERGREEN_VLINE_START_END + EVERGREEN_CRTC5_REGISTER_OFFSET |
}; |
static uint32_t vline_status[6] = { |
EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, |
EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, |
EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, |
EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, |
EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, |
EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET |
}; |
return r600_cs_common_vline_parse(p, vline_start_end, vline_status); |
} |
static int evergreen_packet0_check(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
unsigned idx, unsigned reg) |
{ |
int r; |
switch (reg) { |
case EVERGREEN_VLINE_START_END: |
r = evergreen_cs_packet_parse_vline(p); |
if (r) { |
DRM_ERROR("No reloc for ib[%d]=0x%04X\n", |
idx, reg); |
return r; |
} |
break; |
default: |
printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", |
reg, idx); |
return -EINVAL; |
} |
return 0; |
} |
static int evergreen_cs_parse_packet0(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt) |
{ |
unsigned reg, i; |
unsigned idx; |
int r; |
idx = pkt->idx + 1; |
reg = pkt->reg; |
for (i = 0; i <= pkt->count; i++, idx++, reg += 4) { |
r = evergreen_packet0_check(p, pkt, idx, reg); |
if (r) { |
return r; |
} |
} |
return 0; |
} |
/** |
* evergreen_cs_check_reg() - check if register is authorized or not |
* @parser: parser structure holding parsing context |
* @reg: register we are testing |
* @idx: index into the cs buffer |
* |
* This function will test against evergreen_reg_safe_bm and return 0 |
* if register is safe. If register is not flag as safe this function |
* will test it against a list of register needind special handling. |
*/ |
static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) |
{ |
struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track; |
struct radeon_cs_reloc *reloc; |
u32 last_reg; |
u32 m, i, tmp, *ib; |
int r; |
if (p->rdev->family >= CHIP_CAYMAN) |
last_reg = ARRAY_SIZE(cayman_reg_safe_bm); |
else |
last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); |
i = (reg >> 7); |
if (i >= last_reg) { |
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); |
return -EINVAL; |
} |
m = 1 << ((reg >> 2) & 31); |
if (p->rdev->family >= CHIP_CAYMAN) { |
if (!(cayman_reg_safe_bm[i] & m)) |
return 0; |
} else { |
if (!(evergreen_reg_safe_bm[i] & m)) |
return 0; |
} |
ib = p->ib.ptr; |
switch (reg) { |
/* force following reg to 0 in an attempt to disable out buffer |
* which will need us to better understand how it works to perform |
* security check on it (Jerome) |
*/ |
case SQ_ESGS_RING_SIZE: |
case SQ_GSVS_RING_SIZE: |
case SQ_ESTMP_RING_SIZE: |
case SQ_GSTMP_RING_SIZE: |
case SQ_HSTMP_RING_SIZE: |
case SQ_LSTMP_RING_SIZE: |
case SQ_PSTMP_RING_SIZE: |
case SQ_VSTMP_RING_SIZE: |
case SQ_ESGS_RING_ITEMSIZE: |
case SQ_ESTMP_RING_ITEMSIZE: |
case SQ_GSTMP_RING_ITEMSIZE: |
case SQ_GSVS_RING_ITEMSIZE: |
case SQ_GS_VERT_ITEMSIZE: |
case SQ_GS_VERT_ITEMSIZE_1: |
case SQ_GS_VERT_ITEMSIZE_2: |
case SQ_GS_VERT_ITEMSIZE_3: |
case SQ_GSVS_RING_OFFSET_1: |
case SQ_GSVS_RING_OFFSET_2: |
case SQ_GSVS_RING_OFFSET_3: |
case SQ_HSTMP_RING_ITEMSIZE: |
case SQ_LSTMP_RING_ITEMSIZE: |
case SQ_PSTMP_RING_ITEMSIZE: |
case SQ_VSTMP_RING_ITEMSIZE: |
case VGT_TF_RING_SIZE: |
/* get value to populate the IB don't remove */ |
/*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_HSTMP_RING_BASE: |
case SQ_LSTMP_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 DB_DEPTH_CONTROL: |
track->db_depth_control = radeon_get_ib_value(p, idx); |
track->db_dirty = true; |
break; |
case CAYMAN_DB_EQAA: |
if (p->rdev->family < CHIP_CAYMAN) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
break; |
case CAYMAN_DB_DEPTH_INFO: |
if (p->rdev->family < CHIP_CAYMAN) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
break; |
case DB_Z_INFO: |
track->db_z_info = radeon_get_ib_value(p, idx); |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { |
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] &= ~Z_ARRAY_MODE(0xf); |
track->db_z_info &= ~Z_ARRAY_MODE(0xf); |
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->tiling_flags, |
&bankw, &bankh, &mtaspect, |
&tile_split); |
ib[idx] |= DB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); |
ib[idx] |= DB_TILE_SPLIT(tile_split) | |
DB_BANK_WIDTH(bankw) | |
DB_BANK_HEIGHT(bankh) | |
DB_MACRO_TILE_ASPECT(mtaspect); |
} |
} |
track->db_dirty = true; |
break; |
case DB_STENCIL_INFO: |
track->db_s_info = radeon_get_ib_value(p, idx); |
track->db_dirty = true; |
break; |
case DB_DEPTH_VIEW: |
track->db_depth_view = radeon_get_ib_value(p, idx); |
track->db_dirty = true; |
break; |
case DB_DEPTH_SIZE: |
track->db_depth_size = radeon_get_ib_value(p, idx); |
track->db_dirty = true; |
break; |
case R_02805C_DB_DEPTH_SLICE: |
track->db_depth_slice = radeon_get_ib_value(p, idx); |
track->db_dirty = true; |
break; |
case DB_Z_READ_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; |
} |
track->db_z_read_offset = radeon_get_ib_value(p, idx); |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->db_z_read_bo = reloc->robj; |
track->db_dirty = true; |
break; |
case DB_Z_WRITE_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; |
} |
track->db_z_write_offset = radeon_get_ib_value(p, idx); |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->db_z_write_bo = reloc->robj; |
track->db_dirty = true; |
break; |
case DB_STENCIL_READ_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; |
} |
track->db_s_read_offset = radeon_get_ib_value(p, idx); |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->db_s_read_bo = reloc->robj; |
track->db_dirty = true; |
break; |
case DB_STENCIL_WRITE_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; |
} |
track->db_s_write_offset = radeon_get_ib_value(p, idx); |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->db_s_write_bo = reloc->robj; |
track->db_dirty = true; |
break; |
case VGT_STRMOUT_CONFIG: |
track->vgt_strmout_config = radeon_get_ib_value(p, idx); |
track->streamout_dirty = true; |
break; |
case VGT_STRMOUT_BUFFER_CONFIG: |
track->vgt_strmout_buffer_config = radeon_get_ib_value(p, idx); |
track->streamout_dirty = true; |
break; |
case VGT_STRMOUT_BUFFER_BASE_0: |
case VGT_STRMOUT_BUFFER_BASE_1: |
case VGT_STRMOUT_BUFFER_BASE_2: |
case VGT_STRMOUT_BUFFER_BASE_3: |
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; |
} |
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->gpu_offset >> 8) & 0xffffffff); |
track->vgt_strmout_bo[tmp] = reloc->robj; |
track->streamout_dirty = true; |
break; |
case VGT_STRMOUT_BUFFER_SIZE_0: |
case VGT_STRMOUT_BUFFER_SIZE_1: |
case VGT_STRMOUT_BUFFER_SIZE_2: |
case VGT_STRMOUT_BUFFER_SIZE_3: |
tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16; |
/* size in register is DWs, convert to bytes */ |
track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4; |
track->streamout_dirty = true; |
break; |
case CP_COHER_BASE: |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
dev_warn(p->dev, "missing reloc for CP_COHER_BASE " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
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; |
break; |
case CB_SHADER_MASK: |
track->cb_shader_mask = radeon_get_ib_value(p, idx); |
track->cb_dirty = true; |
break; |
case PA_SC_AA_CONFIG: |
if (p->rdev->family >= CHIP_CAYMAN) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
tmp = radeon_get_ib_value(p, idx) & MSAA_NUM_SAMPLES_MASK; |
track->nsamples = 1 << tmp; |
break; |
case CAYMAN_PA_SC_AA_CONFIG: |
if (p->rdev->family < CHIP_CAYMAN) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
tmp = radeon_get_ib_value(p, idx) & CAYMAN_MSAA_NUM_SAMPLES_MASK; |
track->nsamples = 1 << tmp; |
break; |
case CB_COLOR0_VIEW: |
case CB_COLOR1_VIEW: |
case CB_COLOR2_VIEW: |
case CB_COLOR3_VIEW: |
case CB_COLOR4_VIEW: |
case CB_COLOR5_VIEW: |
case CB_COLOR6_VIEW: |
case CB_COLOR7_VIEW: |
tmp = (reg - CB_COLOR0_VIEW) / 0x3c; |
track->cb_color_view[tmp] = radeon_get_ib_value(p, idx); |
track->cb_dirty = true; |
break; |
case CB_COLOR8_VIEW: |
case CB_COLOR9_VIEW: |
case CB_COLOR10_VIEW: |
case CB_COLOR11_VIEW: |
tmp = ((reg - CB_COLOR8_VIEW) / 0x1c) + 8; |
track->cb_color_view[tmp] = radeon_get_ib_value(p, idx); |
track->cb_dirty = true; |
break; |
case CB_COLOR0_INFO: |
case CB_COLOR1_INFO: |
case CB_COLOR2_INFO: |
case CB_COLOR3_INFO: |
case CB_COLOR4_INFO: |
case CB_COLOR5_INFO: |
case CB_COLOR6_INFO: |
case CB_COLOR7_INFO: |
tmp = (reg - CB_COLOR0_INFO) / 0x3c; |
track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { |
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] |= 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; |
case CB_COLOR8_INFO: |
case CB_COLOR9_INFO: |
case CB_COLOR10_INFO: |
case CB_COLOR11_INFO: |
tmp = ((reg - CB_COLOR8_INFO) / 0x1c) + 8; |
track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { |
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] |= 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; |
case CB_COLOR0_PITCH: |
case CB_COLOR1_PITCH: |
case CB_COLOR2_PITCH: |
case CB_COLOR3_PITCH: |
case CB_COLOR4_PITCH: |
case CB_COLOR5_PITCH: |
case CB_COLOR6_PITCH: |
case CB_COLOR7_PITCH: |
tmp = (reg - CB_COLOR0_PITCH) / 0x3c; |
track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx); |
track->cb_dirty = true; |
break; |
case CB_COLOR8_PITCH: |
case CB_COLOR9_PITCH: |
case CB_COLOR10_PITCH: |
case CB_COLOR11_PITCH: |
tmp = ((reg - CB_COLOR8_PITCH) / 0x1c) + 8; |
track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx); |
track->cb_dirty = true; |
break; |
case CB_COLOR0_SLICE: |
case CB_COLOR1_SLICE: |
case CB_COLOR2_SLICE: |
case CB_COLOR3_SLICE: |
case CB_COLOR4_SLICE: |
case CB_COLOR5_SLICE: |
case CB_COLOR6_SLICE: |
case CB_COLOR7_SLICE: |
tmp = (reg - CB_COLOR0_SLICE) / 0x3c; |
track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx); |
track->cb_color_slice_idx[tmp] = idx; |
track->cb_dirty = true; |
break; |
case CB_COLOR8_SLICE: |
case CB_COLOR9_SLICE: |
case CB_COLOR10_SLICE: |
case CB_COLOR11_SLICE: |
tmp = ((reg - CB_COLOR8_SLICE) / 0x1c) + 8; |
track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx); |
track->cb_color_slice_idx[tmp] = idx; |
track->cb_dirty = true; |
break; |
case CB_COLOR0_ATTRIB: |
case CB_COLOR1_ATTRIB: |
case CB_COLOR2_ATTRIB: |
case CB_COLOR3_ATTRIB: |
case CB_COLOR4_ATTRIB: |
case CB_COLOR5_ATTRIB: |
case CB_COLOR6_ATTRIB: |
case CB_COLOR7_ATTRIB: |
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; |
} |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { |
if (reloc->tiling_flags & RADEON_TILING_MACRO) { |
unsigned bankw, bankh, mtaspect, tile_split; |
evergreen_tiling_fields(reloc->tiling_flags, |
&bankw, &bankh, &mtaspect, |
&tile_split); |
ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); |
ib[idx] |= CB_TILE_SPLIT(tile_split) | |
CB_BANK_WIDTH(bankw) | |
CB_BANK_HEIGHT(bankh) | |
CB_MACRO_TILE_ASPECT(mtaspect); |
} |
} |
tmp = ((reg - CB_COLOR0_ATTRIB) / 0x3c); |
track->cb_color_attrib[tmp] = ib[idx]; |
track->cb_dirty = true; |
break; |
case CB_COLOR8_ATTRIB: |
case CB_COLOR9_ATTRIB: |
case CB_COLOR10_ATTRIB: |
case CB_COLOR11_ATTRIB: |
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; |
} |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { |
if (reloc->tiling_flags & RADEON_TILING_MACRO) { |
unsigned bankw, bankh, mtaspect, tile_split; |
evergreen_tiling_fields(reloc->tiling_flags, |
&bankw, &bankh, &mtaspect, |
&tile_split); |
ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); |
ib[idx] |= CB_TILE_SPLIT(tile_split) | |
CB_BANK_WIDTH(bankw) | |
CB_BANK_HEIGHT(bankh) | |
CB_MACRO_TILE_ASPECT(mtaspect); |
} |
} |
tmp = ((reg - CB_COLOR8_ATTRIB) / 0x1c) + 8; |
track->cb_color_attrib[tmp] = ib[idx]; |
track->cb_dirty = true; |
break; |
case CB_COLOR0_FMASK: |
case CB_COLOR1_FMASK: |
case CB_COLOR2_FMASK: |
case CB_COLOR3_FMASK: |
case CB_COLOR4_FMASK: |
case CB_COLOR5_FMASK: |
case CB_COLOR6_FMASK: |
case CB_COLOR7_FMASK: |
tmp = (reg - CB_COLOR0_FMASK) / 0x3c; |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); |
return -EINVAL; |
} |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->cb_color_fmask_bo[tmp] = reloc->robj; |
break; |
case CB_COLOR0_CMASK: |
case CB_COLOR1_CMASK: |
case CB_COLOR2_CMASK: |
case CB_COLOR3_CMASK: |
case CB_COLOR4_CMASK: |
case CB_COLOR5_CMASK: |
case CB_COLOR6_CMASK: |
case CB_COLOR7_CMASK: |
tmp = (reg - CB_COLOR0_CMASK) / 0x3c; |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); |
return -EINVAL; |
} |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->cb_color_cmask_bo[tmp] = reloc->robj; |
break; |
case CB_COLOR0_FMASK_SLICE: |
case CB_COLOR1_FMASK_SLICE: |
case CB_COLOR2_FMASK_SLICE: |
case CB_COLOR3_FMASK_SLICE: |
case CB_COLOR4_FMASK_SLICE: |
case CB_COLOR5_FMASK_SLICE: |
case CB_COLOR6_FMASK_SLICE: |
case CB_COLOR7_FMASK_SLICE: |
tmp = (reg - CB_COLOR0_FMASK_SLICE) / 0x3c; |
track->cb_color_fmask_slice[tmp] = radeon_get_ib_value(p, idx); |
break; |
case CB_COLOR0_CMASK_SLICE: |
case CB_COLOR1_CMASK_SLICE: |
case CB_COLOR2_CMASK_SLICE: |
case CB_COLOR3_CMASK_SLICE: |
case CB_COLOR4_CMASK_SLICE: |
case CB_COLOR5_CMASK_SLICE: |
case CB_COLOR6_CMASK_SLICE: |
case CB_COLOR7_CMASK_SLICE: |
tmp = (reg - CB_COLOR0_CMASK_SLICE) / 0x3c; |
track->cb_color_cmask_slice[tmp] = radeon_get_ib_value(p, idx); |
break; |
case CB_COLOR0_BASE: |
case CB_COLOR1_BASE: |
case CB_COLOR2_BASE: |
case CB_COLOR3_BASE: |
case CB_COLOR4_BASE: |
case CB_COLOR5_BASE: |
case CB_COLOR6_BASE: |
case CB_COLOR7_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; |
} |
tmp = (reg - CB_COLOR0_BASE) / 0x3c; |
track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx); |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->cb_color_bo[tmp] = reloc->robj; |
track->cb_dirty = true; |
break; |
case CB_COLOR8_BASE: |
case CB_COLOR9_BASE: |
case CB_COLOR10_BASE: |
case CB_COLOR11_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; |
} |
tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8; |
track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx); |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->cb_color_bo[tmp] = reloc->robj; |
track->cb_dirty = true; |
break; |
case DB_HTILE_DATA_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; |
} |
track->htile_offset = radeon_get_ib_value(p, idx); |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->htile_bo = reloc->robj; |
track->db_dirty = true; |
break; |
case DB_HTILE_SURFACE: |
/* 8x8 only */ |
track->htile_surface = radeon_get_ib_value(p, idx); |
/* force 8x8 htile width and height */ |
ib[idx] |= 3; |
track->db_dirty = true; |
break; |
case CB_IMMED0_BASE: |
case CB_IMMED1_BASE: |
case CB_IMMED2_BASE: |
case CB_IMMED3_BASE: |
case CB_IMMED4_BASE: |
case CB_IMMED5_BASE: |
case CB_IMMED6_BASE: |
case CB_IMMED7_BASE: |
case CB_IMMED8_BASE: |
case CB_IMMED9_BASE: |
case CB_IMMED10_BASE: |
case CB_IMMED11_BASE: |
case SQ_PGM_START_FS: |
case SQ_PGM_START_ES: |
case SQ_PGM_START_VS: |
case SQ_PGM_START_GS: |
case SQ_PGM_START_PS: |
case SQ_PGM_START_HS: |
case SQ_PGM_START_LS: |
case SQ_CONST_MEM_BASE: |
case SQ_ALU_CONST_CACHE_GS_0: |
case SQ_ALU_CONST_CACHE_GS_1: |
case SQ_ALU_CONST_CACHE_GS_2: |
case SQ_ALU_CONST_CACHE_GS_3: |
case SQ_ALU_CONST_CACHE_GS_4: |
case SQ_ALU_CONST_CACHE_GS_5: |
case SQ_ALU_CONST_CACHE_GS_6: |
case SQ_ALU_CONST_CACHE_GS_7: |
case SQ_ALU_CONST_CACHE_GS_8: |
case SQ_ALU_CONST_CACHE_GS_9: |
case SQ_ALU_CONST_CACHE_GS_10: |
case SQ_ALU_CONST_CACHE_GS_11: |
case SQ_ALU_CONST_CACHE_GS_12: |
case SQ_ALU_CONST_CACHE_GS_13: |
case SQ_ALU_CONST_CACHE_GS_14: |
case SQ_ALU_CONST_CACHE_GS_15: |
case SQ_ALU_CONST_CACHE_PS_0: |
case SQ_ALU_CONST_CACHE_PS_1: |
case SQ_ALU_CONST_CACHE_PS_2: |
case SQ_ALU_CONST_CACHE_PS_3: |
case SQ_ALU_CONST_CACHE_PS_4: |
case SQ_ALU_CONST_CACHE_PS_5: |
case SQ_ALU_CONST_CACHE_PS_6: |
case SQ_ALU_CONST_CACHE_PS_7: |
case SQ_ALU_CONST_CACHE_PS_8: |
case SQ_ALU_CONST_CACHE_PS_9: |
case SQ_ALU_CONST_CACHE_PS_10: |
case SQ_ALU_CONST_CACHE_PS_11: |
case SQ_ALU_CONST_CACHE_PS_12: |
case SQ_ALU_CONST_CACHE_PS_13: |
case SQ_ALU_CONST_CACHE_PS_14: |
case SQ_ALU_CONST_CACHE_PS_15: |
case SQ_ALU_CONST_CACHE_VS_0: |
case SQ_ALU_CONST_CACHE_VS_1: |
case SQ_ALU_CONST_CACHE_VS_2: |
case SQ_ALU_CONST_CACHE_VS_3: |
case SQ_ALU_CONST_CACHE_VS_4: |
case SQ_ALU_CONST_CACHE_VS_5: |
case SQ_ALU_CONST_CACHE_VS_6: |
case SQ_ALU_CONST_CACHE_VS_7: |
case SQ_ALU_CONST_CACHE_VS_8: |
case SQ_ALU_CONST_CACHE_VS_9: |
case SQ_ALU_CONST_CACHE_VS_10: |
case SQ_ALU_CONST_CACHE_VS_11: |
case SQ_ALU_CONST_CACHE_VS_12: |
case SQ_ALU_CONST_CACHE_VS_13: |
case SQ_ALU_CONST_CACHE_VS_14: |
case SQ_ALU_CONST_CACHE_VS_15: |
case SQ_ALU_CONST_CACHE_HS_0: |
case SQ_ALU_CONST_CACHE_HS_1: |
case SQ_ALU_CONST_CACHE_HS_2: |
case SQ_ALU_CONST_CACHE_HS_3: |
case SQ_ALU_CONST_CACHE_HS_4: |
case SQ_ALU_CONST_CACHE_HS_5: |
case SQ_ALU_CONST_CACHE_HS_6: |
case SQ_ALU_CONST_CACHE_HS_7: |
case SQ_ALU_CONST_CACHE_HS_8: |
case SQ_ALU_CONST_CACHE_HS_9: |
case SQ_ALU_CONST_CACHE_HS_10: |
case SQ_ALU_CONST_CACHE_HS_11: |
case SQ_ALU_CONST_CACHE_HS_12: |
case SQ_ALU_CONST_CACHE_HS_13: |
case SQ_ALU_CONST_CACHE_HS_14: |
case SQ_ALU_CONST_CACHE_HS_15: |
case SQ_ALU_CONST_CACHE_LS_0: |
case SQ_ALU_CONST_CACHE_LS_1: |
case SQ_ALU_CONST_CACHE_LS_2: |
case SQ_ALU_CONST_CACHE_LS_3: |
case SQ_ALU_CONST_CACHE_LS_4: |
case SQ_ALU_CONST_CACHE_LS_5: |
case SQ_ALU_CONST_CACHE_LS_6: |
case SQ_ALU_CONST_CACHE_LS_7: |
case SQ_ALU_CONST_CACHE_LS_8: |
case SQ_ALU_CONST_CACHE_LS_9: |
case SQ_ALU_CONST_CACHE_LS_10: |
case SQ_ALU_CONST_CACHE_LS_11: |
case SQ_ALU_CONST_CACHE_LS_12: |
case SQ_ALU_CONST_CACHE_LS_13: |
case SQ_ALU_CONST_CACHE_LS_14: |
case SQ_ALU_CONST_CACHE_LS_15: |
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 SX_MEMORY_EXPORT_BASE: |
if (p->rdev->family >= CHIP_CAYMAN) { |
dev_warn(p->dev, "bad SET_CONFIG_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
dev_warn(p->dev, "bad SET_CONFIG_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
break; |
case CAYMAN_SX_SCATTER_EXPORT_BASE: |
if (p->rdev->family < CHIP_CAYMAN) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
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 SX_MISC: |
track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0; |
break; |
default: |
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); |
return -EINVAL; |
} |
return 0; |
} |
static bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) |
{ |
u32 last_reg, m, i; |
if (p->rdev->family >= CHIP_CAYMAN) |
last_reg = ARRAY_SIZE(cayman_reg_safe_bm); |
else |
last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); |
i = (reg >> 7); |
if (i >= last_reg) { |
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); |
return false; |
} |
m = 1 << ((reg >> 2) & 31); |
if (p->rdev->family >= CHIP_CAYMAN) { |
if (!(cayman_reg_safe_bm[i] & m)) |
return true; |
} else { |
if (!(evergreen_reg_safe_bm[i] & m)) |
return true; |
} |
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); |
return false; |
} |
static int evergreen_packet3_check(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt) |
{ |
struct radeon_cs_reloc *reloc; |
struct evergreen_cs_track *track; |
volatile u32 *ib; |
unsigned idx; |
unsigned i; |
unsigned start_reg, end_reg, reg; |
int r; |
u32 idx_value; |
track = (struct evergreen_cs_track *)p->track; |
ib = p->ib.ptr; |
idx = pkt->idx + 1; |
idx_value = radeon_get_ib_value(p, idx); |
switch (pkt->opcode) { |
case PACKET3_SET_PREDICATION: |
{ |
int pred_op; |
int tmp; |
uint64_t offset; |
if (pkt->count != 1) { |
DRM_ERROR("bad SET PREDICATION\n"); |
return -EINVAL; |
} |
tmp = radeon_get_ib_value(p, idx + 1); |
pred_op = (tmp >> 16) & 0x7; |
/* for the clear predicate operation */ |
if (pred_op == 0) |
return 0; |
if (pred_op > 2) { |
DRM_ERROR("bad SET PREDICATION operation %d\n", pred_op); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad SET PREDICATION\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(idx_value & 0xfffffff0) + |
((u64)(tmp & 0xff) << 32); |
ib[idx + 0] = offset; |
ib[idx + 1] = (tmp & 0xffffff00) | (upper_32_bits(offset) & 0xff); |
} |
break; |
case PACKET3_CONTEXT_CONTROL: |
if (pkt->count != 1) { |
DRM_ERROR("bad CONTEXT_CONTROL\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_INDEX_TYPE: |
case PACKET3_NUM_INSTANCES: |
case PACKET3_CLEAR_STATE: |
if (pkt->count) { |
DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n"); |
return -EINVAL; |
} |
break; |
case CAYMAN_PACKET3_DEALLOC_STATE: |
if (p->rdev->family < CHIP_CAYMAN) { |
DRM_ERROR("bad PACKET3_DEALLOC_STATE\n"); |
return -EINVAL; |
} |
if (pkt->count) { |
DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_INDEX_BASE: |
{ |
uint64_t offset; |
if (pkt->count != 1) { |
DRM_ERROR("bad INDEX_BASE\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad INDEX_BASE\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
idx_value + |
((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); |
ib[idx+0] = offset; |
ib[idx+1] = upper_32_bits(offset) & 0xff; |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); |
return r; |
} |
break; |
} |
case PACKET3_DRAW_INDEX: |
{ |
uint64_t offset; |
if (pkt->count != 3) { |
DRM_ERROR("bad DRAW_INDEX\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad DRAW_INDEX\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
idx_value + |
((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); |
ib[idx+0] = offset; |
ib[idx+1] = upper_32_bits(offset) & 0xff; |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); |
return r; |
} |
break; |
} |
case PACKET3_DRAW_INDEX_2: |
{ |
uint64_t offset; |
if (pkt->count != 4) { |
DRM_ERROR("bad DRAW_INDEX_2\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad DRAW_INDEX_2\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
radeon_get_ib_value(p, idx+1) + |
((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); |
ib[idx+1] = offset; |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); |
return r; |
} |
break; |
} |
case PACKET3_DRAW_INDEX_AUTO: |
if (pkt->count != 1) { |
DRM_ERROR("bad DRAW_INDEX_AUTO\n"); |
return -EINVAL; |
} |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx); |
return r; |
} |
break; |
case PACKET3_DRAW_INDEX_MULTI_AUTO: |
if (pkt->count != 2) { |
DRM_ERROR("bad DRAW_INDEX_MULTI_AUTO\n"); |
return -EINVAL; |
} |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx); |
return r; |
} |
break; |
case PACKET3_DRAW_INDEX_IMMD: |
if (pkt->count < 2) { |
DRM_ERROR("bad DRAW_INDEX_IMMD\n"); |
return -EINVAL; |
} |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); |
return r; |
} |
break; |
case PACKET3_DRAW_INDEX_OFFSET: |
if (pkt->count != 2) { |
DRM_ERROR("bad DRAW_INDEX_OFFSET\n"); |
return -EINVAL; |
} |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); |
return r; |
} |
break; |
case PACKET3_DRAW_INDEX_OFFSET_2: |
if (pkt->count != 3) { |
DRM_ERROR("bad DRAW_INDEX_OFFSET_2\n"); |
return -EINVAL; |
} |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); |
return r; |
} |
break; |
case PACKET3_DISPATCH_DIRECT: |
if (pkt->count != 3) { |
DRM_ERROR("bad DISPATCH_DIRECT\n"); |
return -EINVAL; |
} |
r = evergreen_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx); |
return r; |
} |
break; |
case PACKET3_DISPATCH_INDIRECT: |
if (pkt->count != 1) { |
DRM_ERROR("bad DISPATCH_INDIRECT\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad DISPATCH_INDIRECT\n"); |
return -EINVAL; |
} |
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__); |
return r; |
} |
break; |
case PACKET3_WAIT_REG_MEM: |
if (pkt->count != 5) { |
DRM_ERROR("bad WAIT_REG_MEM\n"); |
return -EINVAL; |
} |
/* bit 4 is reg (0) or mem (1) */ |
if (idx_value & 0x10) { |
uint64_t offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad WAIT_REG_MEM\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(radeon_get_ib_value(p, idx+1) & 0xfffffffc) + |
((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); |
ib[idx+1] = (ib[idx+1] & 0x3) | (offset & 0xfffffffc); |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
} else if (idx_value & 0x100) { |
DRM_ERROR("cannot use PFP on REG wait\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_CP_DMA: |
{ |
u32 command, size, info; |
u64 offset, tmp; |
if (pkt->count != 4) { |
DRM_ERROR("bad CP DMA\n"); |
return -EINVAL; |
} |
command = radeon_get_ib_value(p, idx+4); |
size = command & 0x1fffff; |
info = radeon_get_ib_value(p, idx+1); |
if ((((info & 0x60000000) >> 29) != 0) || /* src = GDS or DATA */ |
(((info & 0x00300000) >> 20) != 0) || /* dst = GDS */ |
((((info & 0x00300000) >> 20) == 0) && |
(command & PACKET3_CP_DMA_CMD_DAS)) || /* dst = register */ |
((((info & 0x60000000) >> 29) == 0) && |
(command & PACKET3_CP_DMA_CMD_SAS))) { /* src = register */ |
/* non mem to mem copies requires dw aligned count */ |
if (size % 4) { |
DRM_ERROR("CP DMA command requires dw count alignment\n"); |
return -EINVAL; |
} |
} |
if (command & PACKET3_CP_DMA_CMD_SAS) { |
/* src address space is register */ |
/* GDS is ok */ |
if (((info & 0x60000000) >> 29) != 1) { |
DRM_ERROR("CP DMA SAS not supported\n"); |
return -EINVAL; |
} |
} else { |
if (command & PACKET3_CP_DMA_CMD_SAIC) { |
DRM_ERROR("CP DMA SAIC only supported for registers\n"); |
return -EINVAL; |
} |
/* src address space is memory */ |
if (((info & 0x60000000) >> 29) == 0) { |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad CP DMA SRC\n"); |
return -EINVAL; |
} |
tmp = radeon_get_ib_value(p, idx) + |
((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); |
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", |
tmp + size, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
ib[idx] = offset; |
ib[idx+1] = (ib[idx+1] & 0xffffff00) | (upper_32_bits(offset) & 0xff); |
} else if (((info & 0x60000000) >> 29) != 2) { |
DRM_ERROR("bad CP DMA SRC_SEL\n"); |
return -EINVAL; |
} |
} |
if (command & PACKET3_CP_DMA_CMD_DAS) { |
/* dst address space is register */ |
/* GDS is ok */ |
if (((info & 0x00300000) >> 20) != 1) { |
DRM_ERROR("CP DMA DAS not supported\n"); |
return -EINVAL; |
} |
} else { |
/* dst address space is memory */ |
if (command & PACKET3_CP_DMA_CMD_DAIC) { |
DRM_ERROR("CP DMA DAIC only supported for registers\n"); |
return -EINVAL; |
} |
if (((info & 0x00300000) >> 20) == 0) { |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad CP DMA DST\n"); |
return -EINVAL; |
} |
tmp = radeon_get_ib_value(p, idx+2) + |
((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32); |
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", |
tmp + size, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
ib[idx+2] = offset; |
ib[idx+3] = upper_32_bits(offset) & 0xff; |
} else { |
DRM_ERROR("bad CP DMA DST_SEL\n"); |
return -EINVAL; |
} |
} |
break; |
} |
case PACKET3_SURFACE_SYNC: |
if (pkt->count != 3) { |
DRM_ERROR("bad SURFACE_SYNC\n"); |
return -EINVAL; |
} |
/* 0xffffffff/0x0 is flush all cache flag */ |
if (radeon_get_ib_value(p, idx + 1) != 0xffffffff || |
radeon_get_ib_value(p, idx + 2) != 0) { |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad SURFACE_SYNC\n"); |
return -EINVAL; |
} |
ib[idx+2] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
} |
break; |
case PACKET3_EVENT_WRITE: |
if (pkt->count != 2 && pkt->count != 0) { |
DRM_ERROR("bad EVENT_WRITE\n"); |
return -EINVAL; |
} |
if (pkt->count) { |
uint64_t offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad EVENT_WRITE\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(radeon_get_ib_value(p, idx+1) & 0xfffffff8) + |
((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); |
ib[idx+1] = offset & 0xfffffff8; |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
} |
break; |
case PACKET3_EVENT_WRITE_EOP: |
{ |
uint64_t offset; |
if (pkt->count != 4) { |
DRM_ERROR("bad EVENT_WRITE_EOP\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad EVENT_WRITE_EOP\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(radeon_get_ib_value(p, idx+1) & 0xfffffffc) + |
((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); |
ib[idx+1] = offset & 0xfffffffc; |
ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff); |
break; |
} |
case PACKET3_EVENT_WRITE_EOS: |
{ |
uint64_t offset; |
if (pkt->count != 3) { |
DRM_ERROR("bad EVENT_WRITE_EOS\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad EVENT_WRITE_EOS\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(radeon_get_ib_value(p, idx+1) & 0xfffffffc) + |
((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); |
ib[idx+1] = offset & 0xfffffffc; |
ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff); |
break; |
} |
case PACKET3_SET_CONFIG_REG: |
start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_CONFIG_REG_START) || |
(start_reg >= PACKET3_SET_CONFIG_REG_END) || |
(end_reg >= PACKET3_SET_CONFIG_REG_END)) { |
DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n"); |
return -EINVAL; |
} |
for (i = 0; i < pkt->count; i++) { |
reg = start_reg + (4 * i); |
r = evergreen_cs_check_reg(p, reg, idx+1+i); |
if (r) |
return r; |
} |
break; |
case PACKET3_SET_CONTEXT_REG: |
start_reg = (idx_value << 2) + PACKET3_SET_CONTEXT_REG_START; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_CONTEXT_REG_START) || |
(start_reg >= PACKET3_SET_CONTEXT_REG_END) || |
(end_reg >= PACKET3_SET_CONTEXT_REG_END)) { |
DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n"); |
return -EINVAL; |
} |
for (i = 0; i < pkt->count; i++) { |
reg = start_reg + (4 * i); |
r = evergreen_cs_check_reg(p, reg, idx+1+i); |
if (r) |
return r; |
} |
break; |
case PACKET3_SET_RESOURCE: |
if (pkt->count % 8) { |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
start_reg = (idx_value << 2) + PACKET3_SET_RESOURCE_START; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_RESOURCE_START) || |
(start_reg >= PACKET3_SET_RESOURCE_END) || |
(end_reg >= PACKET3_SET_RESOURCE_END)) { |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
for (i = 0; i < (pkt->count / 8); i++) { |
struct radeon_bo *texture, *mipmap; |
u32 toffset, moffset; |
u32 size, offset, mip_address, tex_dim; |
switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) { |
case SQ_TEX_VTX_VALID_TEXTURE: |
/* tex base */ |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad SET_RESOURCE (tex)\n"); |
return -EINVAL; |
} |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { |
ib[idx+1+(i*8)+1] |= |
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->tiling_flags, |
&bankw, &bankh, &mtaspect, |
&tile_split); |
ib[idx+1+(i*8)+6] |= TEX_TILE_SPLIT(tile_split); |
ib[idx+1+(i*8)+7] |= |
TEX_BANK_WIDTH(bankw) | |
TEX_BANK_HEIGHT(bankh) | |
MACRO_TILE_ASPECT(mtaspect) | |
TEX_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); |
} |
} |
texture = reloc->robj; |
toffset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
/* tex mip base */ |
tex_dim = ib[idx+1+(i*8)+0] & 0x7; |
mip_address = ib[idx+1+(i*8)+3]; |
if ((tex_dim == SQ_TEX_DIM_2D_MSAA || tex_dim == SQ_TEX_DIM_2D_ARRAY_MSAA) && |
!mip_address && |
!radeon_cs_packet_next_is_pkt3_nop(p)) { |
/* MIP_ADDRESS should point to FMASK for an MSAA texture. |
* It should be 0 if FMASK is disabled. */ |
moffset = 0; |
mipmap = NULL; |
} else { |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad SET_RESOURCE (tex)\n"); |
return -EINVAL; |
} |
moffset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
mipmap = reloc->robj; |
} |
r = evergreen_cs_track_validate_texture(p, texture, mipmap, idx+1+(i*8)); |
if (r) |
return r; |
ib[idx+1+(i*8)+2] += toffset; |
ib[idx+1+(i*8)+3] += moffset; |
break; |
case SQ_TEX_VTX_VALID_BUFFER: |
{ |
uint64_t offset64; |
/* vtx base */ |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad SET_RESOURCE (vtx)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+1+(i*8)+0); |
size = radeon_get_ib_value(p, idx+1+(i*8)+1); |
if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) { |
/* force size to size of the buffer */ |
dev_warn(p->dev, "vbo resource seems too big for the bo\n"); |
ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj) - 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); |
break; |
} |
case SQ_TEX_VTX_INVALID_TEXTURE: |
case SQ_TEX_VTX_INVALID_BUFFER: |
default: |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
} |
break; |
case PACKET3_SET_ALU_CONST: |
/* XXX fix me ALU const buffers only */ |
break; |
case PACKET3_SET_BOOL_CONST: |
start_reg = (idx_value << 2) + PACKET3_SET_BOOL_CONST_START; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_BOOL_CONST_START) || |
(start_reg >= PACKET3_SET_BOOL_CONST_END) || |
(end_reg >= PACKET3_SET_BOOL_CONST_END)) { |
DRM_ERROR("bad SET_BOOL_CONST\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_SET_LOOP_CONST: |
start_reg = (idx_value << 2) + PACKET3_SET_LOOP_CONST_START; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_LOOP_CONST_START) || |
(start_reg >= PACKET3_SET_LOOP_CONST_END) || |
(end_reg >= PACKET3_SET_LOOP_CONST_END)) { |
DRM_ERROR("bad SET_LOOP_CONST\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_SET_CTL_CONST: |
start_reg = (idx_value << 2) + PACKET3_SET_CTL_CONST_START; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_CTL_CONST_START) || |
(start_reg >= PACKET3_SET_CTL_CONST_END) || |
(end_reg >= PACKET3_SET_CTL_CONST_END)) { |
DRM_ERROR("bad SET_CTL_CONST\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_SET_SAMPLER: |
if (pkt->count % 3) { |
DRM_ERROR("bad SET_SAMPLER\n"); |
return -EINVAL; |
} |
start_reg = (idx_value << 2) + PACKET3_SET_SAMPLER_START; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_SAMPLER_START) || |
(start_reg >= PACKET3_SET_SAMPLER_END) || |
(end_reg >= PACKET3_SET_SAMPLER_END)) { |
DRM_ERROR("bad SET_SAMPLER\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_STRMOUT_BUFFER_UPDATE: |
if (pkt->count != 4) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (invalid count)\n"); |
return -EINVAL; |
} |
/* Updating memory at DST_ADDRESS. */ |
if (idx_value & 0x1) { |
u64 offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing dst reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+1); |
offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE dst bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+1] = offset; |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
} |
/* Reading data from SRC_ADDRESS. */ |
if (((idx_value >> 1) & 0x3) == 2) { |
u64 offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing src reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+3); |
offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE src bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+3] = offset; |
ib[idx+4] = upper_32_bits(offset) & 0xff; |
} |
break; |
case PACKET3_MEM_WRITE: |
{ |
u64 offset; |
if (pkt->count != 3) { |
DRM_ERROR("bad MEM_WRITE (invalid count)\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad MEM_WRITE (missing reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+0); |
offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL; |
if (offset & 0x7) { |
DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n"); |
return -EINVAL; |
} |
if ((offset + 8) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n", |
offset + 8, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+0] = offset; |
ib[idx+1] = upper_32_bits(offset) & 0xff; |
break; |
} |
case PACKET3_COPY_DW: |
if (pkt->count != 4) { |
DRM_ERROR("bad COPY_DW (invalid count)\n"); |
return -EINVAL; |
} |
if (idx_value & 0x1) { |
u64 offset; |
/* SRC is memory. */ |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad COPY_DW (missing src reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+1); |
offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad COPY_DW src bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+1] = offset; |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
} else { |
/* SRC is a reg. */ |
reg = radeon_get_ib_value(p, idx+1) << 2; |
if (!evergreen_is_safe_reg(p, reg, idx+1)) |
return -EINVAL; |
} |
if (idx_value & 0x2) { |
u64 offset; |
/* DST is memory. */ |
r = radeon_cs_packet_next_reloc(p, &reloc, 0); |
if (r) { |
DRM_ERROR("bad COPY_DW (missing dst reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+3); |
offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad COPY_DW dst bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+3] = offset; |
ib[idx+4] = upper_32_bits(offset) & 0xff; |
} else { |
/* DST is a reg. */ |
reg = radeon_get_ib_value(p, idx+3) << 2; |
if (!evergreen_is_safe_reg(p, reg, idx+3)) |
return -EINVAL; |
} |
break; |
case PACKET3_NOP: |
break; |
default: |
DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); |
return -EINVAL; |
} |
return 0; |
} |
int evergreen_cs_parse(struct radeon_cs_parser *p) |
{ |
struct radeon_cs_packet pkt; |
struct evergreen_cs_track *track; |
u32 tmp; |
int r; |
if (p->track == NULL) { |
/* initialize tracker, we are in kms */ |
track = kzalloc(sizeof(*track), GFP_KERNEL); |
if (track == NULL) |
return -ENOMEM; |
evergreen_cs_track_init(track); |
if (p->rdev->family >= CHIP_CAYMAN) |
tmp = p->rdev->config.cayman.tile_config; |
else |
tmp = p->rdev->config.evergreen.tile_config; |
switch (tmp & 0xf) { |
case 0: |
track->npipes = 1; |
break; |
case 1: |
default: |
track->npipes = 2; |
break; |
case 2: |
track->npipes = 4; |
break; |
case 3: |
track->npipes = 8; |
break; |
} |
switch ((tmp & 0xf0) >> 4) { |
case 0: |
track->nbanks = 4; |
break; |
case 1: |
default: |
track->nbanks = 8; |
break; |
case 2: |
track->nbanks = 16; |
break; |
} |
switch ((tmp & 0xf00) >> 8) { |
case 0: |
track->group_size = 256; |
break; |
case 1: |
default: |
track->group_size = 512; |
break; |
} |
switch ((tmp & 0xf000) >> 12) { |
case 0: |
track->row_size = 1; |
break; |
case 1: |
default: |
track->row_size = 2; |
break; |
case 2: |
track->row_size = 4; |
break; |
} |
p->track = track; |
} |
do { |
r = radeon_cs_packet_parse(p, &pkt, p->idx); |
if (r) { |
kfree(p->track); |
p->track = NULL; |
return r; |
} |
p->idx += pkt.count + 2; |
switch (pkt.type) { |
case RADEON_PACKET_TYPE0: |
r = evergreen_cs_parse_packet0(p, &pkt); |
break; |
case RADEON_PACKET_TYPE2: |
break; |
case RADEON_PACKET_TYPE3: |
r = evergreen_packet3_check(p, &pkt); |
break; |
default: |
DRM_ERROR("Unknown packet type %d !\n", pkt.type); |
kfree(p->track); |
p->track = NULL; |
return -EINVAL; |
} |
if (r) { |
kfree(p->track); |
p->track = NULL; |
return r; |
} |
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); |
#if 0 |
for (r = 0; r < p->ib.length_dw; r++) { |
printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]); |
mdelay(1); |
} |
#endif |
kfree(p->track); |
p->track = NULL; |
return 0; |
} |
/** |
* evergreen_dma_cs_parse() - parse the DMA IB |
* @p: parser structure holding parsing context. |
* |
* Parses the DMA IB from the CS ioctl and updates |
* the GPU addresses based on the reloc information and |
* checks for errors. (Evergreen-Cayman) |
* Returns 0 for success and an error on failure. |
**/ |
int evergreen_dma_cs_parse(struct radeon_cs_parser *p) |
{ |
struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; |
struct radeon_cs_reloc *src_reloc, *dst_reloc, *dst2_reloc; |
u32 header, cmd, count, sub_cmd; |
volatile u32 *ib = p->ib.ptr; |
u32 idx; |
u64 src_offset, dst_offset, dst2_offset; |
int r; |
do { |
if (p->idx >= ib_chunk->length_dw) { |
DRM_ERROR("Can not parse packet at %d after CS end %d !\n", |
p->idx, ib_chunk->length_dw); |
return -EINVAL; |
} |
idx = p->idx; |
header = radeon_get_ib_value(p, idx); |
cmd = GET_DMA_CMD(header); |
count = GET_DMA_COUNT(header); |
sub_cmd = GET_DMA_SUB_CMD(header); |
switch (cmd) { |
case DMA_PACKET_WRITE: |
r = r600_dma_cs_next_reloc(p, &dst_reloc); |
if (r) { |
DRM_ERROR("bad DMA_PACKET_WRITE\n"); |
return -EINVAL; |
} |
switch (sub_cmd) { |
/* tiled */ |
case 8: |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset <<= 8; |
ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8); |
p->idx += count + 7; |
break; |
/* linear */ |
case 0: |
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->gpu_offset & 0xfffffffc); |
ib[idx+2] += upper_32_bits(dst_reloc->gpu_offset) & 0xff; |
p->idx += count + 3; |
break; |
default: |
DRM_ERROR("bad DMA_PACKET_WRITE [%6d] 0x%08x sub cmd is not 0 or 8\n", idx, header); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA write buffer too small (%llu %lu)\n", |
dst_offset, radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
break; |
case DMA_PACKET_COPY: |
r = r600_dma_cs_next_reloc(p, &src_reloc); |
if (r) { |
DRM_ERROR("bad DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
r = r600_dma_cs_next_reloc(p, &dst_reloc); |
if (r) { |
DRM_ERROR("bad DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
switch (sub_cmd) { |
/* Copy L2L, DW aligned */ |
case 0x00: |
/* L2L, dw */ |
src_offset = radeon_get_ib_value(p, idx+2); |
src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32; |
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
dev_warn(p->dev, "DMA L2L, dw src buffer too small (%llu %lu)\n", |
src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA L2L, dw dst buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
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 */ |
case 0x08: |
/* detile bit */ |
if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) { |
/* tiled src, linear dst */ |
src_offset = radeon_get_ib_value(p, idx+1); |
src_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->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->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->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", |
src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, dst buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
p->idx += 9; |
break; |
/* Copy L2L, byte aligned */ |
case 0x40: |
/* L2L, byte */ |
src_offset = radeon_get_ib_value(p, idx+2); |
src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32; |
if ((src_offset + count) > radeon_bo_size(src_reloc->robj)) { |
dev_warn(p->dev, "DMA L2L, byte src buffer too small (%llu %lu)\n", |
src_offset + count, radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + count) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA L2L, byte dst buffer too small (%llu %lu)\n", |
dst_offset + count, radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
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 */ |
case 0x41: |
/* L2L, partial */ |
if (p->family < CHIP_CAYMAN) { |
DRM_ERROR("L2L Partial is cayman only !\n"); |
return -EINVAL; |
} |
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; |
/* Copy L2L, DW aligned, broadcast */ |
case 0x44: |
/* L2L, dw, broadcast */ |
r = r600_dma_cs_next_reloc(p, &dst2_reloc); |
if (r) { |
DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
dst2_offset = radeon_get_ib_value(p, idx+2); |
dst2_offset |= ((u64)(radeon_get_ib_value(p, idx+5) & 0xff)) << 32; |
src_offset = radeon_get_ib_value(p, idx+3); |
src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32; |
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
dev_warn(p->dev, "DMA L2L, dw, broadcast src buffer too small (%llu %lu)\n", |
src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA L2L, dw, broadcast dst buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) { |
dev_warn(p->dev, "DMA L2L, dw, broadcast dst2 buffer too small (%llu %lu)\n", |
dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj)); |
return -EINVAL; |
} |
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 */ |
case 0x48: |
if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) { |
DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
r = r600_dma_cs_next_reloc(p, &dst2_reloc); |
if (r) { |
DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset <<= 8; |
dst2_offset = radeon_get_ib_value(p, idx+2); |
dst2_offset <<= 8; |
src_offset = radeon_get_ib_value(p, idx+8); |
src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32; |
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, frame to fields src buffer too small (%llu %lu)\n", |
src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, frame to fields buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, frame to fields buffer too small (%llu %lu)\n", |
dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj)); |
return -EINVAL; |
} |
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 */ |
case 0x49: |
/* L2T, T2L partial */ |
if (p->family < CHIP_CAYMAN) { |
DRM_ERROR("L2T, T2L Partial is cayman only !\n"); |
return -EINVAL; |
} |
/* detile bit */ |
if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) { |
/* tiled src, linear dst */ |
ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8); |
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->gpu_offset & 0xfffffffc); |
ib[idx+8] += upper_32_bits(src_reloc->gpu_offset) & 0xff; |
ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8); |
} |
p->idx += 12; |
break; |
/* Copy L2T broadcast */ |
case 0x4b: |
/* L2T, broadcast */ |
if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) { |
DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
r = r600_dma_cs_next_reloc(p, &dst2_reloc); |
if (r) { |
DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset <<= 8; |
dst2_offset = radeon_get_ib_value(p, idx+2); |
dst2_offset <<= 8; |
src_offset = radeon_get_ib_value(p, idx+8); |
src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32; |
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", |
src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, broadcast dst buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, broadcast dst2 buffer too small (%llu %lu)\n", |
dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj)); |
return -EINVAL; |
} |
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) */ |
case 0x4c: |
/* L2T, T2L */ |
/* detile bit */ |
if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) { |
/* tiled src, linear dst */ |
src_offset = radeon_get_ib_value(p, idx+1); |
src_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->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->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->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", |
src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, T2L dst buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
p->idx += 9; |
break; |
/* Copy T2T, partial (tile units) */ |
case 0x4d: |
/* T2T partial */ |
if (p->family < CHIP_CAYMAN) { |
DRM_ERROR("L2T, T2L Partial is cayman only !\n"); |
return -EINVAL; |
} |
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) */ |
case 0x4f: |
/* L2T, broadcast */ |
if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) { |
DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
r = r600_dma_cs_next_reloc(p, &dst2_reloc); |
if (r) { |
DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset <<= 8; |
dst2_offset = radeon_get_ib_value(p, idx+2); |
dst2_offset <<= 8; |
src_offset = radeon_get_ib_value(p, idx+8); |
src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32; |
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", |
src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, broadcast dst buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) { |
dev_warn(p->dev, "DMA L2T, broadcast dst2 buffer too small (%llu %lu)\n", |
dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj)); |
return -EINVAL; |
} |
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: |
DRM_ERROR("bad DMA_PACKET_COPY [%6d] 0x%08x invalid sub cmd\n", idx, header); |
return -EINVAL; |
} |
break; |
case DMA_PACKET_CONSTANT_FILL: |
r = r600_dma_cs_next_reloc(p, &dst_reloc); |
if (r) { |
DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n"); |
return -EINVAL; |
} |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16; |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n", |
dst_offset, radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
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: |
p->idx += 1; |
break; |
default: |
DRM_ERROR("Unknown packet type %d at %d !\n", cmd, idx); |
return -EINVAL; |
} |
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); |
#if 0 |
for (r = 0; r < p->ib->length_dw; r++) { |
printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]); |
mdelay(1); |
} |
#endif |
return 0; |
} |
/* vm parser */ |
static bool evergreen_vm_reg_valid(u32 reg) |
{ |
/* context regs are fine */ |
if (reg >= 0x28000) |
return true; |
/* check config regs */ |
switch (reg) { |
case WAIT_UNTIL: |
case GRBM_GFX_INDEX: |
case CP_STRMOUT_CNTL: |
case CP_COHER_CNTL: |
case CP_COHER_SIZE: |
case VGT_VTX_VECT_EJECT_REG: |
case VGT_CACHE_INVALIDATION: |
case VGT_GS_VERTEX_REUSE: |
case VGT_PRIMITIVE_TYPE: |
case VGT_INDEX_TYPE: |
case VGT_NUM_INDICES: |
case VGT_NUM_INSTANCES: |
case VGT_COMPUTE_DIM_X: |
case VGT_COMPUTE_DIM_Y: |
case VGT_COMPUTE_DIM_Z: |
case VGT_COMPUTE_START_X: |
case VGT_COMPUTE_START_Y: |
case VGT_COMPUTE_START_Z: |
case VGT_COMPUTE_INDEX: |
case VGT_COMPUTE_THREAD_GROUP_SIZE: |
case VGT_HS_OFFCHIP_PARAM: |
case PA_CL_ENHANCE: |
case PA_SU_LINE_STIPPLE_VALUE: |
case PA_SC_LINE_STIPPLE_STATE: |
case PA_SC_ENHANCE: |
case SQ_DYN_GPR_CNTL_PS_FLUSH_REQ: |
case SQ_DYN_GPR_SIMD_LOCK_EN: |
case SQ_CONFIG: |
case SQ_GPR_RESOURCE_MGMT_1: |
case SQ_GLOBAL_GPR_RESOURCE_MGMT_1: |
case SQ_GLOBAL_GPR_RESOURCE_MGMT_2: |
case SQ_CONST_MEM_BASE: |
case SQ_STATIC_THREAD_MGMT_1: |
case SQ_STATIC_THREAD_MGMT_2: |
case SQ_STATIC_THREAD_MGMT_3: |
case SPI_CONFIG_CNTL: |
case SPI_CONFIG_CNTL_1: |
case TA_CNTL_AUX: |
case DB_DEBUG: |
case DB_DEBUG2: |
case DB_DEBUG3: |
case DB_DEBUG4: |
case DB_WATERMARKS: |
case TD_PS_BORDER_COLOR_INDEX: |
case TD_PS_BORDER_COLOR_RED: |
case TD_PS_BORDER_COLOR_GREEN: |
case TD_PS_BORDER_COLOR_BLUE: |
case TD_PS_BORDER_COLOR_ALPHA: |
case TD_VS_BORDER_COLOR_INDEX: |
case TD_VS_BORDER_COLOR_RED: |
case TD_VS_BORDER_COLOR_GREEN: |
case TD_VS_BORDER_COLOR_BLUE: |
case TD_VS_BORDER_COLOR_ALPHA: |
case TD_GS_BORDER_COLOR_INDEX: |
case TD_GS_BORDER_COLOR_RED: |
case TD_GS_BORDER_COLOR_GREEN: |
case TD_GS_BORDER_COLOR_BLUE: |
case TD_GS_BORDER_COLOR_ALPHA: |
case TD_HS_BORDER_COLOR_INDEX: |
case TD_HS_BORDER_COLOR_RED: |
case TD_HS_BORDER_COLOR_GREEN: |
case TD_HS_BORDER_COLOR_BLUE: |
case TD_HS_BORDER_COLOR_ALPHA: |
case TD_LS_BORDER_COLOR_INDEX: |
case TD_LS_BORDER_COLOR_RED: |
case TD_LS_BORDER_COLOR_GREEN: |
case TD_LS_BORDER_COLOR_BLUE: |
case TD_LS_BORDER_COLOR_ALPHA: |
case TD_CS_BORDER_COLOR_INDEX: |
case TD_CS_BORDER_COLOR_RED: |
case TD_CS_BORDER_COLOR_GREEN: |
case TD_CS_BORDER_COLOR_BLUE: |
case TD_CS_BORDER_COLOR_ALPHA: |
case SQ_ESGS_RING_SIZE: |
case SQ_GSVS_RING_SIZE: |
case SQ_ESTMP_RING_SIZE: |
case SQ_GSTMP_RING_SIZE: |
case SQ_HSTMP_RING_SIZE: |
case SQ_LSTMP_RING_SIZE: |
case SQ_PSTMP_RING_SIZE: |
case SQ_VSTMP_RING_SIZE: |
case SQ_ESGS_RING_ITEMSIZE: |
case SQ_ESTMP_RING_ITEMSIZE: |
case SQ_GSTMP_RING_ITEMSIZE: |
case SQ_GSVS_RING_ITEMSIZE: |
case SQ_GS_VERT_ITEMSIZE: |
case SQ_GS_VERT_ITEMSIZE_1: |
case SQ_GS_VERT_ITEMSIZE_2: |
case SQ_GS_VERT_ITEMSIZE_3: |
case SQ_GSVS_RING_OFFSET_1: |
case SQ_GSVS_RING_OFFSET_2: |
case SQ_GSVS_RING_OFFSET_3: |
case SQ_HSTMP_RING_ITEMSIZE: |
case SQ_LSTMP_RING_ITEMSIZE: |
case SQ_PSTMP_RING_ITEMSIZE: |
case SQ_VSTMP_RING_ITEMSIZE: |
case VGT_TF_RING_SIZE: |
case SQ_ESGS_RING_BASE: |
case SQ_GSVS_RING_BASE: |
case SQ_ESTMP_RING_BASE: |
case SQ_GSTMP_RING_BASE: |
case SQ_HSTMP_RING_BASE: |
case SQ_LSTMP_RING_BASE: |
case SQ_PSTMP_RING_BASE: |
case SQ_VSTMP_RING_BASE: |
case CAYMAN_VGT_OFFCHIP_LDS_BASE: |
case CAYMAN_SQ_EX_ALLOC_TABLE_SLOTS: |
return true; |
default: |
DRM_ERROR("Invalid register 0x%x in CS\n", reg); |
return false; |
} |
} |
static int evergreen_vm_packet3_check(struct radeon_device *rdev, |
u32 *ib, struct radeon_cs_packet *pkt) |
{ |
u32 idx = pkt->idx + 1; |
u32 idx_value = ib[idx]; |
u32 start_reg, end_reg, reg, i; |
u32 command, info; |
switch (pkt->opcode) { |
case PACKET3_NOP: |
case PACKET3_SET_BASE: |
case PACKET3_CLEAR_STATE: |
case PACKET3_INDEX_BUFFER_SIZE: |
case PACKET3_DISPATCH_DIRECT: |
case PACKET3_DISPATCH_INDIRECT: |
case PACKET3_MODE_CONTROL: |
case PACKET3_SET_PREDICATION: |
case PACKET3_COND_EXEC: |
case PACKET3_PRED_EXEC: |
case PACKET3_DRAW_INDIRECT: |
case PACKET3_DRAW_INDEX_INDIRECT: |
case PACKET3_INDEX_BASE: |
case PACKET3_DRAW_INDEX_2: |
case PACKET3_CONTEXT_CONTROL: |
case PACKET3_DRAW_INDEX_OFFSET: |
case PACKET3_INDEX_TYPE: |
case PACKET3_DRAW_INDEX: |
case PACKET3_DRAW_INDEX_AUTO: |
case PACKET3_DRAW_INDEX_IMMD: |
case PACKET3_NUM_INSTANCES: |
case PACKET3_DRAW_INDEX_MULTI_AUTO: |
case PACKET3_STRMOUT_BUFFER_UPDATE: |
case PACKET3_DRAW_INDEX_OFFSET_2: |
case PACKET3_DRAW_INDEX_MULTI_ELEMENT: |
case PACKET3_MPEG_INDEX: |
case PACKET3_WAIT_REG_MEM: |
case PACKET3_MEM_WRITE: |
case PACKET3_SURFACE_SYNC: |
case PACKET3_EVENT_WRITE: |
case PACKET3_EVENT_WRITE_EOP: |
case PACKET3_EVENT_WRITE_EOS: |
case PACKET3_SET_CONTEXT_REG: |
case PACKET3_SET_BOOL_CONST: |
case PACKET3_SET_LOOP_CONST: |
case PACKET3_SET_RESOURCE: |
case PACKET3_SET_SAMPLER: |
case PACKET3_SET_CTL_CONST: |
case PACKET3_SET_RESOURCE_OFFSET: |
case PACKET3_SET_CONTEXT_REG_INDIRECT: |
case PACKET3_SET_RESOURCE_INDIRECT: |
case CAYMAN_PACKET3_DEALLOC_STATE: |
break; |
case PACKET3_COND_WRITE: |
if (idx_value & 0x100) { |
reg = ib[idx + 5] * 4; |
if (!evergreen_vm_reg_valid(reg)) |
return -EINVAL; |
} |
break; |
case PACKET3_COPY_DW: |
if (idx_value & 0x2) { |
reg = ib[idx + 3] * 4; |
if (!evergreen_vm_reg_valid(reg)) |
return -EINVAL; |
} |
break; |
case PACKET3_SET_CONFIG_REG: |
start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_CONFIG_REG_START) || |
(start_reg >= PACKET3_SET_CONFIG_REG_END) || |
(end_reg >= PACKET3_SET_CONFIG_REG_END)) { |
DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n"); |
return -EINVAL; |
} |
for (i = 0; i < pkt->count; i++) { |
reg = start_reg + (4 * i); |
if (!evergreen_vm_reg_valid(reg)) |
return -EINVAL; |
} |
break; |
case PACKET3_CP_DMA: |
command = ib[idx + 4]; |
info = ib[idx + 1]; |
if ((((info & 0x60000000) >> 29) != 0) || /* src = GDS or DATA */ |
(((info & 0x00300000) >> 20) != 0) || /* dst = GDS */ |
((((info & 0x00300000) >> 20) == 0) && |
(command & PACKET3_CP_DMA_CMD_DAS)) || /* dst = register */ |
((((info & 0x60000000) >> 29) == 0) && |
(command & PACKET3_CP_DMA_CMD_SAS))) { /* src = register */ |
/* non mem to mem copies requires dw aligned count */ |
if ((command & 0x1fffff) % 4) { |
DRM_ERROR("CP DMA command requires dw count alignment\n"); |
return -EINVAL; |
} |
} |
if (command & PACKET3_CP_DMA_CMD_SAS) { |
/* src address space is register */ |
if (((info & 0x60000000) >> 29) == 0) { |
start_reg = idx_value << 2; |
if (command & PACKET3_CP_DMA_CMD_SAIC) { |
reg = start_reg; |
if (!evergreen_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad SRC register\n"); |
return -EINVAL; |
} |
} else { |
for (i = 0; i < (command & 0x1fffff); i++) { |
reg = start_reg + (4 * i); |
if (!evergreen_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad SRC register\n"); |
return -EINVAL; |
} |
} |
} |
} |
} |
if (command & PACKET3_CP_DMA_CMD_DAS) { |
/* dst address space is register */ |
if (((info & 0x00300000) >> 20) == 0) { |
start_reg = ib[idx + 2]; |
if (command & PACKET3_CP_DMA_CMD_DAIC) { |
reg = start_reg; |
if (!evergreen_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad DST register\n"); |
return -EINVAL; |
} |
} else { |
for (i = 0; i < (command & 0x1fffff); i++) { |
reg = start_reg + (4 * i); |
if (!evergreen_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad DST register\n"); |
return -EINVAL; |
} |
} |
} |
} |
} |
break; |
default: |
return -EINVAL; |
} |
return 0; |
} |
int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
int ret = 0; |
u32 idx = 0; |
struct radeon_cs_packet pkt; |
do { |
pkt.idx = idx; |
pkt.type = RADEON_CP_PACKET_GET_TYPE(ib->ptr[idx]); |
pkt.count = RADEON_CP_PACKET_GET_COUNT(ib->ptr[idx]); |
pkt.one_reg_wr = 0; |
switch (pkt.type) { |
case RADEON_PACKET_TYPE0: |
dev_err(rdev->dev, "Packet0 not allowed!\n"); |
ret = -EINVAL; |
break; |
case RADEON_PACKET_TYPE2: |
idx += 1; |
break; |
case RADEON_PACKET_TYPE3: |
pkt.opcode = RADEON_CP_PACKET3_GET_OPCODE(ib->ptr[idx]); |
ret = evergreen_vm_packet3_check(rdev, ib->ptr, &pkt); |
idx += pkt.count + 2; |
break; |
default: |
dev_err(rdev->dev, "Unknown packet type %d !\n", pkt.type); |
ret = -EINVAL; |
break; |
} |
if (ret) |
break; |
} while (idx < ib->length_dw); |
return ret; |
} |
/** |
* evergreen_dma_ib_parse() - parse the DMA IB for VM |
* @rdev: radeon_device pointer |
* @ib: radeon_ib pointer |
* |
* Parses the DMA IB from the VM CS ioctl |
* checks for errors. (Cayman-SI) |
* Returns 0 for success and an error on failure. |
**/ |
int evergreen_dma_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
u32 idx = 0; |
u32 header, cmd, count, sub_cmd; |
do { |
header = ib->ptr[idx]; |
cmd = GET_DMA_CMD(header); |
count = GET_DMA_COUNT(header); |
sub_cmd = GET_DMA_SUB_CMD(header); |
switch (cmd) { |
case DMA_PACKET_WRITE: |
switch (sub_cmd) { |
/* tiled */ |
case 8: |
idx += count + 7; |
break; |
/* linear */ |
case 0: |
idx += count + 3; |
break; |
default: |
DRM_ERROR("bad DMA_PACKET_WRITE [%6d] 0x%08x sub cmd is not 0 or 8\n", idx, ib->ptr[idx]); |
return -EINVAL; |
} |
break; |
case DMA_PACKET_COPY: |
switch (sub_cmd) { |
/* Copy L2L, DW aligned */ |
case 0x00: |
idx += 5; |
break; |
/* Copy L2T/T2L */ |
case 0x08: |
idx += 9; |
break; |
/* Copy L2L, byte aligned */ |
case 0x40: |
idx += 5; |
break; |
/* Copy L2L, partial */ |
case 0x41: |
idx += 9; |
break; |
/* Copy L2L, DW aligned, broadcast */ |
case 0x44: |
idx += 7; |
break; |
/* Copy L2T Frame to Field */ |
case 0x48: |
idx += 10; |
break; |
/* Copy L2T/T2L, partial */ |
case 0x49: |
idx += 12; |
break; |
/* Copy L2T broadcast */ |
case 0x4b: |
idx += 10; |
break; |
/* Copy L2T/T2L (tile units) */ |
case 0x4c: |
idx += 9; |
break; |
/* Copy T2T, partial (tile units) */ |
case 0x4d: |
idx += 13; |
break; |
/* Copy L2T broadcast (tile units) */ |
case 0x4f: |
idx += 10; |
break; |
default: |
DRM_ERROR("bad DMA_PACKET_COPY [%6d] 0x%08x invalid sub cmd\n", idx, ib->ptr[idx]); |
return -EINVAL; |
} |
break; |
case DMA_PACKET_CONSTANT_FILL: |
idx += 4; |
break; |
case DMA_PACKET_NOP: |
idx += 1; |
break; |
default: |
DRM_ERROR("Unknown packet type %d at %d !\n", cmd, idx); |
return -EINVAL; |
} |
} while (idx < ib->length_dw); |
return 0; |
} |
/drivers/video/drm/radeon/evergreen_dma.c |
---|
0,0 → 1,184 |
/* |
* Copyright 2010 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "radeon_asic.h" |
#include "evergreend.h" |
u32 evergreen_gpu_check_soft_reset(struct radeon_device *rdev); |
/** |
* evergreen_dma_fence_ring_emit - emit a fence on the DMA ring |
* |
* @rdev: radeon_device pointer |
* @fence: radeon fence object |
* |
* Add a DMA fence packet to the ring to write |
* the fence seq number and DMA trap packet to generate |
* an interrupt if needed (evergreen-SI). |
*/ |
void evergreen_dma_fence_ring_emit(struct radeon_device *rdev, |
struct radeon_fence *fence) |
{ |
struct radeon_ring *ring = &rdev->ring[fence->ring]; |
u64 addr = rdev->fence_drv[fence->ring].gpu_addr; |
/* write the fence */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0)); |
radeon_ring_write(ring, addr & 0xfffffffc); |
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff)); |
radeon_ring_write(ring, fence->seq); |
/* generate an interrupt */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0)); |
/* flush HDP */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2)); |
radeon_ring_write(ring, 1); |
} |
/** |
* evergreen_dma_ring_ib_execute - schedule an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to schedule |
* |
* Schedule an IB in the DMA ring (evergreen). |
*/ |
void evergreen_dma_ring_ib_execute(struct radeon_device *rdev, |
struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
if (rdev->wb.enabled) { |
u32 next_rptr = ring->wptr + 4; |
while ((next_rptr & 7) != 5) |
next_rptr++; |
next_rptr += 3; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 1)); |
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff); |
radeon_ring_write(ring, next_rptr); |
} |
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring. |
* Pad as necessary with NOPs. |
*/ |
while ((ring->wptr & 7) != 5) |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0)); |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_INDIRECT_BUFFER, 0, 0)); |
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0)); |
radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF)); |
} |
/** |
* evergreen_copy_dma - copy pages using the 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 DMA engine (evergreen-cayman). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int evergreen_copy_dma(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.dma_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_dw, cur_size_in_dw; |
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_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; |
num_loops = DIV_ROUND_UP(size_in_dw, 0xfffff); |
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11); |
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_dw = size_in_dw; |
if (cur_size_in_dw > 0xFFFFF) |
cur_size_in_dw = 0xFFFFF; |
size_in_dw -= cur_size_in_dw; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, cur_size_in_dw)); |
radeon_ring_write(ring, dst_offset & 0xfffffffc); |
radeon_ring_write(ring, src_offset & 0xfffffffc); |
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_dw * 4; |
dst_offset += cur_size_in_dw * 4; |
} |
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, false); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
/** |
* evergreen_dma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up. |
* Returns true if the engine appears to be locked up, false if not. |
*/ |
bool evergreen_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
u32 reset_mask = evergreen_gpu_check_soft_reset(rdev); |
if (!(reset_mask & RADEON_RESET_DMA)) { |
radeon_ring_lockup_update(rdev, ring); |
return false; |
} |
return radeon_ring_test_lockup(rdev, ring); |
} |
/drivers/video/drm/radeon/evergreen_hdmi.c |
---|
32,6 → 32,12 |
#include "evergreend.h" |
#include "atom.h" |
extern void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder); |
extern void dce6_afmt_write_sad_regs(struct drm_encoder *encoder); |
extern void dce6_afmt_select_pin(struct drm_encoder *encoder); |
extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, |
struct drm_display_mode *mode); |
/* |
* update the N and CTS parameters for a given pixel clock rate |
*/ |
54,6 → 60,83 |
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; |
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(connector), &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 evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder) |
{ |
struct radeon_device *rdev = encoder->dev->dev_private; |
78,9 → 161,11 |
}; |
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) { |
DRM_ERROR("Couldn't find encoder's connector\n"); |
87,8 → 172,8 |
return; |
} |
sad_count = drm_edid_to_sad(radeon_connector->edid, &sads); |
if (sad_count < 0) { |
sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); |
if (sad_count <= 0) { |
DRM_ERROR("Couldn't read SADs: %d\n", sad_count); |
return; |
} |
96,6 → 181,8 |
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++) { |
102,14 → 189,22 |
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) |
value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq); |
stereo_freqs |= sad->freq; |
else |
break; |
} |
} |
value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); |
WREG32(eld_reg_to_type[i][0], value); |
} |
128,15 → 223,8 |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
uint32_t offset = dig->afmt->offset; |
uint8_t *frame = buffer + 3; |
uint8_t *header = buffer; |
/* Our header values (type, version, length) should be alright, Intel |
* is using the same. Checksum function also seems to be OK, it works |
* fine for audio infoframe. However calculated value is always lower |
* by 2 in comparison to fglrx. It breaks displaying anything in case |
* of TVs that strictly check the checksum. Hack it manually here to |
* workaround this issue. */ |
frame[0x0] += 2; |
WREG32(AFMT_AVI_INFO0 + offset, |
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); |
WREG32(AFMT_AVI_INFO1 + offset, |
144,9 → 232,58 |
WREG32(AFMT_AVI_INFO2 + offset, |
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); |
WREG32(AFMT_AVI_INFO3 + offset, |
frame[0xC] | (frame[0xD] << 8)); |
frame[0xC] | (frame[0xD] << 8) | (header[1] << 24)); |
} |
static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
u32 base_rate = 24000; |
u32 max_ratio = clock / base_rate; |
u32 dto_phase; |
u32 dto_modulo = clock; |
u32 wallclock_ratio; |
u32 dto_cntl; |
if (!dig || !dig->afmt) |
return; |
if (ASIC_IS_DCE6(rdev)) { |
dto_phase = 24 * 1000; |
} else { |
if (max_ratio >= 8) { |
dto_phase = 192 * 1000; |
wallclock_ratio = 3; |
} else if (max_ratio >= 4) { |
dto_phase = 96 * 1000; |
wallclock_ratio = 2; |
} else if (max_ratio >= 2) { |
dto_phase = 48 * 1000; |
wallclock_ratio = 1; |
} else { |
dto_phase = 24 * 1000; |
wallclock_ratio = 0; |
} |
dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; |
dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); |
WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); |
} |
/* XXX two dtos; generally use dto0 for hdmi */ |
/* Express [24MHz / target pixel clock] as an exact rational |
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE |
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator |
*/ |
WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); |
WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); |
WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo); |
} |
/* |
* update the info frames with the data from the current display mode |
*/ |
156,34 → 293,72 |
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; |
/* Silent, r600_hdmi_enable will raise WARN for us */ |
if (!dig->afmt->enabled) |
return; |
offset = dig->afmt->offset; |
// r600_audio_set_clock(encoder, mode->clock); |
/* 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, |
HDMI_NULL_SEND); /* send null packets when required */ |
WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000); |
WREG32(HDMI_AUDIO_PACKET_CONTROL + offset, |
HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */ |
HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ |
val = RREG32(HDMI_CONTROL + offset); |
val &= ~HDMI_DEEP_COLOR_ENABLE; |
val &= ~HDMI_DEEP_COLOR_DEPTH_MASK; |
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 */ |
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_ACR_PACKET_CONTROL + offset, |
HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ |
HDMI_ACR_SOURCE); /* select SW CTS value */ |
WREG32(HDMI_CONTROL + offset, val); |
WREG32(HDMI_VBI_PACKET_CONTROL + offset, |
HDMI_NULL_SEND | /* send null packets when required */ |
191,8 → 366,6 |
HDMI_GC_CONT); /* send general control packets every frame */ |
WREG32(HDMI_INFOFRAME_CONTROL0 + offset, |
HDMI_AVI_INFO_SEND | /* enable AVI info frames */ |
HDMI_AVI_INFO_CONT | /* send AVI info frames every frame/field */ |
HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ |
HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */ |
200,11 → 373,63 |
AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ |
WREG32(HDMI_INFOFRAME_CONTROL1 + offset, |
HDMI_AVI_INFO_LINE(2) | /* anything other than 0 */ |
HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */ |
WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */ |
WREG32(HDMI_AUDIO_PACKET_CONTROL + offset, |
HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */ |
HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ |
WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, |
AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ |
/* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */ |
if (bpc > 8) |
WREG32(HDMI_ACR_PACKET_CONTROL + offset, |
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ |
else |
WREG32(HDMI_ACR_PACKET_CONTROL + offset, |
HDMI_ACR_SOURCE | /* select SW CTS value */ |
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ |
evergreen_hdmi_update_ACR(encoder, mode->clock); |
WREG32(AFMT_60958_0 + offset, |
AFMT_60958_CS_CHANNEL_NUMBER_L(1)); |
WREG32(AFMT_60958_1 + offset, |
AFMT_60958_CS_CHANNEL_NUMBER_R(2)); |
WREG32(AFMT_60958_2 + offset, |
AFMT_60958_CS_CHANNEL_NUMBER_2(3) | |
AFMT_60958_CS_CHANNEL_NUMBER_3(4) | |
AFMT_60958_CS_CHANNEL_NUMBER_4(5) | |
AFMT_60958_CS_CHANNEL_NUMBER_5(6) | |
AFMT_60958_CS_CHANNEL_NUMBER_6(7) | |
AFMT_60958_CS_CHANNEL_NUMBER_7(8)); |
if (ASIC_IS_DCE6(rdev)) { |
dce6_afmt_write_speaker_allocation(encoder); |
} else { |
dce4_afmt_write_speaker_allocation(encoder); |
} |
WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset, |
AFMT_AUDIO_CHANNEL_ENABLE(0xff)); |
/* fglrx sets 0x40 in 0x5f80 here */ |
if (ASIC_IS_DCE6(rdev)) { |
dce6_afmt_select_pin(encoder); |
dce6_afmt_write_sad_regs(encoder); |
dce6_afmt_write_latency_fields(encoder, mode); |
} else { |
evergreen_hdmi_write_sad_regs(encoder); |
dce4_afmt_write_latency_fields(encoder, mode); |
} |
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); |
if (err < 0) { |
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); |
218,11 → 443,47 |
} |
evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); |
evergreen_hdmi_update_ACR(encoder, mode->clock); |
WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset, |
HDMI_AVI_INFO_SEND | /* enable AVI info frames */ |
HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */ |
WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset, |
HDMI_AVI_INFO_LINE(2), /* anything other than 0 */ |
~HDMI_AVI_INFO_LINE_MASK); |
WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset, |
AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */ |
/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ |
WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF); |
WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF); |
WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001); |
WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); |
/* 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 radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
if (!dig || !dig->afmt) |
return; |
/* Silent, r600_hdmi_enable will raise WARN for us */ |
if (enable && dig->afmt->enabled) |
return; |
if (!enable && !dig->afmt->enabled) |
return; |
dig->afmt->enabled = enable; |
DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", |
enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id); |
} |
/drivers/video/drm/radeon/evergreen_reg.h |
---|
24,7 → 24,17 |
#ifndef __EVERGREEN_REG_H__ |
#define __EVERGREEN_REG_H__ |
/* trinity */ |
#define TN_SMC_IND_INDEX_0 0x200 |
#define TN_SMC_IND_DATA_0 0x204 |
/* evergreen */ |
#define EVERGREEN_PIF_PHY0_INDEX 0x8 |
#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 |
#define EVERGREEN_D3VGA_CONTROL 0x3e0 |
40,6 → 50,9 |
#define EVERGREEN_AUDIO_PLL1_DIV 0x5b4 |
#define EVERGREEN_AUDIO_PLL1_UNK 0x5bc |
#define EVERGREEN_CG_IND_ADDR 0x8f8 |
#define EVERGREEN_CG_IND_DATA 0x8fc |
#define EVERGREEN_AUDIO_ENABLE 0x5e78 |
#define EVERGREEN_AUDIO_VENDOR_ID 0x5ec0 |
103,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 |
224,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 |
/drivers/video/drm/radeon/evergreen_reg_safe.h |
---|
0,0 → 1,514 |
static const unsigned evergreen_reg_safe_bm[2047] = { |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFF0F7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0xCFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFDDEFFF, 0xCF3FFFFF, 0xFFFFF40F, |
0xFEFFFFDF, 0xFFFFFFFF, 0xFFFFFFEF, 0xEFFFFFFF, |
0xFFFFF800, 0xFFFFFFFF, 0xFFFFFFFF, 0xBFFFFF07, |
0xFFFBF0FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFDF, 0xFFFFFFFF, 0xFFFF7FFE, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFB, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFDE, 0xFFFFFFFF, |
0xFFDF0FFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xC0000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFC3E4, 0xFFFFFFFF, 0x0000FFFF, 0x00000000, |
0x000CC000, 0x00000000, 0xFFD00000, 0x00000000, |
0x00000E00, 0x00000000, 0x00000000, 0x00000000, |
0x00000000, 0xC0000000, 0xFFFFF8FF, 0xFE07FF00, |
0x3CF1B003, 0xE39E7BCF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xF7020000, 0xDDD89CDD, 0x001FA3FD, 0xFFFFFFE0, |
0xBFFF0002, 0xEFC3DF87, 0x7BF0F7E1, 0x1EFC3DF8, |
0xDFBF0F7E, 0xFFFFF7EF, 0xFFFFFFFF, 0x00000000, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xCFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF8, |
}; |
/drivers/video/drm/radeon/evergreen_smc.h |
---|
0,0 → 1,67 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __EVERGREEN_SMC_H__ |
#define __EVERGREEN_SMC_H__ |
#include "rv770_smc.h" |
#pragma pack(push, 1) |
#define SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE 16 |
struct SMC_Evergreen_MCRegisterAddress |
{ |
uint16_t s0; |
uint16_t s1; |
}; |
typedef struct SMC_Evergreen_MCRegisterAddress SMC_Evergreen_MCRegisterAddress; |
struct SMC_Evergreen_MCRegisterSet |
{ |
uint32_t value[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE]; |
}; |
typedef struct SMC_Evergreen_MCRegisterSet SMC_Evergreen_MCRegisterSet; |
struct SMC_Evergreen_MCRegisters |
{ |
uint8_t last; |
uint8_t reserved[3]; |
SMC_Evergreen_MCRegisterAddress address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE]; |
SMC_Evergreen_MCRegisterSet data[5]; |
}; |
typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters; |
#define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100 |
#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters 0x8 |
#define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable 0xC |
#define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20 |
#pragma pack(pop) |
#endif |
/drivers/video/drm/radeon/evergreend.h |
---|
48,6 → 48,297 |
#define SUMO_GB_ADDR_CONFIG_GOLDEN 0x02010002 |
#define SUMO2_GB_ADDR_CONFIG_GOLDEN 0x02010002 |
/* pm registers */ |
#define SMC_MSG 0x20c |
#define HOST_SMC_MSG(x) ((x) << 0) |
#define HOST_SMC_MSG_MASK (0xff << 0) |
#define HOST_SMC_MSG_SHIFT 0 |
#define HOST_SMC_RESP(x) ((x) << 8) |
#define HOST_SMC_RESP_MASK (0xff << 8) |
#define HOST_SMC_RESP_SHIFT 8 |
#define SMC_HOST_MSG(x) ((x) << 16) |
#define SMC_HOST_MSG_MASK (0xff << 16) |
#define SMC_HOST_MSG_SHIFT 16 |
#define SMC_HOST_RESP(x) ((x) << 24) |
#define SMC_HOST_RESP_MASK (0xff << 24) |
#define SMC_HOST_RESP_SHIFT 24 |
#define DCCG_DISP_SLOW_SELECT_REG 0x4fc |
#define DCCG_DISP1_SLOW_SELECT(x) ((x) << 0) |
#define DCCG_DISP1_SLOW_SELECT_MASK (7 << 0) |
#define DCCG_DISP1_SLOW_SELECT_SHIFT 0 |
#define DCCG_DISP2_SLOW_SELECT(x) ((x) << 4) |
#define DCCG_DISP2_SLOW_SELECT_MASK (7 << 4) |
#define DCCG_DISP2_SLOW_SELECT_SHIFT 4 |
#define CG_SPLL_FUNC_CNTL 0x600 |
#define SPLL_RESET (1 << 0) |
#define SPLL_SLEEP (1 << 1) |
#define SPLL_BYPASS_EN (1 << 3) |
#define SPLL_REF_DIV(x) ((x) << 4) |
#define SPLL_REF_DIV_MASK (0x3f << 4) |
#define SPLL_PDIV_A(x) ((x) << 20) |
#define SPLL_PDIV_A_MASK (0x7f << 20) |
#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) |
#define MPLL_AD_FUNC_CNTL 0x624 |
#define CLKF(x) ((x) << 0) |
#define CLKF_MASK (0x7f << 0) |
#define CLKR(x) ((x) << 7) |
#define CLKR_MASK (0x1f << 7) |
#define CLKFRAC(x) ((x) << 12) |
#define CLKFRAC_MASK (0x1f << 12) |
#define YCLK_POST_DIV(x) ((x) << 17) |
#define YCLK_POST_DIV_MASK (3 << 17) |
#define IBIAS(x) ((x) << 20) |
#define IBIAS_MASK (0x3ff << 20) |
#define RESET (1 << 30) |
#define PDNB (1 << 31) |
#define MPLL_AD_FUNC_CNTL_2 0x628 |
#define BYPASS (1 << 19) |
#define BIAS_GEN_PDNB (1 << 24) |
#define RESET_EN (1 << 25) |
#define VCO_MODE (1 << 29) |
#define MPLL_DQ_FUNC_CNTL 0x62c |
#define MPLL_DQ_FUNC_CNTL_2 0x630 |
#define GENERAL_PWRMGT 0x63c |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define THERMAL_PROTECTION_DIS (1 << 2) |
# define THERMAL_PROTECTION_TYPE (1 << 3) |
# define ENABLE_GEN2PCIE (1 << 4) |
# define ENABLE_GEN2XSP (1 << 5) |
# define SW_SMIO_INDEX(x) ((x) << 6) |
# define SW_SMIO_INDEX_MASK (3 << 6) |
# define SW_SMIO_INDEX_SHIFT 6 |
# define LOW_VOLT_D2_ACPI (1 << 8) |
# define LOW_VOLT_D3_ACPI (1 << 9) |
# define VOLT_PWRMGT_EN (1 << 10) |
# define BACKBIAS_PAD_EN (1 << 18) |
# define BACKBIAS_VALUE (1 << 19) |
# define DYN_SPREAD_SPECTRUM_EN (1 << 23) |
# define AC_DC_SW (1 << 24) |
#define SCLK_PWRMGT_CNTL 0x644 |
# define SCLK_PWRMGT_OFF (1 << 0) |
# define SCLK_LOW_D1 (1 << 1) |
# define FIR_RESET (1 << 4) |
# define FIR_FORCE_TREND_SEL (1 << 5) |
# define FIR_TREND_MODE (1 << 6) |
# define DYN_GFX_CLK_OFF_EN (1 << 7) |
# define GFX_CLK_FORCE_ON (1 << 8) |
# define GFX_CLK_REQUEST_OFF (1 << 9) |
# define GFX_CLK_FORCE_OFF (1 << 10) |
# define GFX_CLK_OFF_ACPI_D1 (1 << 11) |
# define GFX_CLK_OFF_ACPI_D2 (1 << 12) |
# define GFX_CLK_OFF_ACPI_D3 (1 << 13) |
# define DYN_LIGHT_SLEEP_EN (1 << 14) |
#define MCLK_PWRMGT_CNTL 0x648 |
# define DLL_SPEED(x) ((x) << 0) |
# define DLL_SPEED_MASK (0x1f << 0) |
# define MPLL_PWRMGT_OFF (1 << 5) |
# define DLL_READY (1 << 6) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCKA0_PDNB (1 << 8) |
# define MRDCKA1_PDNB (1 << 9) |
# define MRDCKB0_PDNB (1 << 10) |
# define MRDCKB1_PDNB (1 << 11) |
# define MRDCKC0_PDNB (1 << 12) |
# define MRDCKC1_PDNB (1 << 13) |
# define MRDCKD0_PDNB (1 << 14) |
# define MRDCKD1_PDNB (1 << 15) |
# define MRDCKA0_RESET (1 << 16) |
# define MRDCKA1_RESET (1 << 17) |
# define MRDCKB0_RESET (1 << 18) |
# define MRDCKB1_RESET (1 << 19) |
# define MRDCKC0_RESET (1 << 20) |
# define MRDCKC1_RESET (1 << 21) |
# define MRDCKD0_RESET (1 << 22) |
# define MRDCKD1_RESET (1 << 23) |
# define DLL_READY_READ (1 << 24) |
# define USE_DISPLAY_GAP (1 << 25) |
# define USE_DISPLAY_URGENT_NORMAL (1 << 26) |
# define MPLL_TURNOFF_D2 (1 << 28) |
#define DLL_CNTL 0x64c |
# define MRDCKA0_BYPASS (1 << 24) |
# define MRDCKA1_BYPASS (1 << 25) |
# define MRDCKB0_BYPASS (1 << 26) |
# define MRDCKB1_BYPASS (1 << 27) |
# define MRDCKC0_BYPASS (1 << 28) |
# define MRDCKC1_BYPASS (1 << 29) |
# define MRDCKD0_BYPASS (1 << 30) |
# define MRDCKD1_BYPASS (1 << 31) |
#define CG_AT 0x6d4 |
# define CG_R(x) ((x) << 0) |
# define CG_R_MASK (0xffff << 0) |
# define CG_L(x) ((x) << 16) |
# define CG_L_MASK (0xffff << 16) |
#define CG_DISPLAY_GAP_CNTL 0x714 |
# define DISP1_GAP(x) ((x) << 0) |
# define DISP1_GAP_MASK (3 << 0) |
# define DISP2_GAP(x) ((x) << 2) |
# define DISP2_GAP_MASK (3 << 2) |
# define VBI_TIMER_COUNT(x) ((x) << 4) |
# define VBI_TIMER_COUNT_MASK (0x3fff << 4) |
# define VBI_TIMER_UNIT(x) ((x) << 20) |
# define VBI_TIMER_UNIT_MASK (7 << 20) |
# define DISP1_GAP_MCHG(x) ((x) << 24) |
# define DISP1_GAP_MCHG_MASK (3 << 24) |
# define DISP2_GAP_MCHG(x) ((x) << 26) |
# define DISP2_GAP_MCHG_MASK (3 << 26) |
#define CG_BIF_REQ_AND_RSP 0x7f4 |
#define CG_CLIENT_REQ(x) ((x) << 0) |
#define CG_CLIENT_REQ_MASK (0xff << 0) |
#define CG_CLIENT_REQ_SHIFT 0 |
#define CG_CLIENT_RESP(x) ((x) << 8) |
#define CG_CLIENT_RESP_MASK (0xff << 8) |
#define CG_CLIENT_RESP_SHIFT 8 |
#define CLIENT_CG_REQ(x) ((x) << 16) |
#define CLIENT_CG_REQ_MASK (0xff << 16) |
#define CLIENT_CG_REQ_SHIFT 16 |
#define CLIENT_CG_RESP(x) ((x) << 24) |
#define CLIENT_CG_RESP_MASK (0xff << 24) |
#define CLIENT_CG_RESP_SHIFT 24 |
#define CG_SPLL_SPREAD_SPECTRUM 0x790 |
#define SSEN (1 << 0) |
#define CG_SPLL_SPREAD_SPECTRUM_2 0x794 |
#define MPLL_SS1 0x85c |
#define CLKV(x) ((x) << 0) |
#define CLKV_MASK (0x3ffffff << 0) |
#define MPLL_SS2 0x860 |
#define CLKS(x) ((x) << 0) |
#define CLKS_MASK (0xfff << 0) |
#define CG_IND_ADDR 0x8f8 |
#define CG_IND_DATA 0x8fc |
/* CGIND regs */ |
#define CG_CGTT_LOCAL_0 0x00 |
#define CG_CGTT_LOCAL_1 0x01 |
#define CG_CGTT_LOCAL_2 0x02 |
#define CG_CGTT_LOCAL_3 0x03 |
#define CG_CGLS_TILE_0 0x20 |
#define CG_CGLS_TILE_1 0x21 |
#define CG_CGLS_TILE_2 0x22 |
#define CG_CGLS_TILE_3 0x23 |
#define CG_CGLS_TILE_4 0x24 |
#define CG_CGLS_TILE_5 0x25 |
#define CG_CGLS_TILE_6 0x26 |
#define CG_CGLS_TILE_7 0x27 |
#define CG_CGLS_TILE_8 0x28 |
#define CG_CGLS_TILE_9 0x29 |
#define CG_CGLS_TILE_10 0x2a |
#define CG_CGLS_TILE_11 0x2b |
#define VM_L2_CG 0x15c0 |
#define MC_CONFIG 0x2000 |
#define MC_CONFIG_MCD 0x20a0 |
#define MC_CG_CONFIG_MCD 0x20a4 |
#define MC_RD_ENABLE_MCD(x) ((x) << 8) |
#define MC_RD_ENABLE_MCD_MASK (7 << 8) |
#define MC_HUB_MISC_HUB_CG 0x20b8 |
#define MC_HUB_MISC_VM_CG 0x20bc |
#define MC_HUB_MISC_SIP_CG 0x20c0 |
#define MC_XPB_CLK_GAT 0x2478 |
#define MC_CG_CONFIG 0x25bc |
#define MC_RD_ENABLE(x) ((x) << 4) |
#define MC_RD_ENABLE_MASK (3 << 4) |
#define MC_CITF_MISC_RD_CG 0x2648 |
#define MC_CITF_MISC_WR_CG 0x264c |
#define MC_CITF_MISC_VM_CG 0x2650 |
# define MEM_LS_ENABLE (1 << 19) |
#define MC_ARB_BURST_TIME 0x2808 |
#define STATE0(x) ((x) << 0) |
#define STATE0_MASK (0x1f << 0) |
#define STATE1(x) ((x) << 5) |
#define STATE1_MASK (0x1f << 5) |
#define STATE2(x) ((x) << 10) |
#define STATE2_MASK (0x1f << 10) |
#define STATE3(x) ((x) << 15) |
#define STATE3_MASK (0x1f << 15) |
#define MC_SEQ_RAS_TIMING 0x28a0 |
#define MC_SEQ_CAS_TIMING 0x28a4 |
#define MC_SEQ_MISC_TIMING 0x28a8 |
#define MC_SEQ_MISC_TIMING2 0x28ac |
#define MC_SEQ_RD_CTL_D0 0x28b4 |
#define MC_SEQ_RD_CTL_D1 0x28b8 |
#define MC_SEQ_WR_CTL_D0 0x28bc |
#define MC_SEQ_WR_CTL_D1 0x28c0 |
#define MC_SEQ_STATUS_M 0x29f4 |
# define PMG_PWRSTATE (1 << 16) |
#define MC_SEQ_MISC1 0x2a04 |
#define MC_SEQ_RESERVE_M 0x2a08 |
#define MC_PMG_CMD_EMRS 0x2a0c |
#define MC_SEQ_MISC3 0x2a2c |
#define MC_SEQ_MISC5 0x2a54 |
#define MC_SEQ_MISC6 0x2a58 |
#define MC_SEQ_MISC7 0x2a64 |
#define MC_SEQ_CG 0x2a68 |
#define CG_SEQ_REQ(x) ((x) << 0) |
#define CG_SEQ_REQ_MASK (0xff << 0) |
#define CG_SEQ_REQ_SHIFT 0 |
#define CG_SEQ_RESP(x) ((x) << 8) |
#define CG_SEQ_RESP_MASK (0xff << 8) |
#define CG_SEQ_RESP_SHIFT 8 |
#define SEQ_CG_REQ(x) ((x) << 16) |
#define SEQ_CG_REQ_MASK (0xff << 16) |
#define SEQ_CG_REQ_SHIFT 16 |
#define SEQ_CG_RESP(x) ((x) << 24) |
#define SEQ_CG_RESP_MASK (0xff << 24) |
#define SEQ_CG_RESP_SHIFT 24 |
#define MC_SEQ_RAS_TIMING_LP 0x2a6c |
#define MC_SEQ_CAS_TIMING_LP 0x2a70 |
#define MC_SEQ_MISC_TIMING_LP 0x2a74 |
#define MC_SEQ_MISC_TIMING2_LP 0x2a78 |
#define MC_SEQ_WR_CTL_D0_LP 0x2a7c |
#define MC_SEQ_WR_CTL_D1_LP 0x2a80 |
#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84 |
#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88 |
#define MC_PMG_CMD_MRS 0x2aac |
#define MC_SEQ_RD_CTL_D0_LP 0x2b1c |
#define MC_SEQ_RD_CTL_D1_LP 0x2b20 |
#define MC_PMG_CMD_MRS1 0x2b44 |
#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48 |
#define CGTS_SM_CTRL_REG 0x9150 |
/* Registers */ |
#define RCU_IND_INDEX 0x100 |
90,6 → 381,34 |
#define CG_VCLK_STATUS 0x61c |
#define CG_SCRATCH1 0x820 |
#define RLC_CNTL 0x3f00 |
# define RLC_ENABLE (1 << 0) |
# define GFX_POWER_GATING_ENABLE (1 << 7) |
# define GFX_POWER_GATING_SRC (1 << 8) |
# define DYN_PER_SIMD_PG_ENABLE (1 << 27) |
# define LB_CNT_SPIM_ACTIVE (1 << 30) |
# define LOAD_BALANCE_ENABLE (1 << 31) |
#define RLC_HB_BASE 0x3f10 |
#define RLC_HB_CNTL 0x3f0c |
#define RLC_HB_RPTR 0x3f20 |
#define RLC_HB_WPTR 0x3f1c |
#define RLC_HB_WPTR_LSB_ADDR 0x3f14 |
#define RLC_HB_WPTR_MSB_ADDR 0x3f18 |
#define RLC_MC_CNTL 0x3f44 |
#define RLC_UCODE_CNTL 0x3f48 |
#define RLC_UCODE_ADDR 0x3f2c |
#define RLC_UCODE_DATA 0x3f30 |
/* new for TN */ |
#define TN_RLC_SAVE_AND_RESTORE_BASE 0x3f10 |
#define TN_RLC_LB_CNTR_MAX 0x3f14 |
#define TN_RLC_LB_CNTR_INIT 0x3f18 |
#define TN_RLC_CLEAR_STATE_RESTORE_BASE 0x3f20 |
#define TN_RLC_LB_INIT_SIMD_MASK 0x3fe4 |
#define TN_RLC_LB_ALWAYS_ACTIVE_SIMD_MASK 0x3fe8 |
#define TN_RLC_LB_PARAMS 0x3fec |
#define GRBM_GFX_INDEX 0x802C |
#define INSTANCE_INDEX(x) ((x) << 0) |
#define SE_INDEX(x) ((x) << 16) |
182,6 → 501,9 |
#define DCCG_AUDIO_DTO0_MODULE 0x05b4 |
#define DCCG_AUDIO_DTO0_LOAD 0x05b8 |
#define DCCG_AUDIO_DTO0_CNTL 0x05bc |
# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0) |
# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7 |
# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0 |
#define DCCG_AUDIO_DTO1_PHASE 0x05c0 |
#define DCCG_AUDIO_DTO1_MODULE 0x05c4 |
195,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) |
396,6 → 719,13 |
#define AFMT_GENERIC0_7 0x7138 |
/* DCE4/5 ELD audio interface */ |
#define AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER 0x5f78 |
#define SPEAKER_ALLOCATION(x) (((x) & 0x7f) << 0) |
#define SPEAKER_ALLOCATION_MASK (0x7f << 0) |
#define SPEAKER_ALLOCATION_SHIFT 0 |
#define HDMI_CONNECTION (1 << 16) |
#define DP_CONNECTION (1 << 17) |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0 0x5f84 /* LPCM */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1 0x5f88 /* AC3 */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2 0x5f8c /* MPEG1 */ |
425,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) |
503,6 → 871,30 |
#define CG_THERMAL_CTRL 0x72c |
#define TOFFSET_MASK 0x00003FE0 |
#define TOFFSET_SHIFT 5 |
#define DIG_THERM_DPM(x) ((x) << 14) |
#define DIG_THERM_DPM_MASK 0x003FC000 |
#define DIG_THERM_DPM_SHIFT 14 |
#define CG_THERMAL_INT 0x734 |
#define DIG_THERM_INTH(x) ((x) << 8) |
#define DIG_THERM_INTH_MASK 0x0000FF00 |
#define DIG_THERM_INTH_SHIFT 8 |
#define DIG_THERM_INTL(x) ((x) << 16) |
#define DIG_THERM_INTL_MASK 0x00FF0000 |
#define DIG_THERM_INTL_SHIFT 16 |
#define THERM_INT_MASK_HIGH (1 << 24) |
#define THERM_INT_MASK_LOW (1 << 25) |
#define TN_CG_THERMAL_INT_CTRL 0x738 |
#define TN_DIG_THERM_INTH(x) ((x) << 0) |
#define TN_DIG_THERM_INTH_MASK 0x000000FF |
#define TN_DIG_THERM_INTH_SHIFT 0 |
#define TN_DIG_THERM_INTL(x) ((x) << 8) |
#define TN_DIG_THERM_INTL_MASK 0x0000FF00 |
#define TN_DIG_THERM_INTL_SHIFT 8 |
#define TN_THERM_INT_MASK_HIGH (1 << 24) |
#define TN_THERM_INT_MASK_LOW (1 << 25) |
#define CG_MULT_THERMAL_STATUS 0x740 |
#define ASIC_T(x) ((x) << 16) |
#define ASIC_T_MASK 0x07FF0000 |
510,6 → 902,7 |
#define CG_TS0_STATUS 0x760 |
#define TS0_ADC_DOUT_MASK 0x000003FF |
#define TS0_ADC_DOUT_SHIFT 0 |
/* APU */ |
#define CG_THERMAL_STATUS 0x678 |
810,6 → 1203,10 |
# define LATENCY_LOW_WATERMARK(x) ((x) << 0) |
# define LATENCY_HIGH_WATERMARK(x) ((x) << 16) |
#define PIPE0_DMIF_BUFFER_CONTROL 0x0ca0 |
# define DMIF_BUFFERS_ALLOCATED(x) ((x) << 0) |
# define DMIF_BUFFERS_ALLOCATED_COMPLETED (1 << 4) |
#define IH_RB_CNTL 0x3e00 |
# define IH_RB_ENABLE (1 << 0) |
# define IH_IB_SIZE(x) ((x) << 1) /* log2 */ |
958,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 |
992,7 → 1421,48 |
#define DMA_PACKET_CONSTANT_FILL 0xd |
#define DMA_PACKET_NOP 0xf |
/* PCIE link stuff */ |
/* PIF PHY0 indirect regs */ |
#define PB0_PIF_CNTL 0x10 |
# define LS2_EXIT_TIME(x) ((x) << 17) |
# define LS2_EXIT_TIME_MASK (0x7 << 17) |
# define LS2_EXIT_TIME_SHIFT 17 |
#define PB0_PIF_PAIRING 0x11 |
# define MULTI_PIF (1 << 25) |
#define PB0_PIF_PWRDOWN_0 0x12 |
# define PLL_POWER_STATE_IN_TXS2_0(x) ((x) << 7) |
# define PLL_POWER_STATE_IN_TXS2_0_MASK (0x7 << 7) |
# define PLL_POWER_STATE_IN_TXS2_0_SHIFT 7 |
# define PLL_POWER_STATE_IN_OFF_0(x) ((x) << 10) |
# define PLL_POWER_STATE_IN_OFF_0_MASK (0x7 << 10) |
# define PLL_POWER_STATE_IN_OFF_0_SHIFT 10 |
# define PLL_RAMP_UP_TIME_0(x) ((x) << 24) |
# define PLL_RAMP_UP_TIME_0_MASK (0x7 << 24) |
# define PLL_RAMP_UP_TIME_0_SHIFT 24 |
#define PB0_PIF_PWRDOWN_1 0x13 |
# define PLL_POWER_STATE_IN_TXS2_1(x) ((x) << 7) |
# define PLL_POWER_STATE_IN_TXS2_1_MASK (0x7 << 7) |
# define PLL_POWER_STATE_IN_TXS2_1_SHIFT 7 |
# define PLL_POWER_STATE_IN_OFF_1(x) ((x) << 10) |
# define PLL_POWER_STATE_IN_OFF_1_MASK (0x7 << 10) |
# define PLL_POWER_STATE_IN_OFF_1_SHIFT 10 |
# define PLL_RAMP_UP_TIME_1(x) ((x) << 24) |
# define PLL_RAMP_UP_TIME_1_MASK (0x7 << 24) |
# define PLL_RAMP_UP_TIME_1_SHIFT 24 |
/* PIF PHY1 indirect regs */ |
#define PB1_PIF_CNTL 0x10 |
#define PB1_PIF_PAIRING 0x11 |
#define PB1_PIF_PWRDOWN_0 0x12 |
#define PB1_PIF_PWRDOWN_1 0x13 |
/* PCIE PORT indirect regs */ |
#define PCIE_LC_CNTL 0xa0 |
# define LC_L0S_INACTIVITY(x) ((x) << 8) |
# define LC_L0S_INACTIVITY_MASK (0xf << 8) |
# define LC_L0S_INACTIVITY_SHIFT 8 |
# define LC_L1_INACTIVITY(x) ((x) << 12) |
# define LC_L1_INACTIVITY_MASK (0xf << 12) |
# define LC_L1_INACTIVITY_SHIFT 12 |
# define LC_PMI_TO_L1_DIS (1 << 16) |
# define LC_ASPM_TO_L1_DIS (1 << 24) |
#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */ |
#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ |
# define LC_LINK_WIDTH_SHIFT 0 |
1012,6 → 1482,9 |
# define LC_SHORT_RECONFIG_EN (1 << 11) |
# define LC_UPCONFIGURE_SUPPORT (1 << 12) |
# define LC_UPCONFIGURE_DIS (1 << 13) |
# define LC_DYN_LANES_PWR_STATE(x) ((x) << 21) |
# define LC_DYN_LANES_PWR_STATE_MASK (0x3 << 21) |
# define LC_DYN_LANES_PWR_STATE_SHIFT 21 |
#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ |
# define LC_GEN2_EN_STRAP (1 << 0) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) |
1020,6 → 1493,9 |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 |
# define LC_CURRENT_DATA_RATE (1 << 11) |
# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12 |
# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) |
# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) |
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) |
1100,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) |
1115,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 |
/drivers/video/drm/radeon/firmware/BONAIRE_mc2.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/BONAIRE_smc.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/BONAIRE_vce.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAINAN_mc2.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_ce.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_mc.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_mc2.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_me.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_mec.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_pfp.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_rlc.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_sdma.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/HAWAII_smc.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/KAVERI_ce.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/KAVERI_me.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/KAVERI_mec.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/KAVERI_pfp.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/KAVERI_rlc.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/KAVERI_sdma.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/MULLINS_ce.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/MULLINS_me.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/MULLINS_mec.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/MULLINS_pfp.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/MULLINS_rlc.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/MULLINS_sdma.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/OLAND_mc2.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/PITCAIRN_mc2.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/TAHITI_mc2.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/firmware/VERDE_mc2.bin |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/drivers/video/drm/radeon/fwblob.asm |
---|
14,684 → 14,318 |
align 16 |
___start_builtin_fw: |
macro CE_code [arg] |
{ |
dd FIRMWARE_#arg#_CE |
dd arg#_CE_START |
dd (arg#_CE_END - arg#_CE_START) |
} |
dd FIRMWARE_R100_CP |
dd R100CP_START |
dd (R100CP_END - R100CP_START) |
macro CE_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_CE db 'radeon/',`arg,'_ce.bin',0 |
forward |
dd FIRMWARE_R200_CP |
dd R200CP_START |
dd (R200CP_END - R200CP_START) |
align 16 |
arg#_CE_START: |
file "firmware/"#`arg#"_ce.bin" |
arg#_CE_END: |
} |
dd FIRMWARE_R300_CP |
dd R300CP_START |
dd (R300CP_END - R300CP_START) |
macro CP_code [arg] |
{ |
dd FIRMWARE_#arg#_CP |
dd arg#_CP_START |
dd (arg#_CP_END - arg#_CP_START) |
} |
dd FIRMWARE_R420_CP |
dd R420CP_START |
dd (R420CP_END - R420CP_START) |
dd FIRMWARE_R520_CP |
dd R520CP_START |
dd (R520CP_END - R520CP_START) |
dd FIRMWARE_RS600_CP |
dd RS600CP_START |
dd (RS600CP_END - RS600CP_START) |
dd FIRMWARE_RS690_CP |
dd RS690CP_START |
dd (RS690CP_END - RS690CP_START) |
dd FIRMWARE_R600_ME |
dd R600ME_START |
dd (R600ME_END - R600ME_START) |
dd FIRMWARE_RS780_ME |
dd RS780ME_START |
dd (RS780ME_END - RS780ME_START) |
dd FIRMWARE_RS780_PFP |
dd RS780PFP_START |
dd (RS780PFP_END - RS780PFP_START) |
dd FIRMWARE_RV610_ME |
dd RV610ME_START |
dd (RV610ME_END - RV610ME_START) |
dd FIRMWARE_RV620_ME |
dd RV620ME_START |
dd (RV620ME_END - RV620ME_START) |
dd FIRMWARE_RV630_ME |
dd RV630ME_START |
dd (RV630ME_END - RV630ME_START) |
dd FIRMWARE_RV635_ME |
dd RV635ME_START |
dd (RV635ME_END - RV635ME_START) |
dd FIRMWARE_RV670_ME |
dd RV670ME_START |
dd (RV670ME_END - RV670ME_START) |
dd FIRMWARE_RV710_ME |
dd RV710ME_START |
dd (RV710ME_END - RV710ME_START) |
dd FIRMWARE_RV730_ME |
dd RV730ME_START |
dd (RV730ME_END - RV730ME_START) |
dd FIRMWARE_RV770_ME |
dd RV770ME_START |
dd (RV770ME_END - RV770ME_START) |
dd FIRMWARE_CYPRESS_ME |
dd CYPRESSME_START |
dd (CYPRESSME_END - CYPRESSME_START) |
dd FIRMWARE_REDWOOD_ME |
dd REDWOODME_START |
dd (REDWOODME_END - REDWOODME_START) |
dd FIRMWARE_CEDAR_ME |
dd CEDARME_START |
dd (CEDARME_END - CEDARME_START) |
dd FIRMWARE_JUNIPER_ME |
dd JUNIPERME_START |
dd (JUNIPERME_END - JUNIPERME_START) |
dd FIRMWARE_PALM_ME |
dd PALMME_START |
dd (PALMME_END - PALMME_START) |
dd FIRMWARE_SUMO_ME |
dd SUMOME_START |
dd (SUMOME_END - SUMOME_START) |
dd FIRMWARE_SUMO2_ME |
dd SUMO2ME_START |
dd (SUMO2ME_END - SUMO2ME_START) |
macro NI_code [arg] |
macro CP_firmware [arg] |
{ |
dd FIRMWARE_#arg#_ME |
dd arg#ME_START |
dd (arg#ME_END - arg#ME_START) |
forward |
FIRMWARE_#arg#_CP db 'radeon/',`arg,'_cp.bin',0 |
forward |
dd FIRMWARE_#arg#_PFP |
dd arg#PFP_START |
dd (arg#PFP_END - arg#PFP_START) |
dd FIRMWARE_#arg#_MC |
dd arg#MC_START |
dd (arg#MC_END - arg#MC_START) |
align 16 |
arg#_CP_START: |
file "firmware/"#`arg#"_cp.bin" |
arg#_CP_END: |
} |
NI_code BARTS, TURKS, CAICOS, CAYMAN |
dd FIRMWARE_RV610_PFP |
dd RV610PFP_START |
dd (RV610PFP_END - RV610PFP_START) |
dd FIRMWARE_RV620_PFP |
dd RV620PFP_START |
dd (RV620PFP_END - RV620PFP_START) |
dd FIRMWARE_RV630_PFP |
dd RV630PFP_START |
dd (RV630PFP_END - RV630PFP_START) |
dd FIRMWARE_RV635_PFP |
dd RV635PFP_START |
dd (RV635PFP_END - RV635PFP_START) |
dd FIRMWARE_RV670_PFP |
dd RV670PFP_START |
dd (RV670PFP_END - RV670PFP_START) |
dd FIRMWARE_RV710_PFP |
dd RV670PFP_START |
dd (RV710PFP_END - RV710PFP_START) |
dd FIRMWARE_RV730_PFP |
dd RV730PFP_START |
dd (RV730PFP_END - RV730PFP_START) |
dd FIRMWARE_RV770_PFP |
dd RV770PFP_START |
dd (RV770PFP_END - RV770PFP_START) |
dd FIRMWARE_CYPRESS_PFP |
dd CYPRESSPFP_START |
dd (CYPRESSPFP_END - CYPRESSPFP_START) |
dd FIRMWARE_REDWOOD_PFP |
dd REDWOODPFP_START |
dd (REDWOODPFP_END - REDWOODPFP_START) |
dd FIRMWARE_CEDAR_PFP |
dd CEDARPFP_START |
dd (CEDARPFP_END - CEDARPFP_START) |
dd FIRMWARE_JUNIPER_PFP |
dd JUNIPERPFP_START |
dd (JUNIPERPFP_END - JUNIPERPFP_START) |
dd FIRMWARE_PALM_PFP |
dd PALMPFP_START |
dd (PALMPFP_END - PALMPFP_START) |
dd FIRMWARE_SUMO_PFP |
dd SUMOPFP_START |
dd (SUMOPFP_END - SUMOPFP_START) |
dd FIRMWARE_SUMO2_PFP |
dd SUMO2PFP_START |
dd (SUMO2PFP_END - SUMO2PFP_START) |
dd FIRMWARE_BARTS_PFP |
dd BARTSPFP_START |
dd (BARTSPFP_END - BARTSPFP_START) |
dd FIRMWARE_R600_RLC |
dd R600RLC_START |
dd (R600RLC_END - R600RLC_START) |
dd FIRMWARE_R700_RLC |
dd R700RLC_START |
dd (R700RLC_END - R700RLC_START) |
dd FIRMWARE_CYPRESS_RLC |
dd CYPRESSRLC_START |
dd (CYPRESSRLC_END - CYPRESSRLC_START) |
dd FIRMWARE_REDWOOD_RLC |
dd REDWOODRLC_START |
dd (REDWOODRLC_END - REDWOODRLC_START) |
dd FIRMWARE_CEDAR_RLC |
dd CEDARRLC_START |
dd (CEDARRLC_END - CEDARRLC_START) |
dd FIRMWARE_JUNIPER_RLC |
dd JUNIPERRLC_START |
dd (JUNIPERRLC_END - JUNIPERRLC_START) |
dd FIRMWARE_BTC_RLC |
dd BTCRLC_START |
dd (BTCRLC_END - BTCRLC_START) |
dd FIRMWARE_SUMO_RLC |
dd SUMORLC_START |
dd (SUMORLC_END - SUMORLC_START) |
macro SI_code [arg] |
macro PFP_code [arg] |
{ |
dd FIRMWARE_#arg#_PFP |
dd arg#_PFP_START |
dd (arg#_PFP_END - arg#_PFP_START) |
} |
dd FIRMWARE_#arg#_ME |
dd arg#_ME_START |
dd (arg#_ME_END - arg#_ME_START) |
macro PFP_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_PFP db 'radeon/',`arg,'_pfp.bin',0 |
forward |
dd FIRMWARE_#arg#_CE |
dd arg#_CE_START |
dd (arg#_CE_END - arg#_CE_START) |
align 16 |
arg#_PFP_START: |
file "firmware/"#`arg#"_pfp.bin" |
arg#_PFP_END: |
} |
macro MC_code [arg] |
{ |
dd FIRMWARE_#arg#_MC |
dd arg#_MC_START |
dd (arg#_MC_END - arg#_MC_START) |
dd FIRMWARE_#arg#_RLC |
dd arg#_RLC_START |
dd (arg#_RLC_END - arg#_RLC_START) |
} |
SI_code TAHITI, PITCAIRN, VERDE, OLAND, HAINAN |
___end_builtin_fw: |
FIRMWARE_R100_CP db 'radeon/R100_cp.bin',0 |
FIRMWARE_R200_CP db 'radeon/R200_cp.bin',0 |
FIRMWARE_R300_CP db 'radeon/R300_cp.bin',0 |
FIRMWARE_R420_CP db 'radeon/R420_cp.bin',0 |
FIRMWARE_R520_CP db 'radeon/R520_cp.bin',0 |
FIRMWARE_RS600_CP db 'radeon/RS600_cp.bin',0 |
FIRMWARE_RS690_CP db 'radeon/RS690_cp.bin',0 |
FIRMWARE_RS780_ME db 'radeon/RS780_me.bin',0 |
FIRMWARE_R600_ME db 'radeon/RV600_me.bin',0 |
FIRMWARE_RV610_ME db 'radeon/RV610_me.bin',0 |
FIRMWARE_RV620_ME db 'radeon/RV620_me.bin',0 |
FIRMWARE_RV630_ME db 'radeon/RV630_me.bin',0 |
FIRMWARE_RV635_ME db 'radeon/RV635_me.bin',0 |
FIRMWARE_RV670_ME db 'radeon/RV670_me.bin',0 |
FIRMWARE_RV710_ME db 'radeon/RV710_me.bin',0 |
FIRMWARE_RV730_ME db 'radeon/RV730_me.bin',0 |
FIRMWARE_RV770_ME db 'radeon/RV770_me.bin',0 |
FIRMWARE_CYPRESS_ME db 'radeon/CYPRESS_me.bin',0 |
FIRMWARE_REDWOOD_ME db 'radeon/REDWOOD_me.bin',0 |
FIRMWARE_CEDAR_ME db 'radeon/CEDAR_me.bin',0 |
FIRMWARE_JUNIPER_ME db 'radeon/JUNIPER_me.bin',0 |
FIRMWARE_PALM_ME db 'radeon/PALM_me.bin',0 |
FIRMWARE_SUMO_ME db 'radeon/SUMO_me.bin',0 |
FIRMWARE_SUMO2_ME db 'radeon/SUMO2_me.bin',0 |
FIRMWARE_BARTS_ME db 'radeon/BARTS_me.bin',0 |
FIRMWARE_TURKS_ME db 'radeon/TURKS_me.bin',0 |
FIRMWARE_CAICOS_ME db 'radeon/CAICOS_me.bin',0 |
FIRMWARE_CAYMAN_ME db 'radeon/CAYMAN_me.bin',0 |
FIRMWARE_RS780_PFP db 'radeon/RS780_pfp.bin',0 |
FIRMWARE_R600_PFP db 'radeon/R600_pfp.bin',0 |
FIRMWARE_RV610_PFP db 'radeon/RV610_pfp.bin',0 |
FIRMWARE_RV620_PFP db 'radeon/RV620_pfp.bin',0 |
FIRMWARE_RV630_PFP db 'radeon/RV630_pfp.bin',0 |
FIRMWARE_RV635_PFP db 'radeon/RV635_pfp.bin',0 |
FIRMWARE_RV670_PFP db 'radeon/RV670_pfp.bin',0 |
FIRMWARE_RV710_PFP db 'radeon/RV710_pfp.bin',0 |
FIRMWARE_RV730_PFP db 'radeon/RV730_pfp.bin',0 |
FIRMWARE_RV770_PFP db 'radeon/RV770_pfp.bin',0 |
FIRMWARE_CYPRESS_PFP db 'radeon/CYPRESS_pfp.bin',0 |
FIRMWARE_REDWOOD_PFP db 'radeon/REDWOOD_pfp.bin',0 |
FIRMWARE_CEDAR_PFP db 'radeon/CEDAR_pfp.bin',0 |
FIRMWARE_JUNIPER_PFP db 'radeon/JUNIPER_pfp.bin',0 |
FIRMWARE_PALM_PFP db 'radeon/PALM_pfp.bin',0 |
FIRMWARE_SUMO_PFP db 'radeon/SUMO_pfp.bin',0 |
FIRMWARE_SUMO2_PFP db 'radeon/SUMO2_pfp.bin',0 |
FIRMWARE_BARTS_PFP db 'radeon/BARTS_pfp.bin',0 |
FIRMWARE_TURKS_PFP db 'radeon/TURKS_pfp.bin',0 |
FIRMWARE_CAICOS_PFP db 'radeon/CAICOS_pfp.bin',0 |
FIRMWARE_CAYMAN_PFP db 'radeon/CAYMAN_pfp.bin',0 |
FIRMWARE_R600_RLC db 'radeon/R600_rlc.bin',0 |
FIRMWARE_R700_RLC db 'radeon/R700_rlc.bin',0 |
FIRMWARE_CYPRESS_RLC db 'radeon/CYPRESS_rlc.bin',0 |
FIRMWARE_REDWOOD_RLC db 'radeon/REDWOOD_rlc.bin',0 |
FIRMWARE_CEDAR_RLC db 'radeon/CEDAR_rlc.bin',0 |
FIRMWARE_JUNIPER_RLC db 'radeon/JUNIPER_rlc.bin',0 |
FIRMWARE_SUMO_RLC db 'radeon/SUMO_rlc.bin',0 |
FIRMWARE_BTC_RLC db 'radeon/BTC_rlc.bin',0 |
FIRMWARE_CAYMAN_RLC db 'radeon/CAYMAN_rlc.bin',0 |
FIRMWARE_BARTS_MC db 'radeon/BARTS_mc.bin',0 |
FIRMWARE_TURKS_MC db 'radeon/TURKS_mc.bin',0 |
FIRMWARE_CAICOS_MC db 'radeon/CAICOS_mc.bin',0 |
FIRMWARE_CAYMAN_MC db 'radeon/CAYMAN_mc.bin',0 |
macro SI_firmware [arg] |
macro MC_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_PFP db 'radeon/',`arg,'_pfp.bin',0 |
FIRMWARE_#arg#_ME db 'radeon/',`arg,'_me.bin',0 |
FIRMWARE_#arg#_CE db 'radeon/',`arg,'_ce.bin',0 |
FIRMWARE_#arg#_MC db 'radeon/',`arg,'_mc.bin',0 |
FIRMWARE_#arg#_RLC db 'radeon/',`arg,'_rlc.bin',0 |
forward |
align 16 |
arg#_PFP_START: |
file "firmware/"#`arg#"_pfp.bin" |
arg#_PFP_END: |
align 16 |
arg#_ME_START: |
file "firmware/"#`arg#"_me.bin" |
arg#_ME_END: |
align 16 |
arg#_CE_START: |
file "firmware/"#`arg#"_ce.bin" |
arg#_CE_END: |
align 16 |
arg#_MC_START: |
file "firmware/"#`arg#"_mc.bin" |
arg#_MC_END: |
} |
align 16 |
arg#_RLC_START: |
file "firmware/"#`arg#"_rlc.bin" |
arg#_RLC_END: |
macro MC2_code [arg] |
{ |
dd FIRMWARE_#arg#_MC2 |
dd arg#_MC2_START |
dd (arg#_MC2_END - arg#_MC2_START) |
} |
SI_firmware TAHITI, PITCAIRN, VERDE, OLAND, HAINAN |
macro MC2_firmware [arg] |
{ |
align 16 |
R100CP_START: |
file 'firmware/R100_cp.bin' |
R100CP_END: |
forward |
FIRMWARE_#arg#_MC2 db 'radeon/',`arg,'_mc2.bin',0 |
forward |
align 16 |
R200CP_START: |
file 'firmware/R200_cp.bin' |
R200CP_END: |
arg#_MC2_START: |
file "firmware/"#`arg#"_mc2.bin" |
arg#_MC2_END: |
} |
align 16 |
R300CP_START: |
file 'firmware/R300_cp.bin' |
R300CP_END: |
macro ME_code [arg] |
{ |
dd FIRMWARE_#arg#_ME |
dd arg#_ME_START |
dd (arg#_ME_END - arg#_ME_START) |
} |
align 16 |
R420CP_START: |
file 'firmware/R420_cp.bin' |
R420CP_END: |
macro ME_firmware [arg] |
{ |
align 16 |
R520CP_START: |
file 'firmware/R520_cp.bin' |
R520CP_END: |
forward |
FIRMWARE_#arg#_ME db 'radeon/',`arg,'_me.bin',0 |
forward |
align 16 |
RS600CP_START: |
file 'firmware/RS600_cp.bin' |
RS600CP_END: |
arg#_ME_START: |
file "firmware/"#`arg#"_me.bin" |
arg#_ME_END: |
} |
align 16 |
RS690CP_START: |
file 'firmware/RS690_cp.bin' |
RS690CP_END: |
macro MEC_code [arg] |
{ |
dd FIRMWARE_#arg#_MEC |
dd arg#_MEC_START |
dd (arg#_MEC_END - arg#_MEC_START) |
} |
align 16 |
RS780ME_START: |
file 'firmware/RS780_me.bin' |
RS780ME_END: |
macro MEC_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_MEC db 'radeon/',`arg,'_mec.bin',0 |
forward |
align 16 |
RS780PFP_START: |
file 'firmware/RS780_pfp.bin' |
RS780PFP_END: |
arg#_MEC_START: |
file "firmware/"#`arg#"_mec.bin" |
arg#_MEC_END: |
} |
align 16 |
R600ME_START: |
file 'firmware/R600_me.bin' |
R600ME_END: |
macro RLC_code [arg] |
{ |
dd FIRMWARE_#arg#_RLC |
dd arg#_RLC_START |
dd (arg#_RLC_END - arg#_RLC_START) |
} |
align 16 |
RV610ME_START: |
file 'firmware/RV610_me.bin' |
RV610ME_END: |
macro RLC_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_RLC db 'radeon/',`arg,'_rlc.bin',0 |
forward |
align 16 |
RV620ME_START: |
file 'firmware/RV620_me.bin' |
RV620ME_END: |
arg#_RLC_START: |
file "firmware/"#`arg#"_rlc.bin" |
arg#_RLC_END: |
} |
align 16 |
RV630ME_START: |
file 'firmware/RV630_me.bin' |
RV630ME_END: |
macro SDMA_code [arg] |
{ |
dd FIRMWARE_#arg#_SDMA |
dd arg#_SDMA_START |
dd (arg#_SDMA_END - arg#_SDMA_START) |
} |
align 16 |
RV635ME_START: |
file 'firmware/RV635_me.bin' |
RV635ME_END: |
macro SDMA_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_SDMA db 'radeon/',`arg,'_sdma.bin',0 |
forward |
align 16 |
RV670ME_START: |
file 'firmware/RV670_me.bin' |
RV670ME_END: |
arg#_SDMA_START: |
file "firmware/"#`arg#"_sdma.bin" |
arg#_SDMA_END: |
} |
macro SMC_code [arg] |
{ |
dd FIRMWARE_#arg#_SMC |
dd arg#_SMC_START |
dd (arg#_SMC_END - arg#_SMC_START) |
} |
align 16 |
RV710ME_START: |
file 'firmware/RV710_me.bin' |
RV710ME_END: |
macro SMC_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_SMC db 'radeon/',`arg,'_smc.bin',0 |
forward |
align 16 |
RV730ME_START: |
file 'firmware/RV730_me.bin' |
RV730ME_END: |
arg#_SMC_START: |
file "firmware/"#`arg#"_smc.bin" |
arg#_SMC_END: |
} |
align 16 |
RV770ME_START: |
file 'firmware/RV770_me.bin' |
RV770ME_END: |
macro UVD_code [arg] |
{ |
dd FIRMWARE_#arg#_UVD |
dd arg#_UVD_START |
dd (arg#_UVD_END - arg#_UVD_START) |
} |
align 16 |
CYPRESSME_START: |
file 'firmware/CYPRESS_me.bin' |
CYPRESSME_END: |
macro UVD_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_UVD db 'radeon/',`arg,'_uvd.bin',0 |
forward |
align 16 |
REDWOODME_START: |
file 'firmware/REDWOOD_me.bin' |
REDWOODME_END: |
arg#_UVD_START: |
file "firmware/"#`arg#"_uvd.bin" |
arg#_UVD_END: |
} |
align 16 |
CEDARME_START: |
file 'firmware/CEDAR_me.bin' |
CEDARME_END: |
macro VCE_code [arg] |
{ |
dd FIRMWARE_#arg#_VCE |
dd arg#_VCE_START |
dd (arg#_VCE_END - arg#_VCE_START) |
} |
align 16 |
JUNIPERME_START: |
file 'firmware/JUNIPER_me.bin' |
JUNIPERME_END: |
macro VCE_firmware [arg] |
{ |
forward |
FIRMWARE_#arg#_VCE db 'radeon/',`arg,'_vce.bin',0 |
forward |
align 16 |
PALMME_START: |
file 'firmware/PALM_me.bin' |
PALMME_END: |
arg#_VCE_START: |
file "firmware/"#`arg#"_vce.bin" |
arg#_VCE_END: |
} |
align 16 |
SUMOME_START: |
file 'firmware/SUMO_me.bin' |
SUMOME_END: |
___start_builtin_fw: |
align 16 |
SUMO2ME_START: |
file 'firmware/SUMO2_me.bin' |
SUMO2ME_END: |
CE_code BONAIRE, HAINAN, HAWAII, KABINI, KAVERI, MULLINS, OLAND,\ |
PITCAIRN, TAHITI, VERDE |
align 16 |
BARTSME_START: |
file 'firmware/BARTS_me.bin' |
BARTSME_END: |
CP_code R100, R200, R300, R420, R520, RS600, RS690 |
align 16 |
TURKSME_START: |
file 'firmware/TURKS_me.bin' |
TURKSME_END: |
MC_code BARTS, BONAIRE, CAICOS, CAYMAN, HAINAN,\ |
HAWAII, OLAND, PITCAIRN,\ |
TAHITI, TURKS, VERDE |
align 16 |
CAICOSME_START: |
file 'firmware/CAICOS_me.bin' |
CAICOSME_END: |
MC2_code BONAIRE, HAINAN, HAWAII, OLAND, PITCAIRN,\ |
TAHITI, VERDE |
align 16 |
CAYMANME_START: |
file 'firmware/CAYMAN_me.bin' |
CAYMANME_END: |
ME_code R600, RS780, RV610, RV620, RV630, RV635, RV670, RV710, RV730, RV770,\ |
ARUBA, BARTS, BONAIRE, CAICOS, CAYMAN, CEDAR, CYPRESS, HAINAN,\ |
HAWAII, JUNIPER, KABINI, KAVERI, MULLINS, OLAND, PALM, PITCAIRN,\ |
REDWOOD, SUMO, SUMO2, TAHITI, TURKS, VERDE |
MEC_code BONAIRE, HAWAII, KABINI, KAVERI, MULLINS |
align 16 |
RV610PFP_START: |
file 'firmware/RV610_pfp.bin' |
RV610PFP_END: |
PFP_code R600, RS780, RV610, RV620, RV630, RV635, RV670, RV710, RV730, RV770,\ |
ARUBA, BARTS, BONAIRE, CAICOS, CAYMAN, CEDAR, CYPRESS, HAINAN,\ |
HAWAII, JUNIPER, KABINI, KAVERI, MULLINS, OLAND, PALM, PITCAIRN,\ |
REDWOOD, SUMO, SUMO2, TAHITI, TURKS, VERDE |
RLC_code R600, R700,\ |
ARUBA, BONAIRE, BTC, CAYMAN, CEDAR, CYPRESS, HAINAN,\ |
HAWAII, JUNIPER, KABINI, KAVERI, MULLINS, OLAND, PITCAIRN,\ |
REDWOOD, SUMO, TAHITI, VERDE |
align 16 |
RV620PFP_START: |
file 'firmware/RV620_pfp.bin' |
RV620PFP_END: |
SDMA_code BONAIRE, HAWAII, KABINI, KAVERI, MULLINS |
align 16 |
RV630PFP_START: |
file 'firmware/RV630_pfp.bin' |
RV630PFP_END: |
SMC_code RV710, RV730, RV740, RV770,\ |
BARTS, BONAIRE, CAICOS, CAYMAN, CEDAR, CYPRESS, HAINAN,\ |
HAWAII, JUNIPER, OLAND, PITCAIRN,\ |
REDWOOD, TAHITI, TURKS, VERDE |
UVD_code RV710, BONAIRE, CYPRESS, SUMO, TAHITI |
align 16 |
RV635PFP_START: |
file 'firmware/RV635_pfp.bin' |
RV635PFP_END: |
VCE_code BONAIRE |
align 16 |
RV670PFP_START: |
file 'firmware/RV670_pfp.bin' |
RV670PFP_END: |
___end_builtin_fw: |
align 16 |
RV710PFP_START: |
file 'firmware/RV710_pfp.bin' |
RV710PFP_END: |
CE_firmware BONAIRE, HAINAN, HAWAII, KABINI, KAVERI, MULLINS, OLAND,\ |
PITCAIRN, TAHITI, VERDE |
align 16 |
RV730PFP_START: |
file 'firmware/RV730_pfp.bin' |
RV730PFP_END: |
CP_firmware R100, R200, R300, R420, R520, RS600, RS690 |
MC_firmware BARTS, BONAIRE, CAICOS, CAYMAN, HAINAN,\ |
HAWAII, OLAND, PITCAIRN,\ |
TAHITI, TURKS, VERDE |
align 16 |
RV770PFP_START: |
file 'firmware/RV770_pfp.bin' |
RV770PFP_END: |
MC2_firmware BONAIRE, HAINAN, HAWAII, OLAND, PITCAIRN,\ |
TAHITI, VERDE |
ME_firmware R600, RS780, RV610, RV620, RV630, RV635, RV670, RV710, RV730, RV770,\ |
ARUBA, BARTS, BONAIRE, CAICOS, CAYMAN, CEDAR, CYPRESS, HAINAN,\ |
HAWAII, JUNIPER, KABINI, KAVERI, MULLINS, OLAND, PALM, PITCAIRN,\ |
REDWOOD, SUMO, SUMO2, TAHITI, TURKS, VERDE |
align 16 |
CYPRESSPFP_START: |
file 'firmware/CYPRESS_pfp.bin' |
CYPRESSPFP_END: |
MEC_firmware BONAIRE, HAWAII, KABINI, KAVERI, MULLINS |
align 16 |
REDWOODPFP_START: |
file 'firmware/REDWOOD_pfp.bin' |
REDWOODPFP_END: |
PFP_firmware R600, RS780, RV610, RV620, RV630, RV635, RV670, RV710, RV730, RV770,\ |
ARUBA, BARTS, BONAIRE, CAICOS, CAYMAN, CEDAR, CYPRESS, HAINAN,\ |
HAWAII, JUNIPER, KABINI, KAVERI, MULLINS, OLAND, PALM, PITCAIRN,\ |
REDWOOD, SUMO, SUMO2, TAHITI, TURKS, VERDE |
align 16 |
CEDARPFP_START: |
file 'firmware/CEDAR_pfp.bin' |
CEDARPFP_END: |
RLC_firmware R600, R700,\ |
ARUBA, BONAIRE, BTC, CAYMAN, CEDAR, CYPRESS, HAINAN,\ |
HAWAII, JUNIPER, KABINI, KAVERI, MULLINS, OLAND, PITCAIRN,\ |
REDWOOD, SUMO, TAHITI, VERDE |
align 16 |
JUNIPERPFP_START: |
file 'firmware/JUNIPER_pfp.bin' |
JUNIPERPFP_END: |
SDMA_firmware BONAIRE, HAWAII, KABINI, KAVERI, MULLINS |
align 16 |
PALMPFP_START: |
file 'firmware/PALM_pfp.bin' |
PALMPFP_END: |
SMC_firmware RV710, RV730, RV740, RV770,\ |
BARTS, BONAIRE, CAICOS, CAYMAN, CEDAR, CYPRESS, HAINAN,\ |
HAWAII, JUNIPER, OLAND, PITCAIRN,\ |
REDWOOD, TAHITI, TURKS, VERDE |
align 16 |
SUMOPFP_START: |
file 'firmware/SUMO_pfp.bin' |
SUMOPFP_END: |
UVD_firmware RV710, BONAIRE, CYPRESS, SUMO, TAHITI |
align 16 |
SUMO2PFP_START: |
file 'firmware/SUMO2_pfp.bin' |
SUMO2PFP_END: |
VCE_firmware BONAIRE |
align 16 |
BARTSPFP_START: |
file 'firmware/BARTS_pfp.bin' |
BARTSPFP_END: |
align 16 |
TURKSPFP_START: |
file 'firmware/TURKS_pfp.bin' |
TURKSPFP_END: |
align 16 |
CAICOSPFP_START: |
file 'firmware/CAICOS_pfp.bin' |
CAICOSPFP_END: |
align 16 |
CAYMANPFP_START: |
file 'firmware/CAYMAN_pfp.bin' |
CAYMANPFP_END: |
align 16 |
R600RLC_START: |
file 'firmware/R600_rlc.bin' |
R600RLC_END: |
align 16 |
R700RLC_START: |
file 'firmware/R700_rlc.bin' |
R700RLC_END: |
align 16 |
CYPRESSRLC_START: |
file 'firmware/CYPRESS_rlc.bin' |
CYPRESSRLC_END: |
align 16 |
REDWOODRLC_START: |
file 'firmware/REDWOOD_rlc.bin' |
REDWOODRLC_END: |
align 16 |
CEDARRLC_START: |
file 'firmware/CEDAR_rlc.bin' |
CEDARRLC_END: |
align 16 |
JUNIPERRLC_START: |
file 'firmware/JUNIPER_rlc.bin' |
JUNIPERRLC_END: |
align 16 |
SUMORLC_START: |
file 'firmware/SUMO_rlc.bin' |
SUMORLC_END: |
align 16 |
BTCRLC_START: |
file 'firmware/BTC_rlc.bin' |
BTCRLC_END: |
align 16 |
CAYMANRLC_START: |
file 'firmware/CAYMAN_rlc.bin' |
CAYMANRLC_END: |
align 16 |
BARTSMC_START: |
file 'firmware/BARTS_mc.bin' |
BARTSMC_END: |
align 16 |
TURKSMC_START: |
file 'firmware/TURKS_mc.bin' |
TURKSMC_END: |
align 16 |
CAICOSMC_START: |
file 'firmware/CAICOS_mc.bin' |
CAICOSMC_END: |
align 16 |
CAYMANMC_START: |
file 'firmware/CAYMAN_mc.bin' |
CAYMANMC_END: |
/drivers/video/drm/radeon/kv_dpm.c |
---|
0,0 → 1,2833 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "cikd.h" |
#include "r600_dpm.h" |
#include "kv_dpm.h" |
#include "radeon_asic.h" |
#include <linux/seq_file.h> |
#define KV_MAX_DEEPSLEEP_DIVIDER_ID 5 |
#define KV_MINIMUM_ENGINE_CLOCK 800 |
#define SMC_RAM_END 0x40000 |
static void kv_init_graphics_levels(struct radeon_device *rdev); |
static int kv_calculate_ds_divider(struct radeon_device *rdev); |
static int kv_calculate_nbps_level_settings(struct radeon_device *rdev); |
static int kv_calculate_dpm_settings(struct radeon_device *rdev); |
static void kv_enable_new_levels(struct radeon_device *rdev); |
static void kv_program_nbps_index_settings(struct radeon_device *rdev, |
struct radeon_ps *new_rps); |
static int kv_set_enabled_level(struct radeon_device *rdev, u32 level); |
static int kv_set_enabled_levels(struct radeon_device *rdev); |
static int kv_force_dpm_highest(struct radeon_device *rdev); |
static int kv_force_dpm_lowest(struct radeon_device *rdev); |
static void kv_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps); |
static int kv_set_thermal_temperature_range(struct radeon_device *rdev, |
int min_temp, int max_temp); |
static int kv_init_fps_limits(struct radeon_device *rdev); |
void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); |
static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate); |
static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate); |
static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate); |
extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev); |
extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev); |
extern void cik_update_cg(struct radeon_device *rdev, |
u32 block, bool enable); |
static const struct kv_lcac_config_values sx_local_cac_cfg_kv[] = |
{ |
{ 0, 4, 1 }, |
{ 1, 4, 1 }, |
{ 2, 5, 1 }, |
{ 3, 4, 2 }, |
{ 4, 1, 1 }, |
{ 5, 5, 2 }, |
{ 6, 6, 1 }, |
{ 7, 9, 2 }, |
{ 0xffffffff } |
}; |
static const struct kv_lcac_config_values mc0_local_cac_cfg_kv[] = |
{ |
{ 0, 4, 1 }, |
{ 0xffffffff } |
}; |
static const struct kv_lcac_config_values mc1_local_cac_cfg_kv[] = |
{ |
{ 0, 4, 1 }, |
{ 0xffffffff } |
}; |
static const struct kv_lcac_config_values mc2_local_cac_cfg_kv[] = |
{ |
{ 0, 4, 1 }, |
{ 0xffffffff } |
}; |
static const struct kv_lcac_config_values mc3_local_cac_cfg_kv[] = |
{ |
{ 0, 4, 1 }, |
{ 0xffffffff } |
}; |
static const struct kv_lcac_config_values cpl_local_cac_cfg_kv[] = |
{ |
{ 0, 4, 1 }, |
{ 1, 4, 1 }, |
{ 2, 5, 1 }, |
{ 3, 4, 1 }, |
{ 4, 1, 1 }, |
{ 5, 5, 1 }, |
{ 6, 6, 1 }, |
{ 7, 9, 1 }, |
{ 8, 4, 1 }, |
{ 9, 2, 1 }, |
{ 10, 3, 1 }, |
{ 11, 6, 1 }, |
{ 12, 8, 2 }, |
{ 13, 1, 1 }, |
{ 14, 2, 1 }, |
{ 15, 3, 1 }, |
{ 16, 1, 1 }, |
{ 17, 4, 1 }, |
{ 18, 3, 1 }, |
{ 19, 1, 1 }, |
{ 20, 8, 1 }, |
{ 21, 5, 1 }, |
{ 22, 1, 1 }, |
{ 23, 1, 1 }, |
{ 24, 4, 1 }, |
{ 27, 6, 1 }, |
{ 28, 1, 1 }, |
{ 0xffffffff } |
}; |
static const struct kv_lcac_config_reg sx0_cac_config_reg[] = |
{ |
{ 0xc0400d00, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } |
}; |
static const struct kv_lcac_config_reg mc0_cac_config_reg[] = |
{ |
{ 0xc0400d30, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } |
}; |
static const struct kv_lcac_config_reg mc1_cac_config_reg[] = |
{ |
{ 0xc0400d3c, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } |
}; |
static const struct kv_lcac_config_reg mc2_cac_config_reg[] = |
{ |
{ 0xc0400d48, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } |
}; |
static const struct kv_lcac_config_reg mc3_cac_config_reg[] = |
{ |
{ 0xc0400d54, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } |
}; |
static const struct kv_lcac_config_reg cpl_cac_config_reg[] = |
{ |
{ 0xc0400d80, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } |
}; |
static const struct kv_pt_config_reg didt_config_kv[] = |
{ |
{ 0x10, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x10, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x10, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x10, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x11, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x11, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x11, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x11, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x12, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x12, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x12, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x12, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x2, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, |
{ 0x2, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, |
{ 0x2, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, |
{ 0x1, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, |
{ 0x1, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, |
{ 0x0, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x30, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x30, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x30, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x30, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x31, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x31, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x31, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x31, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x32, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x32, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x32, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x32, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x22, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, |
{ 0x22, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, |
{ 0x22, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, |
{ 0x21, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, |
{ 0x21, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, |
{ 0x20, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x50, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x50, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x50, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x50, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x51, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x51, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x51, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x51, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x52, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x52, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x52, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x52, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x42, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, |
{ 0x42, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, |
{ 0x42, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, |
{ 0x41, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, |
{ 0x41, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, |
{ 0x40, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x70, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x70, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x70, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x70, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x71, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x71, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x71, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x71, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x72, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x72, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x72, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x72, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0x62, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, |
{ 0x62, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, |
{ 0x62, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, |
{ 0x61, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, |
{ 0x61, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, |
{ 0x60, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, |
{ 0xFFFFFFFF } |
}; |
static struct kv_ps *kv_get_ps(struct radeon_ps *rps) |
{ |
struct kv_ps *ps = rps->ps_priv; |
return ps; |
} |
static struct kv_power_info *kv_get_pi(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
#if 0 |
static void kv_program_local_cac_table(struct radeon_device *rdev, |
const struct kv_lcac_config_values *local_cac_table, |
const struct kv_lcac_config_reg *local_cac_reg) |
{ |
u32 i, count, data; |
const struct kv_lcac_config_values *values = local_cac_table; |
while (values->block_id != 0xffffffff) { |
count = values->signal_id; |
for (i = 0; i < count; i++) { |
data = ((values->block_id << local_cac_reg->block_shift) & |
local_cac_reg->block_mask); |
data |= ((i << local_cac_reg->signal_shift) & |
local_cac_reg->signal_mask); |
data |= ((values->t << local_cac_reg->t_shift) & |
local_cac_reg->t_mask); |
data |= ((1 << local_cac_reg->enable_shift) & |
local_cac_reg->enable_mask); |
WREG32_SMC(local_cac_reg->cntl, data); |
} |
values++; |
} |
} |
#endif |
static int kv_program_pt_config_registers(struct radeon_device *rdev, |
const struct kv_pt_config_reg *cac_config_regs) |
{ |
const struct kv_pt_config_reg *config_regs = cac_config_regs; |
u32 data; |
u32 cache = 0; |
if (config_regs == NULL) |
return -EINVAL; |
while (config_regs->offset != 0xFFFFFFFF) { |
if (config_regs->type == KV_CONFIGREG_CACHE) { |
cache |= ((config_regs->value << config_regs->shift) & config_regs->mask); |
} else { |
switch (config_regs->type) { |
case KV_CONFIGREG_SMC_IND: |
data = RREG32_SMC(config_regs->offset); |
break; |
case KV_CONFIGREG_DIDT_IND: |
data = RREG32_DIDT(config_regs->offset); |
break; |
default: |
data = RREG32(config_regs->offset << 2); |
break; |
} |
data &= ~config_regs->mask; |
data |= ((config_regs->value << config_regs->shift) & config_regs->mask); |
data |= cache; |
cache = 0; |
switch (config_regs->type) { |
case KV_CONFIGREG_SMC_IND: |
WREG32_SMC(config_regs->offset, data); |
break; |
case KV_CONFIGREG_DIDT_IND: |
WREG32_DIDT(config_regs->offset, data); |
break; |
default: |
WREG32(config_regs->offset << 2, data); |
break; |
} |
} |
config_regs++; |
} |
return 0; |
} |
static void kv_do_enable_didt(struct radeon_device *rdev, bool enable) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 data; |
if (pi->caps_sq_ramping) { |
data = RREG32_DIDT(DIDT_SQ_CTRL0); |
if (enable) |
data |= DIDT_CTRL_EN; |
else |
data &= ~DIDT_CTRL_EN; |
WREG32_DIDT(DIDT_SQ_CTRL0, data); |
} |
if (pi->caps_db_ramping) { |
data = RREG32_DIDT(DIDT_DB_CTRL0); |
if (enable) |
data |= DIDT_CTRL_EN; |
else |
data &= ~DIDT_CTRL_EN; |
WREG32_DIDT(DIDT_DB_CTRL0, data); |
} |
if (pi->caps_td_ramping) { |
data = RREG32_DIDT(DIDT_TD_CTRL0); |
if (enable) |
data |= DIDT_CTRL_EN; |
else |
data &= ~DIDT_CTRL_EN; |
WREG32_DIDT(DIDT_TD_CTRL0, data); |
} |
if (pi->caps_tcp_ramping) { |
data = RREG32_DIDT(DIDT_TCP_CTRL0); |
if (enable) |
data |= DIDT_CTRL_EN; |
else |
data &= ~DIDT_CTRL_EN; |
WREG32_DIDT(DIDT_TCP_CTRL0, data); |
} |
} |
static int kv_enable_didt(struct radeon_device *rdev, bool enable) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
if (pi->caps_sq_ramping || |
pi->caps_db_ramping || |
pi->caps_td_ramping || |
pi->caps_tcp_ramping) { |
cik_enter_rlc_safe_mode(rdev); |
if (enable) { |
ret = kv_program_pt_config_registers(rdev, didt_config_kv); |
if (ret) { |
cik_exit_rlc_safe_mode(rdev); |
return ret; |
} |
} |
kv_do_enable_didt(rdev, enable); |
cik_exit_rlc_safe_mode(rdev); |
} |
return 0; |
} |
#if 0 |
static void kv_initialize_hardware_cac_manager(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
if (pi->caps_cac) { |
WREG32_SMC(LCAC_SX0_OVR_SEL, 0); |
WREG32_SMC(LCAC_SX0_OVR_VAL, 0); |
kv_program_local_cac_table(rdev, sx_local_cac_cfg_kv, sx0_cac_config_reg); |
WREG32_SMC(LCAC_MC0_OVR_SEL, 0); |
WREG32_SMC(LCAC_MC0_OVR_VAL, 0); |
kv_program_local_cac_table(rdev, mc0_local_cac_cfg_kv, mc0_cac_config_reg); |
WREG32_SMC(LCAC_MC1_OVR_SEL, 0); |
WREG32_SMC(LCAC_MC1_OVR_VAL, 0); |
kv_program_local_cac_table(rdev, mc1_local_cac_cfg_kv, mc1_cac_config_reg); |
WREG32_SMC(LCAC_MC2_OVR_SEL, 0); |
WREG32_SMC(LCAC_MC2_OVR_VAL, 0); |
kv_program_local_cac_table(rdev, mc2_local_cac_cfg_kv, mc2_cac_config_reg); |
WREG32_SMC(LCAC_MC3_OVR_SEL, 0); |
WREG32_SMC(LCAC_MC3_OVR_VAL, 0); |
kv_program_local_cac_table(rdev, mc3_local_cac_cfg_kv, mc3_cac_config_reg); |
WREG32_SMC(LCAC_CPL_OVR_SEL, 0); |
WREG32_SMC(LCAC_CPL_OVR_VAL, 0); |
kv_program_local_cac_table(rdev, cpl_local_cac_cfg_kv, cpl_cac_config_reg); |
} |
} |
#endif |
static int kv_enable_smc_cac(struct radeon_device *rdev, bool enable) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret = 0; |
if (pi->caps_cac) { |
if (enable) { |
ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableCac); |
if (ret) |
pi->cac_enabled = false; |
else |
pi->cac_enabled = true; |
} else if (pi->cac_enabled) { |
kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableCac); |
pi->cac_enabled = false; |
} |
} |
return ret; |
} |
static int kv_process_firmware_header(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, DpmTable), |
&tmp, pi->sram_end); |
if (ret == 0) |
pi->dpm_table_start = tmp; |
ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION + |
offsetof(SMU7_Firmware_Header, SoftRegisters), |
&tmp, pi->sram_end); |
if (ret == 0) |
pi->soft_regs_start = tmp; |
return ret; |
} |
static int kv_enable_dpm_voltage_scaling(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
pi->graphics_voltage_change_enable = 1; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, GraphicsVoltageChangeEnable), |
&pi->graphics_voltage_change_enable, |
sizeof(u8), pi->sram_end); |
return ret; |
} |
static int kv_set_dpm_interval(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
pi->graphics_interval = 1; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, GraphicsInterval), |
&pi->graphics_interval, |
sizeof(u8), pi->sram_end); |
return ret; |
} |
static int kv_set_dpm_boot_state(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, GraphicsBootLevel), |
&pi->graphics_boot_level, |
sizeof(u8), pi->sram_end); |
return ret; |
} |
static void kv_program_vc(struct radeon_device *rdev) |
{ |
WREG32_SMC(CG_FTV_0, 0x3FFFC100); |
} |
static void kv_clear_vc(struct radeon_device *rdev) |
{ |
WREG32_SMC(CG_FTV_0, 0); |
} |
static int kv_set_divider_value(struct radeon_device *rdev, |
u32 index, u32 sclk) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct atom_clock_dividers dividers; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
sclk, false, ÷rs); |
if (ret) |
return ret; |
pi->graphics_level[index].SclkDid = (u8)dividers.post_div; |
pi->graphics_level[index].SclkFrequency = cpu_to_be32(sclk); |
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) |
{ |
return 6200 - (voltage * 25); |
} |
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 = 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); |
} |
static int kv_set_vid(struct radeon_device *rdev, u32 index, u32 vid) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->graphics_level[index].VoltageDownH = (u8)pi->voltage_drop_t; |
pi->graphics_level[index].MinVddNb = |
cpu_to_be32(kv_convert_2bit_index_to_voltage(rdev, vid)); |
return 0; |
} |
static int kv_set_at(struct radeon_device *rdev, u32 index, u32 at) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->graphics_level[index].AT = cpu_to_be16((u16)at); |
return 0; |
} |
static void kv_dpm_power_level_enable(struct radeon_device *rdev, |
u32 index, bool enable) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->graphics_level[index].EnabledForActivity = enable ? 1 : 0; |
} |
static void kv_start_dpm(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(GENERAL_PWRMGT); |
tmp |= GLOBAL_PWRMGT_EN; |
WREG32_SMC(GENERAL_PWRMGT, tmp); |
kv_smc_dpm_enable(rdev, true); |
} |
static void kv_stop_dpm(struct radeon_device *rdev) |
{ |
kv_smc_dpm_enable(rdev, false); |
} |
static void kv_start_am(struct radeon_device *rdev) |
{ |
u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL); |
sclk_pwrmgt_cntl &= ~(RESET_SCLK_CNT | RESET_BUSY_CNT); |
sclk_pwrmgt_cntl |= DYNAMIC_PM_EN; |
WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl); |
} |
static void kv_reset_am(struct radeon_device *rdev) |
{ |
u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL); |
sclk_pwrmgt_cntl |= (RESET_SCLK_CNT | RESET_BUSY_CNT); |
WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl); |
} |
static int kv_freeze_sclk_dpm(struct radeon_device *rdev, bool freeze) |
{ |
return kv_notify_message_to_smu(rdev, freeze ? |
PPSMC_MSG_SCLKDPM_FreezeLevel : PPSMC_MSG_SCLKDPM_UnfreezeLevel); |
} |
static int kv_force_lowest_valid(struct radeon_device *rdev) |
{ |
return kv_force_dpm_lowest(rdev); |
} |
static int kv_unforce_levels(struct radeon_device *rdev) |
{ |
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); |
} |
static int kv_update_sclk_t(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 low_sclk_interrupt_t = 0; |
int ret = 0; |
if (pi->caps_sclk_throttle_low_notification) { |
low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t); |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, LowSclkInterruptT), |
(u8 *)&low_sclk_interrupt_t, |
sizeof(u32), pi->sram_end); |
} |
return ret; |
} |
static int kv_program_bootup_state(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i; |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
if (table && table->count) { |
for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { |
if (table->entries[i].clk == pi->boot_pl.sclk) |
break; |
} |
pi->graphics_boot_level = (u8)i; |
kv_dpm_power_level_enable(rdev, i, true); |
} else { |
struct sumo_sclk_voltage_mapping_table *table = |
&pi->sys_info.sclk_voltage_mapping_table; |
if (table->num_max_dpm_entries == 0) |
return -EINVAL; |
for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { |
if (table->entries[i].sclk_frequency == pi->boot_pl.sclk) |
break; |
} |
pi->graphics_boot_level = (u8)i; |
kv_dpm_power_level_enable(rdev, i, true); |
} |
return 0; |
} |
static int kv_enable_auto_thermal_throttling(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
pi->graphics_therm_throttle_enable = 1; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, GraphicsThermThrottleEnable), |
&pi->graphics_therm_throttle_enable, |
sizeof(u8), pi->sram_end); |
return ret; |
} |
static int kv_upload_dpm_settings(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, GraphicsLevel), |
(u8 *)&pi->graphics_level, |
sizeof(SMU7_Fusion_GraphicsLevel) * SMU7_MAX_LEVELS_GRAPHICS, |
pi->sram_end); |
if (ret) |
return ret; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, GraphicsDpmLevelCount), |
&pi->graphics_dpm_level_count, |
sizeof(u8), pi->sram_end); |
return ret; |
} |
static u32 kv_get_clock_difference(u32 a, u32 b) |
{ |
return (a >= b) ? a - b : b - a; |
} |
static u32 kv_get_clk_bypass(struct radeon_device *rdev, u32 clk) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 value; |
if (pi->caps_enable_dfs_bypass) { |
if (kv_get_clock_difference(clk, 40000) < 200) |
value = 3; |
else if (kv_get_clock_difference(clk, 30000) < 200) |
value = 2; |
else if (kv_get_clock_difference(clk, 20000) < 200) |
value = 7; |
else if (kv_get_clock_difference(clk, 15000) < 200) |
value = 6; |
else if (kv_get_clock_difference(clk, 10000) < 200) |
value = 8; |
else |
value = 0; |
} else { |
value = 0; |
} |
return value; |
} |
static int kv_populate_uvd_table(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_uvd_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; |
struct atom_clock_dividers dividers; |
int ret; |
u32 i; |
if (table == NULL || table->count == 0) |
return 0; |
pi->uvd_level_count = 0; |
for (i = 0; i < table->count; i++) { |
if (pi->high_voltage_t && |
(pi->high_voltage_t < table->entries[i].v)) |
break; |
pi->uvd_level[i].VclkFrequency = cpu_to_be32(table->entries[i].vclk); |
pi->uvd_level[i].DclkFrequency = cpu_to_be32(table->entries[i].dclk); |
pi->uvd_level[i].MinVddNb = cpu_to_be16(table->entries[i].v); |
pi->uvd_level[i].VClkBypassCntl = |
(u8)kv_get_clk_bypass(rdev, table->entries[i].vclk); |
pi->uvd_level[i].DClkBypassCntl = |
(u8)kv_get_clk_bypass(rdev, table->entries[i].dclk); |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
table->entries[i].vclk, false, ÷rs); |
if (ret) |
return ret; |
pi->uvd_level[i].VclkDivider = (u8)dividers.post_div; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
table->entries[i].dclk, false, ÷rs); |
if (ret) |
return ret; |
pi->uvd_level[i].DclkDivider = (u8)dividers.post_div; |
pi->uvd_level_count++; |
} |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, UvdLevelCount), |
(u8 *)&pi->uvd_level_count, |
sizeof(u8), pi->sram_end); |
if (ret) |
return ret; |
pi->uvd_interval = 1; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, UVDInterval), |
&pi->uvd_interval, |
sizeof(u8), pi->sram_end); |
if (ret) |
return ret; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, UvdLevel), |
(u8 *)&pi->uvd_level, |
sizeof(SMU7_Fusion_UvdLevel) * SMU7_MAX_LEVELS_UVD, |
pi->sram_end); |
return ret; |
} |
static int kv_populate_vce_table(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
u32 i; |
struct radeon_vce_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; |
struct atom_clock_dividers dividers; |
if (table == NULL || table->count == 0) |
return 0; |
pi->vce_level_count = 0; |
for (i = 0; i < table->count; i++) { |
if (pi->high_voltage_t && |
pi->high_voltage_t < table->entries[i].v) |
break; |
pi->vce_level[i].Frequency = cpu_to_be32(table->entries[i].evclk); |
pi->vce_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); |
pi->vce_level[i].ClkBypassCntl = |
(u8)kv_get_clk_bypass(rdev, table->entries[i].evclk); |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
table->entries[i].evclk, false, ÷rs); |
if (ret) |
return ret; |
pi->vce_level[i].Divider = (u8)dividers.post_div; |
pi->vce_level_count++; |
} |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, VceLevelCount), |
(u8 *)&pi->vce_level_count, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
pi->vce_interval = 1; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, VCEInterval), |
(u8 *)&pi->vce_interval, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, VceLevel), |
(u8 *)&pi->vce_level, |
sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_VCE, |
pi->sram_end); |
return ret; |
} |
static int kv_populate_samu_table(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; |
struct atom_clock_dividers dividers; |
int ret; |
u32 i; |
if (table == NULL || table->count == 0) |
return 0; |
pi->samu_level_count = 0; |
for (i = 0; i < table->count; i++) { |
if (pi->high_voltage_t && |
pi->high_voltage_t < table->entries[i].v) |
break; |
pi->samu_level[i].Frequency = cpu_to_be32(table->entries[i].clk); |
pi->samu_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); |
pi->samu_level[i].ClkBypassCntl = |
(u8)kv_get_clk_bypass(rdev, table->entries[i].clk); |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
table->entries[i].clk, false, ÷rs); |
if (ret) |
return ret; |
pi->samu_level[i].Divider = (u8)dividers.post_div; |
pi->samu_level_count++; |
} |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, SamuLevelCount), |
(u8 *)&pi->samu_level_count, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
pi->samu_interval = 1; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, SAMUInterval), |
(u8 *)&pi->samu_interval, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, SamuLevel), |
(u8 *)&pi->samu_level, |
sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_SAMU, |
pi->sram_end); |
if (ret) |
return ret; |
return ret; |
} |
static int kv_populate_acp_table(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; |
struct atom_clock_dividers dividers; |
int ret; |
u32 i; |
if (table == NULL || table->count == 0) |
return 0; |
pi->acp_level_count = 0; |
for (i = 0; i < table->count; i++) { |
pi->acp_level[i].Frequency = cpu_to_be32(table->entries[i].clk); |
pi->acp_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
table->entries[i].clk, false, ÷rs); |
if (ret) |
return ret; |
pi->acp_level[i].Divider = (u8)dividers.post_div; |
pi->acp_level_count++; |
} |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, AcpLevelCount), |
(u8 *)&pi->acp_level_count, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
pi->acp_interval = 1; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, ACPInterval), |
(u8 *)&pi->acp_interval, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, AcpLevel), |
(u8 *)&pi->acp_level, |
sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_ACP, |
pi->sram_end); |
if (ret) |
return ret; |
return ret; |
} |
static void kv_calculate_dfs_bypass_settings(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i; |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
if (table && table->count) { |
for (i = 0; i < pi->graphics_dpm_level_count; i++) { |
if (pi->caps_enable_dfs_bypass) { |
if (kv_get_clock_difference(table->entries[i].clk, 40000) < 200) |
pi->graphics_level[i].ClkBypassCntl = 3; |
else if (kv_get_clock_difference(table->entries[i].clk, 30000) < 200) |
pi->graphics_level[i].ClkBypassCntl = 2; |
else if (kv_get_clock_difference(table->entries[i].clk, 26600) < 200) |
pi->graphics_level[i].ClkBypassCntl = 7; |
else if (kv_get_clock_difference(table->entries[i].clk , 20000) < 200) |
pi->graphics_level[i].ClkBypassCntl = 6; |
else if (kv_get_clock_difference(table->entries[i].clk , 10000) < 200) |
pi->graphics_level[i].ClkBypassCntl = 8; |
else |
pi->graphics_level[i].ClkBypassCntl = 0; |
} else { |
pi->graphics_level[i].ClkBypassCntl = 0; |
} |
} |
} else { |
struct sumo_sclk_voltage_mapping_table *table = |
&pi->sys_info.sclk_voltage_mapping_table; |
for (i = 0; i < pi->graphics_dpm_level_count; i++) { |
if (pi->caps_enable_dfs_bypass) { |
if (kv_get_clock_difference(table->entries[i].sclk_frequency, 40000) < 200) |
pi->graphics_level[i].ClkBypassCntl = 3; |
else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 30000) < 200) |
pi->graphics_level[i].ClkBypassCntl = 2; |
else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 26600) < 200) |
pi->graphics_level[i].ClkBypassCntl = 7; |
else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 20000) < 200) |
pi->graphics_level[i].ClkBypassCntl = 6; |
else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 10000) < 200) |
pi->graphics_level[i].ClkBypassCntl = 8; |
else |
pi->graphics_level[i].ClkBypassCntl = 0; |
} else { |
pi->graphics_level[i].ClkBypassCntl = 0; |
} |
} |
} |
} |
static int kv_enable_ulv(struct radeon_device *rdev, bool enable) |
{ |
return kv_notify_message_to_smu(rdev, enable ? |
PPSMC_MSG_EnableULV : PPSMC_MSG_DisableULV); |
} |
static void kv_reset_acp_boot_level(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->acp_boot_level = 0xff; |
} |
static void kv_update_current_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct kv_ps *new_ps = kv_get_ps(rps); |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->current_rps = *rps; |
pi->current_ps = *new_ps; |
pi->current_rps.ps_priv = &pi->current_ps; |
} |
static void kv_update_requested_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct kv_ps *new_ps = kv_get_ps(rps); |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->requested_rps = *rps; |
pi->requested_ps = *new_ps; |
pi->requested_rps.ps_priv = &pi->requested_ps; |
} |
void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
if (pi->bapm_enable) { |
ret = kv_smc_bapm_enable(rdev, enable); |
if (ret) |
DRM_ERROR("kv_smc_bapm_enable failed\n"); |
} |
} |
int kv_dpm_enable(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret; |
ret = kv_process_firmware_header(rdev); |
if (ret) { |
DRM_ERROR("kv_process_firmware_header failed\n"); |
return ret; |
} |
kv_init_fps_limits(rdev); |
kv_init_graphics_levels(rdev); |
ret = kv_program_bootup_state(rdev); |
if (ret) { |
DRM_ERROR("kv_program_bootup_state failed\n"); |
return ret; |
} |
kv_calculate_dfs_bypass_settings(rdev); |
ret = kv_upload_dpm_settings(rdev); |
if (ret) { |
DRM_ERROR("kv_upload_dpm_settings failed\n"); |
return ret; |
} |
ret = kv_populate_uvd_table(rdev); |
if (ret) { |
DRM_ERROR("kv_populate_uvd_table failed\n"); |
return ret; |
} |
ret = kv_populate_vce_table(rdev); |
if (ret) { |
DRM_ERROR("kv_populate_vce_table failed\n"); |
return ret; |
} |
ret = kv_populate_samu_table(rdev); |
if (ret) { |
DRM_ERROR("kv_populate_samu_table failed\n"); |
return ret; |
} |
ret = kv_populate_acp_table(rdev); |
if (ret) { |
DRM_ERROR("kv_populate_acp_table failed\n"); |
return ret; |
} |
kv_program_vc(rdev); |
#if 0 |
kv_initialize_hardware_cac_manager(rdev); |
#endif |
kv_start_am(rdev); |
if (pi->enable_auto_thermal_throttling) { |
ret = kv_enable_auto_thermal_throttling(rdev); |
if (ret) { |
DRM_ERROR("kv_enable_auto_thermal_throttling failed\n"); |
return ret; |
} |
} |
ret = kv_enable_dpm_voltage_scaling(rdev); |
if (ret) { |
DRM_ERROR("kv_enable_dpm_voltage_scaling failed\n"); |
return ret; |
} |
ret = kv_set_dpm_interval(rdev); |
if (ret) { |
DRM_ERROR("kv_set_dpm_interval failed\n"); |
return ret; |
} |
ret = kv_set_dpm_boot_state(rdev); |
if (ret) { |
DRM_ERROR("kv_set_dpm_boot_state failed\n"); |
return ret; |
} |
ret = kv_enable_ulv(rdev, true); |
if (ret) { |
DRM_ERROR("kv_enable_ulv failed\n"); |
return ret; |
} |
kv_start_dpm(rdev); |
ret = kv_enable_didt(rdev, true); |
if (ret) { |
DRM_ERROR("kv_enable_didt failed\n"); |
return ret; |
} |
ret = kv_enable_smc_cac(rdev, true); |
if (ret) { |
DRM_ERROR("kv_enable_smc_cac failed\n"); |
return ret; |
} |
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); |
if (ret) { |
DRM_ERROR("kv_set_thermal_temperature_range failed\n"); |
return ret; |
} |
rdev->irq.dpm_thermal = true; |
radeon_irq_set(rdev); |
} |
/* 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); |
return ret; |
} |
void kv_dpm_disable(struct radeon_device *rdev) |
{ |
kv_smc_bapm_enable(rdev, false); |
/* powerup blocks */ |
kv_dpm_powergate_acp(rdev, false); |
kv_dpm_powergate_samu(rdev, false); |
kv_dpm_powergate_vce(rdev, false); |
kv_dpm_powergate_uvd(rdev, false); |
kv_enable_smc_cac(rdev, false); |
kv_enable_didt(rdev, false); |
kv_clear_vc(rdev); |
kv_stop_dpm(rdev); |
kv_enable_ulv(rdev, false); |
kv_reset_am(rdev); |
kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); |
} |
#if 0 |
static int kv_write_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 value) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
return kv_copy_bytes_to_smc(rdev, pi->soft_regs_start + reg_offset, |
(u8 *)&value, sizeof(u16), pi->sram_end); |
} |
static int kv_read_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 *value) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
return kv_read_smc_sram_dword(rdev, pi->soft_regs_start + reg_offset, |
value, pi->sram_end); |
} |
#endif |
static void kv_init_sclk_t(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->low_sclk_interrupt_t = 0; |
} |
static int kv_init_fps_limits(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret = 0; |
if (pi->caps_fps) { |
u16 tmp; |
tmp = 45; |
pi->fps_high_t = cpu_to_be16(tmp); |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, FpsHighT), |
(u8 *)&pi->fps_high_t, |
sizeof(u16), pi->sram_end); |
tmp = 30; |
pi->fps_low_t = cpu_to_be16(tmp); |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, FpsLowT), |
(u8 *)&pi->fps_low_t, |
sizeof(u16), pi->sram_end); |
} |
return ret; |
} |
static void kv_init_powergate_state(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->uvd_power_gated = false; |
pi->vce_power_gated = false; |
pi->samu_power_gated = false; |
pi->acp_power_gated = false; |
} |
static int kv_enable_uvd_dpm(struct radeon_device *rdev, bool enable) |
{ |
return kv_notify_message_to_smu(rdev, enable ? |
PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable); |
} |
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); |
} |
static int kv_enable_samu_dpm(struct radeon_device *rdev, bool enable) |
{ |
return kv_notify_message_to_smu(rdev, enable ? |
PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable); |
} |
static int kv_enable_acp_dpm(struct radeon_device *rdev, bool enable) |
{ |
return kv_notify_message_to_smu(rdev, enable ? |
PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable); |
} |
static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
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 (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), |
(uint8_t *)&pi->uvd_boot_level, |
sizeof(u8), pi->sram_end); |
if (ret) |
return ret; |
kv_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_UVDDPM_SetEnabledMask, |
mask); |
} |
return kv_enable_uvd_dpm(rdev, !gate); |
} |
static u8 kv_get_vce_boot_level(struct radeon_device *rdev, u32 evclk) |
{ |
u8 i; |
struct radeon_vce_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; |
for (i = 0; i < table->count; i++) { |
if (table->entries[i].evclk >= evclk) |
break; |
} |
return i; |
} |
static int kv_update_vce_dpm(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_vce_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; |
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 |
pi->vce_boot_level = kv_get_vce_boot_level(rdev, radeon_new_state->evclk); |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, VceBootLevel), |
(u8 *)&pi->vce_boot_level, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
if (pi->caps_stable_p_state) |
kv_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_VCEDPM_SetEnabledMask, |
(1 << pi->vce_boot_level)); |
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; |
} |
static int kv_update_samu_dpm(struct radeon_device *rdev, bool gate) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; |
int ret; |
if (!gate) { |
if (pi->caps_stable_p_state) |
pi->samu_boot_level = table->count - 1; |
else |
pi->samu_boot_level = 0; |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, SamuBootLevel), |
(u8 *)&pi->samu_boot_level, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
if (pi->caps_stable_p_state) |
kv_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_SAMUDPM_SetEnabledMask, |
(1 << pi->samu_boot_level)); |
} |
return kv_enable_samu_dpm(rdev, !gate); |
} |
static u8 kv_get_acp_boot_level(struct radeon_device *rdev) |
{ |
u8 i; |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; |
for (i = 0; i < table->count; i++) { |
if (table->entries[i].clk >= 0) /* XXX */ |
break; |
} |
if (i >= table->count) |
i = table->count - 1; |
return i; |
} |
static void kv_update_acp_boot_level(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u8 acp_boot_level; |
if (!pi->caps_stable_p_state) { |
acp_boot_level = kv_get_acp_boot_level(rdev); |
if (acp_boot_level != pi->acp_boot_level) { |
pi->acp_boot_level = acp_boot_level; |
kv_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_ACPDPM_SetEnabledMask, |
(1 << pi->acp_boot_level)); |
} |
} |
} |
static int kv_update_acp_dpm(struct radeon_device *rdev, bool gate) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; |
int ret; |
if (!gate) { |
if (pi->caps_stable_p_state) |
pi->acp_boot_level = table->count - 1; |
else |
pi->acp_boot_level = kv_get_acp_boot_level(rdev); |
ret = kv_copy_bytes_to_smc(rdev, |
pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, AcpBootLevel), |
(u8 *)&pi->acp_boot_level, |
sizeof(u8), |
pi->sram_end); |
if (ret) |
return ret; |
if (pi->caps_stable_p_state) |
kv_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_ACPDPM_SetEnabledMask, |
(1 << pi->acp_boot_level)); |
} |
return kv_enable_acp_dpm(rdev, !gate); |
} |
void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
if (pi->uvd_power_gated == gate) |
return; |
pi->uvd_power_gated = gate; |
if (gate) { |
if (pi->caps_uvd_pg) { |
uvd_v1_0_stop(rdev); |
cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, false); |
} |
kv_update_uvd_dpm(rdev, gate); |
if (pi->caps_uvd_pg) |
kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerOFF); |
} else { |
if (pi->caps_uvd_pg) { |
kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerON); |
uvd_v4_2_resume(rdev); |
uvd_v1_0_start(rdev); |
cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, true); |
} |
kv_update_uvd_dpm(rdev, gate); |
} |
} |
static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
if (pi->vce_power_gated == gate) |
return; |
pi->vce_power_gated = gate; |
if (gate) { |
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) { |
kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerON); |
vce_v2_0_resume(rdev); |
vce_v1_0_start(rdev); |
} |
} |
} |
static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
if (pi->samu_power_gated == gate) |
return; |
pi->samu_power_gated = gate; |
if (gate) { |
kv_update_samu_dpm(rdev, true); |
if (pi->caps_samu_pg) |
kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerOFF); |
} else { |
if (pi->caps_samu_pg) |
kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerON); |
kv_update_samu_dpm(rdev, false); |
} |
} |
static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
if (pi->acp_power_gated == gate) |
return; |
if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) |
return; |
pi->acp_power_gated = gate; |
if (gate) { |
kv_update_acp_dpm(rdev, true); |
if (pi->caps_acp_pg) |
kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerOFF); |
} else { |
if (pi->caps_acp_pg) |
kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerON); |
kv_update_acp_dpm(rdev, false); |
} |
} |
static void kv_set_valid_clock_range(struct radeon_device *rdev, |
struct radeon_ps *new_rps) |
{ |
struct kv_ps *new_ps = kv_get_ps(new_rps); |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i; |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
if (table && table->count) { |
for (i = 0; i < pi->graphics_dpm_level_count; i++) { |
if ((table->entries[i].clk >= new_ps->levels[0].sclk) || |
(i == (pi->graphics_dpm_level_count - 1))) { |
pi->lowest_valid = i; |
break; |
} |
} |
for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { |
if (table->entries[i].clk <= new_ps->levels[new_ps->num_levels - 1].sclk) |
break; |
} |
pi->highest_valid = i; |
if (pi->lowest_valid > pi->highest_valid) { |
if ((new_ps->levels[0].sclk - table->entries[pi->highest_valid].clk) > |
(table->entries[pi->lowest_valid].clk - new_ps->levels[new_ps->num_levels - 1].sclk)) |
pi->highest_valid = pi->lowest_valid; |
else |
pi->lowest_valid = pi->highest_valid; |
} |
} else { |
struct sumo_sclk_voltage_mapping_table *table = |
&pi->sys_info.sclk_voltage_mapping_table; |
for (i = 0; i < (int)pi->graphics_dpm_level_count; i++) { |
if (table->entries[i].sclk_frequency >= new_ps->levels[0].sclk || |
i == (int)(pi->graphics_dpm_level_count - 1)) { |
pi->lowest_valid = i; |
break; |
} |
} |
for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { |
if (table->entries[i].sclk_frequency <= |
new_ps->levels[new_ps->num_levels - 1].sclk) |
break; |
} |
pi->highest_valid = i; |
if (pi->lowest_valid > pi->highest_valid) { |
if ((new_ps->levels[0].sclk - |
table->entries[pi->highest_valid].sclk_frequency) > |
(table->entries[pi->lowest_valid].sclk_frequency - |
new_ps->levels[new_ps->num_levels -1].sclk)) |
pi->highest_valid = pi->lowest_valid; |
else |
pi->lowest_valid = pi->highest_valid; |
} |
} |
} |
static int kv_update_dfs_bypass_settings(struct radeon_device *rdev, |
struct radeon_ps *new_rps) |
{ |
struct kv_ps *new_ps = kv_get_ps(new_rps); |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret = 0; |
u8 clk_bypass_cntl; |
if (pi->caps_enable_dfs_bypass) { |
clk_bypass_cntl = new_ps->need_dfs_bypass ? |
pi->graphics_level[pi->graphics_boot_level].ClkBypassCntl : 0; |
ret = kv_copy_bytes_to_smc(rdev, |
(pi->dpm_table_start + |
offsetof(SMU7_Fusion_DpmTable, GraphicsLevel) + |
(pi->graphics_boot_level * sizeof(SMU7_Fusion_GraphicsLevel)) + |
offsetof(SMU7_Fusion_GraphicsLevel, ClkBypassCntl)), |
&clk_bypass_cntl, |
sizeof(u8), pi->sram_end); |
} |
return ret; |
} |
static int kv_enable_nb_dpm(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
int ret = 0; |
if (pi->enable_nb_dpm && !pi->nb_dpm_enabled) { |
ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Enable); |
if (ret == 0) |
pi->nb_dpm_enabled = true; |
} |
return ret; |
} |
int kv_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
int ret; |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
ret = kv_force_dpm_highest(rdev); |
if (ret) |
return ret; |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
ret = kv_force_dpm_lowest(rdev); |
if (ret) |
return ret; |
} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { |
ret = kv_unforce_levels(rdev); |
if (ret) |
return ret; |
} |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
int kv_dpm_pre_set_power_state(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; |
struct radeon_ps *new_ps = &requested_ps; |
kv_update_requested_ps(rdev, new_ps); |
kv_apply_state_adjust_rules(rdev, |
&pi->requested_rps, |
&pi->current_rps); |
return 0; |
} |
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; |
int ret; |
if (pi->bapm_enable) { |
ret = kv_smc_bapm_enable(rdev, rdev->pm.dpm.ac_power); |
if (ret) { |
DRM_ERROR("kv_smc_bapm_enable failed\n"); |
return ret; |
} |
} |
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); |
ret = kv_calculate_ds_divider(rdev); |
if (ret) { |
DRM_ERROR("kv_calculate_ds_divider failed\n"); |
return ret; |
} |
kv_calculate_nbps_level_settings(rdev); |
kv_calculate_dpm_settings(rdev); |
kv_force_lowest_valid(rdev); |
kv_enable_new_levels(rdev); |
kv_upload_dpm_settings(rdev); |
kv_program_nbps_index_settings(rdev, new_ps); |
kv_unforce_levels(rdev); |
kv_set_enabled_levels(rdev); |
kv_force_lowest_valid(rdev); |
kv_unforce_levels(rdev); |
ret = kv_update_vce_dpm(rdev, new_ps, old_ps); |
if (ret) { |
DRM_ERROR("kv_update_vce_dpm failed\n"); |
return ret; |
} |
kv_update_sclk_t(rdev); |
if (rdev->family == CHIP_MULLINS) |
kv_enable_nb_dpm(rdev); |
} |
} else { |
if (pi->enable_dpm) { |
kv_set_valid_clock_range(rdev, new_ps); |
kv_update_dfs_bypass_settings(rdev, new_ps); |
ret = kv_calculate_ds_divider(rdev); |
if (ret) { |
DRM_ERROR("kv_calculate_ds_divider failed\n"); |
return ret; |
} |
kv_calculate_nbps_level_settings(rdev); |
kv_calculate_dpm_settings(rdev); |
kv_freeze_sclk_dpm(rdev, true); |
kv_upload_dpm_settings(rdev); |
kv_program_nbps_index_settings(rdev, new_ps); |
kv_freeze_sclk_dpm(rdev, false); |
kv_set_enabled_levels(rdev); |
ret = kv_update_vce_dpm(rdev, new_ps, old_ps); |
if (ret) { |
DRM_ERROR("kv_update_vce_dpm failed\n"); |
return ret; |
} |
kv_update_acp_boot_level(rdev); |
kv_update_sclk_t(rdev); |
kv_enable_nb_dpm(rdev); |
} |
} |
return 0; |
} |
void kv_dpm_post_set_power_state(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_ps *new_ps = &pi->requested_rps; |
kv_update_current_ps(rdev, new_ps); |
} |
void kv_dpm_setup_asic(struct radeon_device *rdev) |
{ |
sumo_take_smu_control(rdev, true); |
kv_init_powergate_state(rdev); |
kv_init_sclk_t(rdev); |
} |
void kv_dpm_reset_asic(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { |
kv_force_lowest_valid(rdev); |
kv_init_graphics_levels(rdev); |
kv_program_bootup_state(rdev); |
kv_upload_dpm_settings(rdev); |
kv_force_lowest_valid(rdev); |
kv_unforce_levels(rdev); |
} else { |
kv_init_graphics_levels(rdev); |
kv_program_bootup_state(rdev); |
kv_freeze_sclk_dpm(rdev, true); |
kv_upload_dpm_settings(rdev); |
kv_freeze_sclk_dpm(rdev, false); |
kv_set_enabled_level(rdev, pi->graphics_boot_level); |
} |
} |
//XXX use sumo_dpm_display_configuration_changed |
static void kv_construct_max_power_limits_table(struct radeon_device *rdev, |
struct radeon_clock_and_voltage_limits *table) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
if (pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries > 0) { |
int idx = pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1; |
table->sclk = |
pi->sys_info.sclk_voltage_mapping_table.entries[idx].sclk_frequency; |
table->vddc = |
kv_convert_2bit_index_to_voltage(rdev, |
pi->sys_info.sclk_voltage_mapping_table.entries[idx].vid_2bit); |
} |
table->mclk = pi->sys_info.nbp_memory_clock[0]; |
} |
static void kv_patch_voltage_values(struct radeon_device *rdev) |
{ |
int i; |
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 (vce_table->count) { |
for (i = 0; i < vce_table->count; i++) |
vce_table->entries[i].v = |
kv_convert_8bit_index_to_voltage(rdev, |
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); |
} |
} |
static void kv_construct_boot_state(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->boot_pl.sclk = pi->sys_info.bootup_sclk; |
pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index; |
pi->boot_pl.ds_divider_index = 0; |
pi->boot_pl.ss_divider_index = 0; |
pi->boot_pl.allow_gnb_slow = 1; |
pi->boot_pl.force_nbp_state = 0; |
pi->boot_pl.display_wm = 0; |
pi->boot_pl.vce_wm = 0; |
} |
static int kv_force_dpm_highest(struct radeon_device *rdev) |
{ |
int ret; |
u32 enable_mask, i; |
ret = kv_dpm_get_enable_mask(rdev, &enable_mask); |
if (ret) |
return ret; |
for (i = SMU7_MAX_LEVELS_GRAPHICS - 1; i > 0; i--) { |
if (enable_mask & (1 << i)) |
break; |
} |
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); |
} |
static int kv_force_dpm_lowest(struct radeon_device *rdev) |
{ |
int ret; |
u32 enable_mask, i; |
ret = kv_dpm_get_enable_mask(rdev, &enable_mask); |
if (ret) |
return ret; |
for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { |
if (enable_mask & (1 << i)) |
break; |
} |
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); |
} |
static u8 kv_get_sleep_divider_id_from_clock(struct radeon_device *rdev, |
u32 sclk, u32 min_sclk_in_sr) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i; |
u32 temp; |
u32 min = (min_sclk_in_sr > KV_MINIMUM_ENGINE_CLOCK) ? |
min_sclk_in_sr : KV_MINIMUM_ENGINE_CLOCK; |
if (sclk < min) |
return 0; |
if (!pi->caps_sclk_ds) |
return 0; |
for (i = KV_MAX_DEEPSLEEP_DIVIDER_ID; i > 0; i--) { |
temp = sclk / sumo_get_sleep_divider_from_id(i); |
if (temp >= min) |
break; |
} |
return (u8)i; |
} |
static int kv_get_high_voltage_limit(struct radeon_device *rdev, int *limit) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
int i; |
if (table && table->count) { |
for (i = table->count - 1; i >= 0; i--) { |
if (pi->high_voltage_t && |
(kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v) <= |
pi->high_voltage_t)) { |
*limit = i; |
return 0; |
} |
} |
} else { |
struct sumo_sclk_voltage_mapping_table *table = |
&pi->sys_info.sclk_voltage_mapping_table; |
for (i = table->num_max_dpm_entries - 1; i >= 0; i--) { |
if (pi->high_voltage_t && |
(kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit) <= |
pi->high_voltage_t)) { |
*limit = i; |
return 0; |
} |
} |
} |
*limit = 0; |
return 0; |
} |
static void kv_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct kv_ps *ps = kv_get_ps(new_rps); |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 min_sclk = 10000; /* ??? */ |
u32 sclk, mclk = 0; |
int i, limit; |
bool force_high; |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
u32 stable_p_state_sclk = 0; |
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; |
if (pi->caps_stable_p_state) { |
stable_p_state_sclk = (max_limits->sclk * 75) / 100; |
for (i = table->count - 1; i >= 0; i++) { |
if (stable_p_state_sclk >= table->entries[i].clk) { |
stable_p_state_sclk = table->entries[i].clk; |
break; |
} |
} |
if (i > 0) |
stable_p_state_sclk = table->entries[0].clk; |
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++) { |
if (ps->levels[i].sclk < sclk) |
ps->levels[i].sclk = sclk; |
} |
if (table && table->count) { |
for (i = 0; i < ps->num_levels; i++) { |
if (pi->high_voltage_t && |
(pi->high_voltage_t < |
kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { |
kv_get_high_voltage_limit(rdev, &limit); |
ps->levels[i].sclk = table->entries[limit].clk; |
} |
} |
} else { |
struct sumo_sclk_voltage_mapping_table *table = |
&pi->sys_info.sclk_voltage_mapping_table; |
for (i = 0; i < ps->num_levels; i++) { |
if (pi->high_voltage_t && |
(pi->high_voltage_t < |
kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { |
kv_get_high_voltage_limit(rdev, &limit); |
ps->levels[i].sclk = table->entries[limit].sclk_frequency; |
} |
} |
} |
if (pi->caps_stable_p_state) { |
for (i = 0; i < ps->num_levels; i++) { |
ps->levels[i].sclk = stable_p_state_sclk; |
} |
} |
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) |
pi->battery_state = true; |
else |
pi->battery_state = false; |
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; |
ps->dpmx_nb_ps_hi = 0x0; |
} else { |
ps->dpm0_pg_nb_ps_lo = 0x3; |
ps->dpm0_pg_nb_ps_hi = 0x0; |
ps->dpmx_nb_ps_lo = 0x3; |
ps->dpmx_nb_ps_hi = 0x0; |
if (pi->sys_info.nb_dpm_enable) { |
force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) || |
pi->video_start || (rdev->pm.dpm.new_active_crtc_count >= 3) || |
pi->disable_nb_ps3_in_battery; |
ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3; |
ps->dpm0_pg_nb_ps_hi = 0x2; |
ps->dpmx_nb_ps_lo = force_high ? 0x2 : 0x3; |
ps->dpmx_nb_ps_hi = 0x2; |
} |
} |
} |
static void kv_dpm_power_level_enabled_for_throttle(struct radeon_device *rdev, |
u32 index, bool enable) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
pi->graphics_level[index].EnabledForThrottle = enable ? 1 : 0; |
} |
static int kv_calculate_ds_divider(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 sclk_in_sr = 10000; /* ??? */ |
u32 i; |
if (pi->lowest_valid > pi->highest_valid) |
return -EINVAL; |
for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { |
pi->graphics_level[i].DeepSleepDivId = |
kv_get_sleep_divider_id_from_clock(rdev, |
be32_to_cpu(pi->graphics_level[i].SclkFrequency), |
sclk_in_sr); |
} |
return 0; |
} |
static int kv_calculate_nbps_level_settings(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i; |
bool force_high; |
struct radeon_clock_and_voltage_limits *max_limits = |
&rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
u32 mclk = max_limits->mclk; |
if (pi->lowest_valid > pi->highest_valid) |
return -EINVAL; |
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; |
pi->graphics_level[i].UpH = 0; |
} |
if (!pi->sys_info.nb_dpm_enable) |
return 0; |
force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) || |
(rdev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start); |
if (force_high) { |
for (i = pi->lowest_valid; i <= pi->highest_valid; i++) |
pi->graphics_level[i].GnbSlow = 0; |
} else { |
if (pi->battery_state) |
pi->graphics_level[0].ForceNbPs1 = 1; |
pi->graphics_level[1].GnbSlow = 0; |
pi->graphics_level[2].GnbSlow = 0; |
pi->graphics_level[3].GnbSlow = 0; |
pi->graphics_level[4].GnbSlow = 0; |
} |
} else { |
for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { |
pi->graphics_level[i].GnbSlow = 1; |
pi->graphics_level[i].ForceNbPs1 = 0; |
pi->graphics_level[i].UpH = 0; |
} |
if (pi->sys_info.nb_dpm_enable && pi->battery_state) { |
pi->graphics_level[pi->lowest_valid].UpH = 0x28; |
pi->graphics_level[pi->lowest_valid].GnbSlow = 0; |
if (pi->lowest_valid != pi->highest_valid) |
pi->graphics_level[pi->lowest_valid].ForceNbPs1 = 1; |
} |
} |
return 0; |
} |
static int kv_calculate_dpm_settings(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i; |
if (pi->lowest_valid > pi->highest_valid) |
return -EINVAL; |
for (i = pi->lowest_valid; i <= pi->highest_valid; i++) |
pi->graphics_level[i].DisplayWatermark = (i == pi->highest_valid) ? 1 : 0; |
return 0; |
} |
static void kv_init_graphics_levels(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i; |
struct radeon_clock_voltage_dependency_table *table = |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; |
if (table && table->count) { |
u32 vid_2bit; |
pi->graphics_dpm_level_count = 0; |
for (i = 0; i < table->count; i++) { |
if (pi->high_voltage_t && |
(pi->high_voltage_t < |
kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v))) |
break; |
kv_set_divider_value(rdev, i, table->entries[i].clk); |
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); |
pi->graphics_dpm_level_count++; |
} |
} else { |
struct sumo_sclk_voltage_mapping_table *table = |
&pi->sys_info.sclk_voltage_mapping_table; |
pi->graphics_dpm_level_count = 0; |
for (i = 0; i < table->num_max_dpm_entries; i++) { |
if (pi->high_voltage_t && |
pi->high_voltage_t < |
kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit)) |
break; |
kv_set_divider_value(rdev, i, table->entries[i].sclk_frequency); |
kv_set_vid(rdev, i, table->entries[i].vid_2bit); |
kv_set_at(rdev, i, pi->at[i]); |
kv_dpm_power_level_enabled_for_throttle(rdev, i, true); |
pi->graphics_dpm_level_count++; |
} |
} |
for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) |
kv_dpm_power_level_enable(rdev, i, false); |
} |
static void kv_enable_new_levels(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i; |
for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { |
if (i >= pi->lowest_valid && i <= pi->highest_valid) |
kv_dpm_power_level_enable(rdev, i, true); |
} |
} |
static int kv_set_enabled_level(struct radeon_device *rdev, u32 level) |
{ |
u32 new_mask = (1 << level); |
return kv_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_SCLKDPM_SetEnabledMask, |
new_mask); |
} |
static int kv_set_enabled_levels(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 i, new_mask = 0; |
for (i = pi->lowest_valid; i <= pi->highest_valid; i++) |
new_mask |= (1 << i); |
return kv_send_msg_to_smc_with_parameter(rdev, |
PPSMC_MSG_SCLKDPM_SetEnabledMask, |
new_mask); |
} |
static void kv_program_nbps_index_settings(struct radeon_device *rdev, |
struct radeon_ps *new_rps) |
{ |
struct kv_ps *new_ps = kv_get_ps(new_rps); |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 nbdpmconfig1; |
if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) |
return; |
if (pi->sys_info.nb_dpm_enable) { |
nbdpmconfig1 = RREG32_SMC(NB_DPM_CONFIG_1); |
nbdpmconfig1 &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | |
DpmXNbPsLo_MASK | DpmXNbPsHi_MASK); |
nbdpmconfig1 |= (Dpm0PgNbPsLo(new_ps->dpm0_pg_nb_ps_lo) | |
Dpm0PgNbPsHi(new_ps->dpm0_pg_nb_ps_hi) | |
DpmXNbPsLo(new_ps->dpmx_nb_ps_lo) | |
DpmXNbPsHi(new_ps->dpmx_nb_ps_hi)); |
WREG32_SMC(NB_DPM_CONFIG_1, nbdpmconfig1); |
} |
} |
static int kv_set_thermal_temperature_range(struct radeon_device *rdev, |
int min_temp, int max_temp) |
{ |
int low_temp = 0 * 1000; |
int high_temp = 255 * 1000; |
u32 tmp; |
if (low_temp < min_temp) |
low_temp = min_temp; |
if (high_temp > max_temp) |
high_temp = max_temp; |
if (high_temp < low_temp) { |
DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); |
return -EINVAL; |
} |
tmp = RREG32_SMC(CG_THERMAL_INT_CTRL); |
tmp &= ~(DIG_THERM_INTH_MASK | DIG_THERM_INTL_MASK); |
tmp |= (DIG_THERM_INTH(49 + (high_temp / 1000)) | |
DIG_THERM_INTL(49 + (low_temp / 1000))); |
WREG32_SMC(CG_THERMAL_INT_CTRL, tmp); |
rdev->pm.dpm.thermal.min_temp = low_temp; |
rdev->pm.dpm.thermal.max_temp = high_temp; |
return 0; |
} |
union igp_info { |
struct _ATOM_INTEGRATED_SYSTEM_INFO info; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; |
}; |
static int kv_parse_sys_info_table(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); |
union igp_info *igp_info; |
u8 frev, crev; |
u16 data_offset; |
int i; |
if (atom_parse_data_header(mode_info->atom_context, index, NULL, |
&frev, &crev, &data_offset)) { |
igp_info = (union igp_info *)(mode_info->atom_context->bios + |
data_offset); |
if (crev != 8) { |
DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); |
return -EINVAL; |
} |
pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_8.ulBootUpEngineClock); |
pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_8.ulBootUpUMAClock); |
pi->sys_info.bootup_nb_voltage_index = |
le16_to_cpu(igp_info->info_8.usBootUpNBVoltage); |
if (igp_info->info_8.ucHtcTmpLmt == 0) |
pi->sys_info.htc_tmp_lmt = 203; |
else |
pi->sys_info.htc_tmp_lmt = igp_info->info_8.ucHtcTmpLmt; |
if (igp_info->info_8.ucHtcHystLmt == 0) |
pi->sys_info.htc_hyst_lmt = 5; |
else |
pi->sys_info.htc_hyst_lmt = igp_info->info_8.ucHtcHystLmt; |
if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { |
DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); |
} |
if (le32_to_cpu(igp_info->info_8.ulSystemConfig) & (1 << 3)) |
pi->sys_info.nb_dpm_enable = true; |
else |
pi->sys_info.nb_dpm_enable = false; |
for (i = 0; i < KV_NUM_NBPSTATES; i++) { |
pi->sys_info.nbp_memory_clock[i] = |
le32_to_cpu(igp_info->info_8.ulNbpStateMemclkFreq[i]); |
pi->sys_info.nbp_n_clock[i] = |
le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]); |
} |
if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) & |
SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) |
pi->caps_enable_dfs_bypass = true; |
sumo_construct_sclk_voltage_mapping_table(rdev, |
&pi->sys_info.sclk_voltage_mapping_table, |
igp_info->info_8.sAvail_SCLK); |
sumo_construct_vid_mapping_table(rdev, |
&pi->sys_info.vid_mapping_table, |
igp_info->info_8.sAvail_SCLK); |
kv_construct_max_power_limits_table(rdev, |
&rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac); |
} |
return 0; |
} |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void kv_patch_boot_state(struct radeon_device *rdev, |
struct kv_ps *ps) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
ps->num_levels = 1; |
ps->levels[0] = pi->boot_pl; |
} |
static void kv_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, |
u8 table_rev) |
{ |
struct kv_ps *ps = kv_get_ps(rps); |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { |
rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); |
rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
rdev->pm.dpm.boot_ps = rps; |
kv_patch_boot_state(rdev, ps); |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void kv_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, int index, |
union pplib_clock_info *clock_info) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct kv_ps *ps = kv_get_ps(rps); |
struct kv_pl *pl = &ps->levels[index]; |
u32 sclk; |
sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); |
sclk |= clock_info->sumo.ucEngineClockHigh << 16; |
pl->sclk = sclk; |
pl->vddc_index = clock_info->sumo.vddcIndex; |
ps->num_levels = index + 1; |
if (pi->caps_sclk_ds) { |
pl->ds_divider_index = 5; |
pl->ss_divider_index = 5; |
} |
} |
static int kv_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i, j, k, non_clock_array_index, clock_array_index; |
union pplib_clock_info *clock_info; |
struct _StateArray *state_array; |
struct _ClockInfoArray *clock_info_array; |
struct _NonClockInfoArray *non_clock_info_array; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
u8 *power_state_offset; |
struct kv_ps *ps; |
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); |
state_array = (struct _StateArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset)); |
clock_info_array = (struct _ClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); |
non_clock_info_array = (struct _NonClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); |
rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * |
state_array->ucNumEntries, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
power_state_offset = (u8 *)state_array->states; |
for (i = 0; i < state_array->ucNumEntries; i++) { |
u8 *idx; |
power_state = (union pplib_power_state *)power_state_offset; |
non_clock_array_index = power_state->v2.nonClockInfoIndex; |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
&non_clock_info_array->nonClockInfo[non_clock_array_index]; |
if (!rdev->pm.power_state[i].clock_info) |
return -EINVAL; |
ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
k = 0; |
idx = (u8 *)&power_state->v2.clockInfoIndex[0]; |
for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { |
clock_array_index = idx[j]; |
if (clock_array_index >= clock_info_array->ucNumEntries) |
continue; |
if (k >= SUMO_MAX_HARDWARE_POWERLEVELS) |
break; |
clock_info = (union pplib_clock_info *) |
((u8 *)&clock_info_array->clockInfo[0] + |
(clock_array_index * clock_info_array->ucEntrySize)); |
kv_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], k, |
clock_info); |
k++; |
} |
kv_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info, |
non_clock_info_array->ucEntrySize); |
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; |
} |
int kv_dpm_init(struct radeon_device *rdev) |
{ |
struct kv_power_info *pi; |
int ret, i; |
pi = kzalloc(sizeof(struct kv_power_info), GFP_KERNEL); |
if (pi == NULL) |
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; |
for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) |
pi->at[i] = TRINITY_AT_DFLT; |
pi->sram_end = SMC_RAM_END; |
pi->enable_nb_dpm = true; |
pi->caps_power_containment = true; |
pi->caps_cac = true; |
pi->enable_didt = false; |
if (pi->enable_didt) { |
pi->caps_sq_ramping = true; |
pi->caps_db_ramping = true; |
pi->caps_td_ramping = true; |
pi->caps_tcp_ramping = true; |
} |
pi->caps_sclk_ds = true; |
pi->enable_auto_thermal_throttling = true; |
pi->disable_nb_ps3_in_battery = false; |
if (radeon_bapm == 0) |
pi->bapm_enable = false; |
else |
pi->bapm_enable = true; |
pi->voltage_drop_t = 0; |
pi->caps_sclk_throttle_low_notification = false; |
pi->caps_fps = false; /* true? */ |
pi->caps_uvd_pg = true; |
pi->caps_uvd_dpm = true; |
pi->caps_vce_pg = false; /* XXX true */ |
pi->caps_samu_pg = false; |
pi->caps_acp_pg = false; |
pi->caps_stable_p_state = false; |
ret = kv_parse_sys_info_table(rdev); |
if (ret) |
return ret; |
kv_patch_voltage_values(rdev); |
kv_construct_boot_state(rdev); |
ret = kv_parse_power_table(rdev); |
if (ret) |
return ret; |
pi->enable_dpm = true; |
return 0; |
} |
void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
u32 current_index = |
(RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >> |
CURR_SCLK_INDEX_SHIFT; |
u32 sclk, tmp; |
u16 vddc; |
if (current_index >= SMU__NUM_SCLK_DPM_STATE) { |
seq_printf(m, "invalid dpm profile %d\n", current_index); |
} else { |
sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency); |
tmp = (RREG32_SMC(SMU_VOLTAGE_STATUS) & SMU_VOLTAGE_CURRENT_LEVEL_MASK) >> |
SMU_VOLTAGE_CURRENT_LEVEL_SHIFT; |
vddc = kv_convert_8bit_index_to_voltage(rdev, (u16)tmp); |
seq_printf(m, "power level %d sclk: %u vddc: %u\n", |
current_index, sclk, vddc); |
} |
} |
void kv_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
int i; |
struct kv_ps *ps = kv_get_ps(rps); |
r600_dpm_print_class_info(rps->class, rps->class2); |
r600_dpm_print_cap_info(rps->caps); |
printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
for (i = 0; i < ps->num_levels; i++) { |
struct kv_pl *pl = &ps->levels[i]; |
printk("\t\tpower level %d sclk: %u vddc: %u\n", |
i, pl->sclk, |
kv_convert_8bit_index_to_voltage(rdev, pl->vddc_index)); |
} |
r600_dpm_print_ps_status(rdev, rps); |
} |
void kv_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
r600_free_extended_power_table(rdev); |
} |
void kv_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
} |
u32 kv_dpm_get_sclk(struct radeon_device *rdev, bool low) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
struct kv_ps *requested_state = kv_get_ps(&pi->requested_rps); |
if (low) |
return requested_state->levels[0].sclk; |
else |
return requested_state->levels[requested_state->num_levels - 1].sclk; |
} |
u32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct kv_power_info *pi = kv_get_pi(rdev); |
return pi->sys_info.bootup_uma_clk; |
} |
/drivers/video/drm/radeon/kv_dpm.h |
---|
0,0 → 1,200 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __KV_DPM_H__ |
#define __KV_DPM_H__ |
#define SMU__NUM_SCLK_DPM_STATE 8 |
#define SMU__NUM_MCLK_DPM_LEVELS 4 |
#define SMU__NUM_LCLK_DPM_LEVELS 8 |
#define SMU__NUM_PCIE_DPM_LEVELS 0 /* ??? */ |
#include "smu7_fusion.h" |
#include "trinity_dpm.h" |
#include "ppsmc.h" |
#define KV_NUM_NBPSTATES 4 |
enum kv_pt_config_reg_type { |
KV_CONFIGREG_MMR = 0, |
KV_CONFIGREG_SMC_IND, |
KV_CONFIGREG_DIDT_IND, |
KV_CONFIGREG_CACHE, |
KV_CONFIGREG_MAX |
}; |
struct kv_pt_config_reg { |
u32 offset; |
u32 mask; |
u32 shift; |
u32 value; |
enum kv_pt_config_reg_type type; |
}; |
struct kv_lcac_config_values { |
u32 block_id; |
u32 signal_id; |
u32 t; |
}; |
struct kv_lcac_config_reg { |
u32 cntl; |
u32 block_mask; |
u32 block_shift; |
u32 signal_mask; |
u32 signal_shift; |
u32 t_mask; |
u32 t_shift; |
u32 enable_mask; |
u32 enable_shift; |
}; |
struct kv_pl { |
u32 sclk; |
u8 vddc_index; |
u8 ds_divider_index; |
u8 ss_divider_index; |
u8 allow_gnb_slow; |
u8 force_nbp_state; |
u8 display_wm; |
u8 vce_wm; |
}; |
struct kv_ps { |
struct kv_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS]; |
u32 num_levels; |
bool need_dfs_bypass; |
u8 dpm0_pg_nb_ps_lo; |
u8 dpm0_pg_nb_ps_hi; |
u8 dpmx_nb_ps_lo; |
u8 dpmx_nb_ps_hi; |
}; |
struct kv_sys_info { |
u32 bootup_uma_clk; |
u32 bootup_sclk; |
u32 dentist_vco_freq; |
u32 nb_dpm_enable; |
u32 nbp_memory_clock[KV_NUM_NBPSTATES]; |
u32 nbp_n_clock[KV_NUM_NBPSTATES]; |
u16 bootup_nb_voltage_index; |
u8 htc_tmp_lmt; |
u8 htc_hyst_lmt; |
struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table; |
struct sumo_vid_mapping_table vid_mapping_table; |
u32 uma_channel_number; |
}; |
struct kv_power_info { |
u32 at[SUMO_MAX_HARDWARE_POWERLEVELS]; |
u32 voltage_drop_t; |
struct kv_sys_info sys_info; |
struct kv_pl boot_pl; |
bool enable_nb_ps_policy; |
bool disable_nb_ps3_in_battery; |
bool video_start; |
bool battery_state; |
u32 lowest_valid; |
u32 highest_valid; |
u16 high_voltage_t; |
bool cac_enabled; |
bool bapm_enable; |
/* smc offsets */ |
u32 sram_end; |
u32 dpm_table_start; |
u32 soft_regs_start; |
/* dpm SMU tables */ |
u8 graphics_dpm_level_count; |
u8 uvd_level_count; |
u8 vce_level_count; |
u8 acp_level_count; |
u8 samu_level_count; |
u16 fps_high_t; |
SMU7_Fusion_GraphicsLevel graphics_level[SMU__NUM_SCLK_DPM_STATE]; |
SMU7_Fusion_ACPILevel acpi_level; |
SMU7_Fusion_UvdLevel uvd_level[SMU7_MAX_LEVELS_UVD]; |
SMU7_Fusion_ExtClkLevel vce_level[SMU7_MAX_LEVELS_VCE]; |
SMU7_Fusion_ExtClkLevel acp_level[SMU7_MAX_LEVELS_ACP]; |
SMU7_Fusion_ExtClkLevel samu_level[SMU7_MAX_LEVELS_SAMU]; |
u8 uvd_boot_level; |
u8 vce_boot_level; |
u8 acp_boot_level; |
u8 samu_boot_level; |
u8 uvd_interval; |
u8 vce_interval; |
u8 acp_interval; |
u8 samu_interval; |
u8 graphics_boot_level; |
u8 graphics_interval; |
u8 graphics_therm_throttle_enable; |
u8 graphics_voltage_change_enable; |
u8 graphics_clk_slow_enable; |
u8 graphics_clk_slow_divider; |
u8 fps_low_t; |
u32 low_sclk_interrupt_t; |
bool uvd_power_gated; |
bool vce_power_gated; |
bool acp_power_gated; |
bool samu_power_gated; |
bool nb_dpm_enabled; |
/* flags */ |
bool enable_didt; |
bool enable_dpm; |
bool enable_auto_thermal_throttling; |
bool enable_nb_dpm; |
/* caps */ |
bool caps_cac; |
bool caps_power_containment; |
bool caps_sq_ramping; |
bool caps_db_ramping; |
bool caps_td_ramping; |
bool caps_tcp_ramping; |
bool caps_sclk_throttle_low_notification; |
bool caps_fps; |
bool caps_uvd_dpm; |
bool caps_uvd_pg; |
bool caps_vce_pg; |
bool caps_samu_pg; |
bool caps_acp_pg; |
bool caps_stable_p_state; |
bool caps_enable_dfs_bypass; |
bool caps_sclk_ds; |
struct radeon_ps current_rps; |
struct kv_ps current_ps; |
struct radeon_ps requested_rps; |
struct kv_ps requested_ps; |
}; |
/* kv_smc.c */ |
int kv_notify_message_to_smu(struct radeon_device *rdev, u32 id); |
int kv_dpm_get_enable_mask(struct radeon_device *rdev, u32 *enable_mask); |
int kv_send_msg_to_smc_with_parameter(struct radeon_device *rdev, |
PPSMC_Msg msg, u32 parameter); |
int kv_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, |
u32 *value, u32 limit); |
int kv_smc_dpm_enable(struct radeon_device *rdev, bool enable); |
int kv_smc_bapm_enable(struct radeon_device *rdev, bool enable); |
int kv_copy_bytes_to_smc(struct radeon_device *rdev, |
u32 smc_start_address, |
const u8 *src, u32 byte_count, u32 limit); |
#endif |
/drivers/video/drm/radeon/kv_smc.c |
---|
0,0 → 1,215 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "cikd.h" |
#include "kv_dpm.h" |
int kv_notify_message_to_smu(struct radeon_device *rdev, u32 id) |
{ |
u32 i; |
u32 tmp = 0; |
WREG32(SMC_MESSAGE_0, id & SMC_MSG_MASK); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(SMC_RESP_0) & SMC_RESP_MASK) != 0) |
break; |
udelay(1); |
} |
tmp = RREG32(SMC_RESP_0) & SMC_RESP_MASK; |
if (tmp != 1) { |
if (tmp == 0xFF) |
return -EINVAL; |
else if (tmp == 0xFE) |
return -EINVAL; |
} |
return 0; |
} |
int kv_dpm_get_enable_mask(struct radeon_device *rdev, u32 *enable_mask) |
{ |
int ret; |
ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_SCLKDPM_GetEnabledMask); |
if (ret == 0) |
*enable_mask = RREG32_SMC(SMC_SYSCON_MSG_ARG_0); |
return ret; |
} |
int kv_send_msg_to_smc_with_parameter(struct radeon_device *rdev, |
PPSMC_Msg msg, u32 parameter) |
{ |
WREG32(SMC_MSG_ARG_0, parameter); |
return kv_notify_message_to_smu(rdev, msg); |
} |
static int kv_set_smc_sram_address(struct radeon_device *rdev, |
u32 smc_address, u32 limit) |
{ |
if (smc_address & 3) |
return -EINVAL; |
if ((smc_address + 3) > limit) |
return -EINVAL; |
WREG32(SMC_IND_INDEX_0, smc_address); |
WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); |
return 0; |
} |
int kv_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, |
u32 *value, u32 limit) |
{ |
int ret; |
ret = kv_set_smc_sram_address(rdev, smc_address, limit); |
if (ret) |
return ret; |
*value = RREG32(SMC_IND_DATA_0); |
return 0; |
} |
int kv_smc_dpm_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Enable); |
else |
return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Disable); |
} |
int kv_smc_bapm_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
return kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableBAPM); |
else |
return kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableBAPM); |
} |
int kv_copy_bytes_to_smc(struct radeon_device *rdev, |
u32 smc_start_address, |
const u8 *src, u32 byte_count, u32 limit) |
{ |
int ret; |
u32 data, original_data, addr, extra_shift, t_byte, count, mask; |
if ((smc_start_address + byte_count) > limit) |
return -EINVAL; |
addr = smc_start_address; |
t_byte = addr & 3; |
/* RMW for the initial bytes */ |
if (t_byte != 0) { |
addr -= t_byte; |
ret = kv_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
return ret; |
original_data = RREG32(SMC_IND_DATA_0); |
data = 0; |
mask = 0; |
count = 4; |
while (count > 0) { |
if (t_byte > 0) { |
mask = (mask << 8) | 0xff; |
t_byte--; |
} else if (byte_count > 0) { |
data = (data << 8) + *src++; |
byte_count--; |
mask <<= 8; |
} else { |
data <<= 8; |
mask = (mask << 8) | 0xff; |
} |
count--; |
} |
data |= original_data & mask; |
ret = kv_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
return ret; |
WREG32(SMC_IND_DATA_0, data); |
addr += 4; |
} |
while (byte_count >= 4) { |
/* SMC address space is BE */ |
data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; |
ret = kv_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
return ret; |
WREG32(SMC_IND_DATA_0, data); |
src += 4; |
byte_count -= 4; |
addr += 4; |
} |
/* RMW for the final bytes */ |
if (byte_count > 0) { |
data = 0; |
ret = kv_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
return ret; |
original_data= RREG32(SMC_IND_DATA_0); |
extra_shift = 8 * (4 - byte_count); |
while (byte_count > 0) { |
/* SMC address space is BE */ |
data = (data << 8) + *src++; |
byte_count--; |
} |
data <<= extra_shift; |
data |= (original_data & ~((~0UL) << extra_shift)); |
ret = kv_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
return ret; |
WREG32(SMC_IND_DATA_0, data); |
} |
return 0; |
} |
/drivers/video/drm/radeon/main.c |
---|
0,0 → 1,317 |
#include <drm/drmP.h> |
#include <drm/drm_crtc_helper.h> |
#include <drm/radeon_drm.h> |
#include "radeon_reg.h" |
#include "radeon.h" |
#include "bitmap.h" |
#define KMS_DEV_CLOSE 0 |
#define KMS_DEV_INIT 1 |
#define KMS_DEV_READY 2 |
struct pci_device { |
uint16_t domain; |
uint8_t bus; |
uint8_t dev; |
uint8_t func; |
uint16_t vendor_id; |
uint16_t device_id; |
uint16_t subvendor_id; |
uint16_t subdevice_id; |
uint32_t device_class; |
uint8_t revision; |
}; |
struct drm_device *main_device; |
struct drm_file *drm_file_handlers[256]; |
videomode_t usermode; |
void cpu_detect(); |
int _stdcall display_handler(ioctl_t *io); |
static char log[256]; |
unsigned long volatile jiffies; |
u64 jiffies_64; |
struct workqueue_struct *system_wq; |
int driver_wq_state; |
int x86_clflush_size; |
void ati_driver_thread() |
{ |
struct radeon_device *rdev = NULL; |
struct workqueue_struct *cwq = NULL; |
// static int dpms = 1; |
// static int dpms_lock = 0; |
// oskey_t key; |
unsigned long irqflags; |
int tmp; |
printf("%s\n",__FUNCTION__); |
while(driver_wq_state == KMS_DEV_INIT) |
{ |
jiffies = GetTimerTicks(); |
jiffies_64 = jiffies; |
delay(1); |
}; |
rdev = main_device->dev_private; |
// cwq = rdev->wq; |
asm volatile("int $0x40":"=a"(tmp):"a"(66),"b"(1),"c"(1)); |
asm volatile("int $0x40":"=a"(tmp):"a"(66),"b"(4),"c"(0x46),"d"(0x330)); |
asm volatile("int $0x40":"=a"(tmp):"a"(66),"b"(4),"c"(0xC6),"d"(0x330)); |
while(driver_wq_state != KMS_DEV_CLOSE) |
{ |
jiffies = GetTimerTicks(); |
#if 0 |
key = get_key(); |
if( (key.val != 1) && (key.state == 0x02)) |
{ |
if(key.code == 0x46 && dpms_lock == 0) |
{ |
dpms_lock = 1; |
if(dpms == 1) |
{ |
i915_dpms(main_device, DRM_MODE_DPMS_OFF); |
printf("dpms off\n"); |
} |
else |
{ |
i915_dpms(main_device, DRM_MODE_DPMS_ON); |
printf("dpms on\n"); |
}; |
dpms ^= 1; |
} |
else if(key.code == 0xC6) |
dpms_lock = 0; |
}; |
spin_lock_irqsave(&cwq->lock, irqflags); |
while (!list_empty(&cwq->worklist)) |
{ |
struct work_struct *work = list_entry(cwq->worklist.next, |
struct work_struct, entry); |
work_func_t f = work->func; |
list_del_init(cwq->worklist.next); |
spin_unlock_irqrestore(&cwq->lock, irqflags); |
f(work); |
spin_lock_irqsave(&cwq->lock, irqflags); |
} |
spin_unlock_irqrestore(&cwq->lock, irqflags); |
#endif |
delay(1); |
}; |
asm volatile ("int $0x40"::"a"(-1)); |
} |
u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline) |
{ |
struct radeon_device *rdev = NULL; |
const struct pci_device_id *ent; |
int err = 0; |
if(action != 1) |
{ |
driver_wq_state = KMS_DEV_CLOSE; |
return 0; |
}; |
if( GetService("DISPLAY") != 0 ) |
return 0; |
printf("Radeon v3.17-rc3 cmdline %s\n", cmdline); |
if( cmdline && *cmdline ) |
parse_cmdline(cmdline, &usermode, log, &radeon_modeset); |
if( *log && !dbg_open(log)) |
{ |
printf("Can't open %s\nExit\n", log); |
return 0; |
} |
cpu_detect(); |
err = enum_pci_devices(); |
if( unlikely(err != 0) ) |
{ |
dbgprintf("Device enumeration failed\n"); |
return 0; |
} |
driver_wq_state = KMS_DEV_INIT; |
CreateKernelThread(ati_driver_thread); |
err = ati_init(); |
if(unlikely(err!= 0)) |
{ |
driver_wq_state = KMS_DEV_CLOSE; |
dbgprintf("Epic Fail :(\n"); |
return 0; |
}; |
driver_wq_state = KMS_DEV_READY; |
rdev = main_device->dev_private; |
printf("current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); |
printf("current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); |
err = RegService("DISPLAY", display_handler); |
if( err != 0) |
dbgprintf("DISPLAY service installed\n"); |
return err; |
}; |
#define CURRENT_API 0x0200 /* 2.00 */ |
#define COMPATIBLE_API 0x0100 /* 1.00 */ |
#define API_VERSION (COMPATIBLE_API << 16) | CURRENT_API |
#define SRV_GETVERSION 0 |
#define SRV_ENUM_MODES 1 |
#define SRV_SET_MODE 2 |
#define SRV_GET_CAPS 3 |
#define SRV_CREATE_SURFACE 10 |
#define SRV_DESTROY_SURFACE 11 |
#define SRV_LOCK_SURFACE 12 |
#define SRV_UNLOCK_SURFACE 13 |
#define SRV_RESIZE_SURFACE 14 |
#define SRV_BLIT_BITMAP 15 |
#define SRV_BLIT_TEXTURE 16 |
#define SRV_BLIT_VIDEO 17 |
int r600_video_blit(uint64_t src_offset, int x, int y, |
int w, int h, int pitch); |
#define check_input(size) \ |
if( unlikely((inp==NULL)||(io->inp_size != (size))) ) \ |
break; |
#define check_output(size) \ |
if( unlikely((outp==NULL)||(io->out_size != (size))) ) \ |
break; |
int _stdcall display_handler(ioctl_t *io) |
{ |
int retval = -1; |
u32_t *inp; |
u32_t *outp; |
inp = io->input; |
outp = io->output; |
switch(io->io_code) |
{ |
case SRV_GETVERSION: |
check_output(4); |
*outp = API_VERSION; |
retval = 0; |
break; |
case SRV_ENUM_MODES: |
// dbgprintf("SRV_ENUM_MODES inp %x inp_size %x out_size %x\n", |
// inp, io->inp_size, io->out_size ); |
check_output(4); |
if( radeon_modeset) |
retval = get_videomodes((videomode_t*)inp, outp); |
break; |
case SRV_SET_MODE: |
// dbgprintf("SRV_SET_MODE inp %x inp_size %x\n", |
// inp, io->inp_size); |
check_input(sizeof(videomode_t)); |
if( radeon_modeset ) |
retval = set_user_mode((videomode_t*)inp); |
break; |
/* |
case SRV_GET_CAPS: |
retval = get_driver_caps((hwcaps_t*)inp); |
break; |
case SRV_CREATE_SURFACE: |
// check_input(8); |
retval = create_surface(main_drm_device, (struct io_call_10*)inp); |
break; |
case SRV_LOCK_SURFACE: |
retval = lock_surface((struct io_call_12*)inp); |
break; |
case SRV_BLIT_BITMAP: |
srv_blit_bitmap( inp[0], inp[1], inp[2], |
inp[3], inp[4], inp[5], inp[6]); |
*/ |
}; |
return retval; |
} |
#define PCI_CLASS_REVISION 0x08 |
#define PCI_CLASS_DISPLAY_VGA 0x0300 |
int pci_scan_filter(u32_t id, u32_t busnr, u32_t devfn) |
{ |
u16_t vendor, device; |
u32_t class; |
int ret = 0; |
vendor = id & 0xffff; |
device = (id >> 16) & 0xffff; |
if(vendor == 0x1002) |
{ |
class = PciRead32(busnr, devfn, PCI_CLASS_REVISION); |
class >>= 16; |
if( class == PCI_CLASS_DISPLAY_VGA) |
ret = 1; |
} |
return ret; |
} |
int seq_printf(struct seq_file *m, const char *f, ...) |
{ |
// int ret; |
// va_list args; |
// va_start(args, f); |
// ret = seq_vprintf(m, f, args); |
// va_end(args); |
// return ret; |
return 0; |
} |
s64 div64_s64(s64 dividend, s64 divisor) |
{ |
s64 quot, t; |
quot = div64_u64(abs64(dividend), abs64(divisor)); |
t = (dividend ^ divisor) >> 63; |
return (quot ^ t) - t; |
} |
/drivers/video/drm/radeon/ni.c |
---|
22,7 → 22,6 |
* Authors: Alex Deucher |
*/ |
#include <linux/firmware.h> |
//#include <linux/platform_device.h> |
#include <linux/slab.h> |
#include <linux/module.h> |
#include <drm/drmP.h> |
33,7 → 32,135 |
#include "atom.h" |
#include "ni_reg.h" |
#include "cayman_blit_shaders.h" |
#include "radeon_ucode.h" |
#include "clearstate_cayman.h" |
static const u32 tn_rlc_save_restore_register_list[] = |
{ |
0x98fc, |
0x98f0, |
0x9834, |
0x9838, |
0x9870, |
0x9874, |
0x8a14, |
0x8b24, |
0x8bcc, |
0x8b10, |
0x8c30, |
0x8d00, |
0x8d04, |
0x8c00, |
0x8c04, |
0x8c10, |
0x8c14, |
0x8d8c, |
0x8cf0, |
0x8e38, |
0x9508, |
0x9688, |
0x9608, |
0x960c, |
0x9610, |
0x9614, |
0x88c4, |
0x8978, |
0x88d4, |
0x900c, |
0x9100, |
0x913c, |
0x90e8, |
0x9354, |
0xa008, |
0x98f8, |
0x9148, |
0x914c, |
0x3f94, |
0x98f4, |
0x9b7c, |
0x3f8c, |
0x8950, |
0x8954, |
0x8a18, |
0x8b28, |
0x9144, |
0x3f90, |
0x915c, |
0x9160, |
0x9178, |
0x917c, |
0x9180, |
0x918c, |
0x9190, |
0x9194, |
0x9198, |
0x919c, |
0x91a8, |
0x91ac, |
0x91b0, |
0x91b4, |
0x91b8, |
0x91c4, |
0x91c8, |
0x91cc, |
0x91d0, |
0x91d4, |
0x91e0, |
0x91e4, |
0x91ec, |
0x91f0, |
0x91f4, |
0x9200, |
0x9204, |
0x929c, |
0x8030, |
0x9150, |
0x9a60, |
0x920c, |
0x9210, |
0x9228, |
0x922c, |
0x9244, |
0x9248, |
0x91e8, |
0x9294, |
0x9208, |
0x9224, |
0x9240, |
0x9220, |
0x923c, |
0x9258, |
0x9744, |
0xa200, |
0xa204, |
0xa208, |
0xa20c, |
0x8d58, |
0x9030, |
0x9034, |
0x9038, |
0x903c, |
0x9040, |
0x9654, |
0x897c, |
0xa210, |
0xa214, |
0x9868, |
0xa02c, |
0x9664, |
0x9698, |
0x949c, |
0x8e10, |
0x8e18, |
0x8c50, |
0x8c58, |
0x8c60, |
0x8c68, |
0x89b4, |
0x9830, |
0x802c, |
}; |
extern bool evergreen_is_display_hung(struct radeon_device *rdev); |
extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev); |
extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save); |
44,36 → 171,30 |
extern int evergreen_mc_init(struct radeon_device *rdev); |
extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev); |
extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev); |
extern void si_rlc_fini(struct radeon_device *rdev); |
extern int si_rlc_init(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 evergreen_gpu_pci_config_reset(struct radeon_device *rdev); |
#define EVERGREEN_PFP_UCODE_SIZE 1120 |
#define EVERGREEN_PM4_UCODE_SIZE 1376 |
#define EVERGREEN_RLC_UCODE_SIZE 768 |
#define BTC_MC_UCODE_SIZE 6024 |
#define CAYMAN_PFP_UCODE_SIZE 2176 |
#define CAYMAN_PM4_UCODE_SIZE 2176 |
#define CAYMAN_RLC_UCODE_SIZE 1024 |
#define CAYMAN_MC_UCODE_SIZE 6037 |
#define ARUBA_RLC_UCODE_SIZE 1536 |
/* Firmware Names */ |
MODULE_FIRMWARE("radeon/BARTS_pfp.bin"); |
MODULE_FIRMWARE("radeon/BARTS_me.bin"); |
MODULE_FIRMWARE("radeon/BARTS_mc.bin"); |
MODULE_FIRMWARE("radeon/BARTS_smc.bin"); |
MODULE_FIRMWARE("radeon/BTC_rlc.bin"); |
MODULE_FIRMWARE("radeon/TURKS_pfp.bin"); |
MODULE_FIRMWARE("radeon/TURKS_me.bin"); |
MODULE_FIRMWARE("radeon/TURKS_mc.bin"); |
MODULE_FIRMWARE("radeon/TURKS_smc.bin"); |
MODULE_FIRMWARE("radeon/CAICOS_pfp.bin"); |
MODULE_FIRMWARE("radeon/CAICOS_me.bin"); |
MODULE_FIRMWARE("radeon/CAICOS_mc.bin"); |
MODULE_FIRMWARE("radeon/CAICOS_smc.bin"); |
MODULE_FIRMWARE("radeon/CAYMAN_pfp.bin"); |
MODULE_FIRMWARE("radeon/CAYMAN_me.bin"); |
MODULE_FIRMWARE("radeon/CAYMAN_mc.bin"); |
MODULE_FIRMWARE("radeon/CAYMAN_rlc.bin"); |
MODULE_FIRMWARE("radeon/CAYMAN_smc.bin"); |
MODULE_FIRMWARE("radeon/ARUBA_pfp.bin"); |
MODULE_FIRMWARE("radeon/ARUBA_me.bin"); |
MODULE_FIRMWARE("radeon/ARUBA_rlc.bin"); |
562,22 → 683,15 |
int ni_init_microcode(struct radeon_device *rdev) |
{ |
struct platform_device *pdev; |
const char *chip_name; |
const char *rlc_chip_name; |
size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size; |
size_t smc_req_size = 0; |
char fw_name[30]; |
int err; |
DRM_DEBUG("\n"); |
pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); |
err = IS_ERR(pdev); |
if (err) { |
printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); |
return -EINVAL; |
} |
switch (rdev->family) { |
case CHIP_BARTS: |
chip_name = "BARTS"; |
586,6 → 700,7 |
me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; |
rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4; |
mc_req_size = BTC_MC_UCODE_SIZE * 4; |
smc_req_size = ALIGN(BARTS_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_TURKS: |
chip_name = "TURKS"; |
594,6 → 709,7 |
me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; |
rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4; |
mc_req_size = BTC_MC_UCODE_SIZE * 4; |
smc_req_size = ALIGN(TURKS_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_CAICOS: |
chip_name = "CAICOS"; |
602,6 → 718,7 |
me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; |
rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4; |
mc_req_size = BTC_MC_UCODE_SIZE * 4; |
smc_req_size = ALIGN(CAICOS_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_CAYMAN: |
chip_name = "CAYMAN"; |
610,6 → 727,7 |
me_req_size = CAYMAN_PM4_UCODE_SIZE * 4; |
rlc_req_size = CAYMAN_RLC_UCODE_SIZE * 4; |
mc_req_size = CAYMAN_MC_UCODE_SIZE * 4; |
smc_req_size = ALIGN(CAYMAN_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_ARUBA: |
chip_name = "ARUBA"; |
626,7 → 744,7 |
DRM_INFO("Loading %s Microcode\n", chip_name); |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); |
err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->pfp_fw->size != pfp_req_size) { |
638,7 → 756,7 |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); |
err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->me_fw->size != me_req_size) { |
649,7 → 767,7 |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); |
err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->rlc_fw->size != rlc_req_size) { |
662,7 → 780,7 |
/* no MC ucode on TN */ |
if (!(rdev->flags & RADEON_IS_IGP)) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); |
err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->mc_fw->size != mc_req_size) { |
672,10 → 790,27 |
err = -EINVAL; |
} |
} |
out: |
platform_device_unregister(pdev); |
if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); |
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); |
if (err) { |
printk(KERN_ERR |
"smc: error loading firmware \"%s\"\n", |
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", |
rdev->mc_fw->size, fw_name); |
err = -EINVAL; |
} |
} |
out: |
if (err) { |
if (err != -EINVAL) |
printk(KERN_ERR |
"ni_cp: Failed to load firmware \"%s\"\n", |
692,6 → 827,14 |
return err; |
} |
int tn_get_temp(struct radeon_device *rdev) |
{ |
u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff; |
int actual_temp = (temp / 8) - 49; |
return actual_temp * 1000; |
} |
/* |
* Core functions |
*/ |
753,6 → 896,10 |
(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) || |
763,6 → 910,10 |
(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) || |
773,9 → 924,17 |
(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; |
783,10 → 942,6 |
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; |
902,6 → 1057,18 |
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); |
1027,7 → 1194,17 |
WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3)); |
udelay(50); |
/* set clockgating golden values on TN */ |
if (rdev->family == CHIP_ARUBA) { |
tmp = RREG32_CG(CG_CGTT_LOCAL_0); |
tmp &= ~0x00380000; |
WREG32_CG(CG_CGTT_LOCAL_0, tmp); |
tmp = RREG32_CG(CG_CGTT_LOCAL_1); |
tmp &= ~0x0e000000; |
WREG32_CG(CG_CGTT_LOCAL_1, tmp); |
} |
} |
/* |
* GART |
1052,7 → 1229,6 |
r = radeon_gart_table_vram_pin(rdev); |
if (r) |
return r; |
radeon_gart_restore(rdev); |
/* Setup TLB control */ |
WREG32(MC_VM_MX_L1_TLB_CNTL, |
(0xA << 7) | |
1063,6 → 1239,7 |
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) | |
1069,6 → 1246,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); |
1093,7 → 1271,7 |
WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (i << 2), 0); |
WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), rdev->vm_manager.max_pfn); |
WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), |
rdev->gart.table_addr >> 12); |
rdev->vm_manager.saved_table_addr[i]); |
} |
/* enable context1-7 */ |
1101,6 → 1279,7 |
(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 | |
1124,6 → 1303,13 |
static void cayman_pcie_gart_disable(struct radeon_device *rdev) |
{ |
unsigned i; |
for (i = 1; i < 8; ++i) { |
rdev->vm_manager.saved_table_addr[i] = RREG32( |
VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2)); |
} |
/* Disable all tables */ |
WREG32(VM_CONTEXT0_CNTL, 0); |
WREG32(VM_CONTEXT1_CNTL, 0); |
1159,13 → 1345,12 |
{ |
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 */ |
1172,7 → 1357,7 |
/* 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); |
1181,6 → 1366,8 |
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)); |
1205,38 → 1392,19 |
(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 */ |
} |
void cayman_uvd_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, PACKET0(UVD_SEMA_ADDR_LOW, 0)); |
radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); |
radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); |
radeon_ring_write(ring, 0x80 | (emit_wait ? 1 : 0)); |
} |
static void cayman_cp_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)); |
WREG32(SCRATCH_UMSK, 0); |
1244,6 → 1412,55 |
} |
} |
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; |
1288,7 → 1505,7 |
radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, 0); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
cayman_cp_enable(rdev, true); |
1330,7 → 1547,7 |
radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ |
radeon_ring_write(ring, 0x00000010); /* */ |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
/* XXX init other rings */ |
1365,6 → 1582,16 |
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; |
1398,8 → 1625,8 |
/* Set ring buffer size */ |
ring = &rdev->ring[ridx[i]]; |
rb_cntl = drm_order(ring->ring_size / 8); |
rb_cntl |= drm_order(RADEON_GPU_PAGE_SIZE/8) << 8; |
rb_cntl = order_base_2(ring->ring_size / 8); |
rb_cntl |= order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8; |
#ifdef __BIG_ENDIAN |
rb_cntl |= BUF_SWAP_32BIT; |
#endif |
1422,9 → 1649,9 |
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); |
1444,190 → 1671,14 |
return r; |
} |
return 0; |
} |
/* |
* DMA |
* Starting with R600, the GPU has an asynchronous |
* DMA engine. The programming model is very similar |
* to the 3D engine (ring buffer, IBs, etc.), but the |
* DMA controller has it's own packet format that is |
* different form the PM4 format used by the 3D engine. |
* It supports copying data, writing embedded data, |
* solid fills, and a number of other things. It also |
* has support for tiling/detiling of buffers. |
* Cayman and newer support two asynchronous DMA engines. |
*/ |
/** |
* cayman_dma_ring_ib_execute - Schedule an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to schedule |
* |
* Schedule an IB in the DMA ring (cayman-SI). |
*/ |
void cayman_dma_ring_ib_execute(struct radeon_device *rdev, |
struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
if (rdev->wb.enabled) { |
u32 next_rptr = ring->wptr + 4; |
while ((next_rptr & 7) != 5) |
next_rptr++; |
next_rptr += 3; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); |
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff); |
radeon_ring_write(ring, next_rptr); |
} |
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring. |
* Pad as necessary with NOPs. |
*/ |
while ((ring->wptr & 7) != 5) |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
radeon_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, ib->vm ? ib->vm->id : 0, 0)); |
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0)); |
radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF)); |
} |
/** |
* cayman_dma_stop - stop the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engines (cayman-SI). |
*/ |
void cayman_dma_stop(struct radeon_device *rdev) |
{ |
u32 rb_cntl; |
radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); |
/* dma0 */ |
rb_cntl = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET); |
rb_cntl &= ~DMA_RB_ENABLE; |
WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, rb_cntl); |
/* dma1 */ |
rb_cntl = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET); |
rb_cntl &= ~DMA_RB_ENABLE; |
WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, rb_cntl); |
rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; |
rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false; |
} |
/** |
* cayman_dma_resume - setup and start the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Set up the DMA ring buffers and enable them. (cayman-SI). |
* Returns 0 for success, error for failure. |
*/ |
int cayman_dma_resume(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring; |
u32 rb_cntl, dma_cntl, ib_cntl; |
u32 rb_bufsz; |
u32 reg_offset, wb_offset; |
int i, r; |
/* Reset dma */ |
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1); |
RREG32(SRBM_SOFT_RESET); |
udelay(50); |
WREG32(SRBM_SOFT_RESET, 0); |
for (i = 0; i < 2; i++) { |
if (i == 0) { |
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; |
reg_offset = DMA0_REGISTER_OFFSET; |
wb_offset = R600_WB_DMA_RPTR_OFFSET; |
} else { |
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]; |
reg_offset = DMA1_REGISTER_OFFSET; |
wb_offset = CAYMAN_WB_DMA1_RPTR_OFFSET; |
} |
WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL + reg_offset, 0); |
WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0); |
/* Set ring buffer size in dwords */ |
rb_bufsz = drm_order(ring->ring_size / 4); |
rb_cntl = rb_bufsz << 1; |
#ifdef __BIG_ENDIAN |
rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE; |
#endif |
WREG32(DMA_RB_CNTL + reg_offset, rb_cntl); |
/* Initialize the ring buffer's read and write pointers */ |
WREG32(DMA_RB_RPTR + reg_offset, 0); |
WREG32(DMA_RB_WPTR + reg_offset, 0); |
/* set the wb address whether it's enabled or not */ |
WREG32(DMA_RB_RPTR_ADDR_HI + reg_offset, |
upper_32_bits(rdev->wb.gpu_addr + wb_offset) & 0xFF); |
WREG32(DMA_RB_RPTR_ADDR_LO + reg_offset, |
((rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC)); |
if (rdev->wb.enabled) |
rb_cntl |= DMA_RPTR_WRITEBACK_ENABLE; |
WREG32(DMA_RB_BASE + reg_offset, ring->gpu_addr >> 8); |
/* enable DMA IBs */ |
ib_cntl = DMA_IB_ENABLE | CMD_VMID_FORCE; |
#ifdef __BIG_ENDIAN |
ib_cntl |= DMA_IB_SWAP_ENABLE; |
#endif |
WREG32(DMA_IB_CNTL + reg_offset, ib_cntl); |
dma_cntl = RREG32(DMA_CNTL + reg_offset); |
dma_cntl &= ~CTXEMPTY_INT_ENABLE; |
WREG32(DMA_CNTL + reg_offset, dma_cntl); |
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; |
r = radeon_ring_test(rdev, ring->idx, ring); |
if (r) { |
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; |
} |
/** |
* cayman_dma_fini - tear down the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engines and free the rings (cayman-SI). |
*/ |
void cayman_dma_fini(struct radeon_device *rdev) |
u32 cayman_gpu_check_soft_reset(struct radeon_device *rdev) |
{ |
cayman_dma_stop(rdev); |
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]); |
radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]); |
} |
static u32 cayman_gpu_check_soft_reset(struct radeon_device *rdev) |
{ |
u32 reset_mask = 0; |
u32 tmp; |
1849,7 → 1900,9 |
reset_mask = cayman_gpu_check_soft_reset(rdev); |
if (!reset_mask) |
if (reset_mask) |
evergreen_gpu_pci_config_reset(rdev); |
r600_set_bios_scratch_engine_hung(rdev, false); |
return 0; |
1871,42 → 1924,12 |
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); |
} |
/** |
* cayman_dma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up. |
* Returns true if the engine appears to be locked up, false if not. |
*/ |
bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
u32 reset_mask = cayman_gpu_check_soft_reset(rdev); |
u32 mask; |
if (ring->idx == R600_RING_TYPE_DMA_INDEX) |
mask = RADEON_RESET_DMA; |
else |
mask = RADEON_RESET_DMA1; |
if (!(reset_mask & mask)) { |
radeon_ring_lockup_update(ring); |
return false; |
} |
/* force ring activities */ |
radeon_ring_force_activity(rdev, ring); |
return radeon_ring_test_lockup(rdev, ring); |
} |
static int cayman_startup(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
1914,24 → 1937,17 |
/* enable pcie gen2 link */ |
evergreen_pcie_gen2_enable(rdev); |
/* enable aspm */ |
evergreen_program_aspm(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"); |
/* scratch needs to be initialized before MC */ |
r = r600_vram_scratch_init(rdev); |
if (r) |
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; |
} |
} |
evergreen_mc_program(rdev); |
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"); |
1939,26 → 1955,18 |
} |
} |
r = r600_vram_scratch_init(rdev); |
if (r) |
return r; |
evergreen_mc_program(rdev); |
r = cayman_pcie_gart_enable(rdev); |
if (r) |
return r; |
cayman_gpu_init(rdev); |
r = evergreen_blit_init(rdev); |
if (r) { |
// r600_blit_fini(rdev); |
rdev->asic->copy.copy = NULL; |
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); |
} |
/* allocate rlc buffers */ |
if (rdev->flags & RADEON_IS_IGP) { |
r = si_rlc_init(rdev); |
rdev->rlc.reg_list = tn_rlc_save_restore_register_list; |
rdev->rlc.reg_list_size = |
(u32)ARRAY_SIZE(tn_rlc_save_restore_register_list); |
rdev->rlc.cs_data = cayman_cs_data; |
r = sumo_rlc_init(rdev); |
if (r) { |
DRM_ERROR("Failed to init rlc BOs!\n"); |
return r; |
2026,24 → 2034,19 |
evergreen_irq_set(rdev); |
r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, |
CP_RB0_RPTR, CP_RB0_WPTR, |
0, 0xfffff, RADEON_CP_PACKET2); |
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, |
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
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, |
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
if (r) |
return r; |
2058,17 → 2061,6 |
if (r) |
return r; |
ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
if (ring->ring_size) { |
r = radeon_ring_init(rdev, ring, ring->ring_size, |
R600_WB_UVD_RPTR_OFFSET, |
UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, |
0, 0xfffff, RADEON_CP_PACKET2); |
if (!r) |
r = r600_uvd_init(rdev); |
if (r) |
DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); |
} |
r = radeon_ib_pool_init(rdev); |
if (r) { |
2145,6 → 2137,27 |
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); |
2213,131 → 2226,167 |
{ |
} |
#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 |
* cayman_vm_decode_fault - print human readable fault info |
* |
* @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 |
* @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value |
* @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value |
* |
* Update the page tables using the CP (cayman/TN). |
* Print human readable fault information (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) |
void cayman_vm_decode_fault(struct radeon_device *rdev, |
u32 status, u32 addr) |
{ |
uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); |
uint64_t value; |
unsigned ndw; |
u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; |
u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT; |
u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT; |
char *block; |
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; |
switch (mc_id) { |
case 32: |
case 16: |
case 96: |
case 80: |
case 160: |
case 144: |
case 224: |
case 208: |
block = "CB"; |
break; |
case 33: |
case 17: |
case 97: |
case 81: |
case 161: |
case 145: |
case 225: |
case 209: |
block = "CB_FMASK"; |
break; |
case 34: |
case 18: |
case 98: |
case 82: |
case 162: |
case 146: |
case 226: |
case 210: |
block = "CB_CMASK"; |
break; |
case 35: |
case 19: |
case 99: |
case 83: |
case 163: |
case 147: |
case 227: |
case 211: |
block = "CB_IMMED"; |
break; |
case 36: |
case 20: |
case 100: |
case 84: |
case 164: |
case 148: |
case 228: |
case 212: |
block = "DB"; |
break; |
case 37: |
case 21: |
case 101: |
case 85: |
case 165: |
case 149: |
case 229: |
case 213: |
block = "DB_HTILE"; |
break; |
case 38: |
case 22: |
case 102: |
case 86: |
case 166: |
case 150: |
case 230: |
case 214: |
block = "SX"; |
break; |
case 39: |
case 23: |
case 103: |
case 87: |
case 167: |
case 151: |
case 231: |
case 215: |
block = "DB_STEN"; |
break; |
case 40: |
case 24: |
case 104: |
case 88: |
case 232: |
case 216: |
case 168: |
case 152: |
block = "TC_TFETCH"; |
break; |
case 41: |
case 25: |
case 105: |
case 89: |
case 233: |
case 217: |
case 169: |
case 153: |
block = "TC_VFETCH"; |
break; |
case 42: |
case 26: |
case 106: |
case 90: |
case 234: |
case 218: |
case 170: |
case 154: |
block = "VC"; |
break; |
case 112: |
block = "CP"; |
break; |
case 113: |
case 114: |
block = "SH"; |
break; |
case 115: |
block = "VGT"; |
break; |
case 178: |
block = "IH"; |
break; |
case 51: |
block = "RLC"; |
break; |
case 55: |
block = "DMA"; |
break; |
case 56: |
block = "HDP"; |
break; |
default: |
block = "unknown"; |
break; |
} |
addr += incr; |
value |= r600_flags; |
ib->ptr[ib->length_dw++] = value; |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
} |
} |
} else { |
if ((flags & RADEON_VM_PAGE_SYSTEM) || |
(count == 1)) { |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
/* for non-physically contiguous pages (system) */ |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, ndw); |
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; |
printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n", |
protections, vmid, addr, |
(status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", |
block, mc_id); |
} |
addr += incr; |
value |= r600_flags; |
ib->ptr[ib->length_dw++] = value; |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
} |
} |
while (ib->length_dw & 0x7) |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0); |
} else { |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
if (flags & RADEON_VM_PAGE_VALID) |
value = addr; |
else |
value = 0; |
/* for physically contiguous pages (vram) */ |
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++] = 0; |
ib->ptr[ib->length_dw++] = value; /* value */ |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
ib->ptr[ib->length_dw++] = incr; /* increment size */ |
ib->ptr[ib->length_dw++] = 0; |
pe += ndw * 4; |
addr += (ndw / 2) * incr; |
count -= ndw / 2; |
} |
} |
while (ib->length_dw & 0x7) |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0); |
} |
} |
/** |
* cayman_vm_flush - vm flush using the CP |
* |
2368,26 → 2417,3 |
radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); |
radeon_ring_write(ring, 0x0); |
} |
void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) |
{ |
struct radeon_ring *ring = &rdev->ring[ridx]; |
if (vm == NULL) |
return; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2)); |
radeon_ring_write(ring, vm->pd_gpu_addr >> 12); |
/* flush hdp cache */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2)); |
radeon_ring_write(ring, 1); |
/* bits 0-7 are the VM contexts0-7 */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); |
radeon_ring_write(ring, 1 << vm->id); |
} |
/drivers/video/drm/radeon/ni_dma.c |
---|
0,0 → 1,476 |
/* |
* Copyright 2010 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#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); |
/* |
* DMA |
* Starting with R600, the GPU has an asynchronous |
* DMA engine. The programming model is very similar |
* to the 3D engine (ring buffer, IBs, etc.), but the |
* DMA controller has it's own packet format that is |
* different form the PM4 format used by the 3D engine. |
* It supports copying data, writing embedded data, |
* solid fills, and a number of other things. It also |
* has support for tiling/detiling of buffers. |
* Cayman and newer support two asynchronous DMA engines. |
*/ |
/** |
* 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 |
* @ib: IB object to schedule |
* |
* Schedule an IB in the DMA ring (cayman-SI). |
*/ |
void cayman_dma_ring_ib_execute(struct radeon_device *rdev, |
struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
if (rdev->wb.enabled) { |
u32 next_rptr = ring->wptr + 4; |
while ((next_rptr & 7) != 5) |
next_rptr++; |
next_rptr += 3; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); |
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff); |
radeon_ring_write(ring, next_rptr); |
} |
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring. |
* Pad as necessary with NOPs. |
*/ |
while ((ring->wptr & 7) != 5) |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
radeon_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, ib->vm ? ib->vm->id : 0, 0)); |
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0)); |
radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF)); |
} |
/** |
* cayman_dma_stop - stop the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engines (cayman-SI). |
*/ |
void cayman_dma_stop(struct radeon_device *rdev) |
{ |
u32 rb_cntl; |
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); |
rb_cntl &= ~DMA_RB_ENABLE; |
WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, rb_cntl); |
/* dma1 */ |
rb_cntl = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET); |
rb_cntl &= ~DMA_RB_ENABLE; |
WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, rb_cntl); |
rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; |
rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false; |
} |
/** |
* cayman_dma_resume - setup and start the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Set up the DMA ring buffers and enable them. (cayman-SI). |
* Returns 0 for success, error for failure. |
*/ |
int cayman_dma_resume(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring; |
u32 rb_cntl, dma_cntl, ib_cntl; |
u32 rb_bufsz; |
u32 reg_offset, wb_offset; |
int i, r; |
/* Reset dma */ |
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1); |
RREG32(SRBM_SOFT_RESET); |
udelay(50); |
WREG32(SRBM_SOFT_RESET, 0); |
for (i = 0; i < 2; i++) { |
if (i == 0) { |
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; |
reg_offset = DMA0_REGISTER_OFFSET; |
wb_offset = R600_WB_DMA_RPTR_OFFSET; |
} else { |
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]; |
reg_offset = DMA1_REGISTER_OFFSET; |
wb_offset = CAYMAN_WB_DMA1_RPTR_OFFSET; |
} |
WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL + reg_offset, 0); |
WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0); |
/* Set ring buffer size in dwords */ |
rb_bufsz = order_base_2(ring->ring_size / 4); |
rb_cntl = rb_bufsz << 1; |
#ifdef __BIG_ENDIAN |
rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE; |
#endif |
WREG32(DMA_RB_CNTL + reg_offset, rb_cntl); |
/* Initialize the ring buffer's read and write pointers */ |
WREG32(DMA_RB_RPTR + reg_offset, 0); |
WREG32(DMA_RB_WPTR + reg_offset, 0); |
/* set the wb address whether it's enabled or not */ |
WREG32(DMA_RB_RPTR_ADDR_HI + reg_offset, |
upper_32_bits(rdev->wb.gpu_addr + wb_offset) & 0xFF); |
WREG32(DMA_RB_RPTR_ADDR_LO + reg_offset, |
((rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC)); |
if (rdev->wb.enabled) |
rb_cntl |= DMA_RPTR_WRITEBACK_ENABLE; |
WREG32(DMA_RB_BASE + reg_offset, ring->gpu_addr >> 8); |
/* enable DMA IBs */ |
ib_cntl = DMA_IB_ENABLE | CMD_VMID_FORCE; |
#ifdef __BIG_ENDIAN |
ib_cntl |= DMA_IB_SWAP_ENABLE; |
#endif |
WREG32(DMA_IB_CNTL + reg_offset, ib_cntl); |
dma_cntl = RREG32(DMA_CNTL + reg_offset); |
dma_cntl &= ~CTXEMPTY_INT_ENABLE; |
WREG32(DMA_CNTL + reg_offset, dma_cntl); |
ring->wptr = 0; |
WREG32(DMA_RB_WPTR + reg_offset, ring->wptr << 2); |
WREG32(DMA_RB_CNTL + reg_offset, rb_cntl | DMA_RB_ENABLE); |
ring->ready = true; |
r = radeon_ring_test(rdev, ring->idx, ring); |
if (r) { |
ring->ready = false; |
return r; |
} |
} |
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; |
} |
/** |
* cayman_dma_fini - tear down the async dma engines |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engines and free the rings (cayman-SI). |
*/ |
void cayman_dma_fini(struct radeon_device *rdev) |
{ |
cayman_dma_stop(rdev); |
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]); |
radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]); |
} |
/** |
* cayman_dma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up. |
* Returns true if the engine appears to be locked up, false if not. |
*/ |
bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
u32 reset_mask = cayman_gpu_check_soft_reset(rdev); |
u32 mask; |
if (ring->idx == R600_RING_TYPE_DMA_INDEX) |
mask = RADEON_RESET_DMA; |
else |
mask = RADEON_RESET_DMA1; |
if (!(reset_mask & mask)) { |
radeon_ring_lockup_update(rdev, ring); |
return false; |
} |
return radeon_ring_test_lockup(rdev, ring); |
} |
/** |
* cayman_dma_vm_copy_pages - update PTEs by copying them from the GART |
* |
* @rdev: radeon_device pointer |
* @ib: indirect buffer to fill with commands |
* @pe: addr of the page entry |
* @src: src addr where to copy from |
* @count: number of page entries to update |
* |
* Update PTEs by copying them from the GART using the DMA (cayman/TN). |
*/ |
void cayman_dma_vm_copy_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, uint64_t src, |
unsigned count) |
{ |
unsigned ndw; |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY, |
0, 0, ndw); |
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 += ndw * 4; |
src += ndw * 4; |
count -= ndw / 2; |
} |
} |
/** |
* cayman_dma_vm_write_pages - update PTEs by writing them manually |
* |
* @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: hw access flags |
* |
* Update PTEs by writing them manually using the DMA (cayman/TN). |
*/ |
void cayman_dma_vm_write_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags) |
{ |
uint64_t value; |
unsigned ndw; |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
/* for non-physically contiguous pages (system) */ |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, |
0, 0, ndw); |
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 & R600_PTE_SYSTEM) { |
value = radeon_vm_map_gart(rdev, addr); |
value &= 0xFFFFFFFFFFFFF000ULL; |
} else if (flags & R600_PTE_VALID) { |
value = addr; |
} else { |
value = 0; |
} |
addr += incr; |
value |= flags; |
ib->ptr[ib->length_dw++] = value; |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
} |
} |
} |
/** |
* cayman_dma_vm_set_pages - update the page tables using the DMA |
* |
* @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: hw access flags |
* |
* Update the page tables using the DMA (cayman/TN). |
*/ |
void cayman_dma_vm_set_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags) |
{ |
uint64_t value; |
unsigned ndw; |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
if (flags & R600_PTE_VALID) |
value = addr; |
else |
value = 0; |
/* for physically contiguous pages (vram) */ |
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++] = flags; /* mask */ |
ib->ptr[ib->length_dw++] = 0; |
ib->ptr[ib->length_dw++] = value; /* value */ |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
ib->ptr[ib->length_dw++] = incr; /* increment size */ |
ib->ptr[ib->length_dw++] = 0; |
pe += ndw * 4; |
addr += (ndw / 2) * incr; |
count -= ndw / 2; |
} |
} |
/** |
* cayman_dma_vm_pad_ib - pad the IB to the required number of dw |
* |
* @ib: indirect buffer to fill with padding |
* |
*/ |
void cayman_dma_vm_pad_ib(struct radeon_ib *ib) |
{ |
while (ib->length_dw & 0x7) |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0); |
} |
void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) |
{ |
struct radeon_ring *ring = &rdev->ring[ridx]; |
if (vm == NULL) |
return; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2)); |
radeon_ring_write(ring, vm->pd_gpu_addr >> 12); |
/* flush hdp cache */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2)); |
radeon_ring_write(ring, 1); |
/* bits 0-7 are the VM contexts0-7 */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); |
radeon_ring_write(ring, 1 << vm->id); |
} |
/drivers/video/drm/radeon/ni_dpm.c |
---|
0,0 → 1,4364 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "nid.h" |
#include "r600_dpm.h" |
#include "ni_dpm.h" |
#include "atom.h" |
#include <linux/math64.h> |
#include <linux/seq_file.h> |
#define MC_CG_ARB_FREQ_F0 0x0a |
#define MC_CG_ARB_FREQ_F1 0x0b |
#define MC_CG_ARB_FREQ_F2 0x0c |
#define MC_CG_ARB_FREQ_F3 0x0d |
#define SMC_RAM_END 0xC000 |
static const struct ni_cac_weights cac_weights_cayman_xt = |
{ |
0x15, |
0x2, |
0x19, |
0x2, |
0x8, |
0x14, |
0x2, |
0x16, |
0xE, |
0x17, |
0x13, |
0x2B, |
0x10, |
0x7, |
0x5, |
0x5, |
0x5, |
0x2, |
0x3, |
0x9, |
0x10, |
0x10, |
0x2B, |
0xA, |
0x9, |
0x4, |
0xD, |
0xD, |
0x3E, |
0x18, |
0x14, |
0, |
0x3, |
0x3, |
0x5, |
0, |
0x2, |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0x1CC, |
0, |
0x164, |
1, |
1, |
1, |
1, |
12, |
12, |
12, |
0x12, |
0x1F, |
132, |
5, |
7, |
0, |
{ 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0 }, |
true |
}; |
static const struct ni_cac_weights cac_weights_cayman_pro = |
{ |
0x16, |
0x4, |
0x10, |
0x2, |
0xA, |
0x16, |
0x2, |
0x18, |
0x10, |
0x1A, |
0x16, |
0x2D, |
0x12, |
0xA, |
0x6, |
0x6, |
0x6, |
0x2, |
0x4, |
0xB, |
0x11, |
0x11, |
0x2D, |
0xC, |
0xC, |
0x7, |
0x10, |
0x10, |
0x3F, |
0x1A, |
0x16, |
0, |
0x7, |
0x4, |
0x6, |
1, |
0x2, |
0x1, |
0, |
0, |
0, |
0, |
0, |
0, |
0x30, |
0, |
0x1CF, |
0, |
0x166, |
1, |
1, |
1, |
1, |
12, |
12, |
12, |
0x15, |
0x1F, |
132, |
6, |
6, |
0, |
{ 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0 }, |
true |
}; |
static const struct ni_cac_weights cac_weights_cayman_le = |
{ |
0x7, |
0xE, |
0x1, |
0xA, |
0x1, |
0x3F, |
0x2, |
0x18, |
0x10, |
0x1A, |
0x1, |
0x3F, |
0x1, |
0xE, |
0x6, |
0x6, |
0x6, |
0x2, |
0x4, |
0x9, |
0x1A, |
0x1A, |
0x2C, |
0xA, |
0x11, |
0x8, |
0x19, |
0x19, |
0x1, |
0x1, |
0x1A, |
0, |
0x8, |
0x5, |
0x8, |
0x1, |
0x3, |
0x1, |
0, |
0, |
0, |
0, |
0, |
0, |
0x38, |
0x38, |
0x239, |
0x3, |
0x18A, |
1, |
1, |
1, |
1, |
12, |
12, |
12, |
0x15, |
0x22, |
132, |
6, |
6, |
0, |
{ 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0 }, |
true |
}; |
#define NISLANDS_MGCG_SEQUENCE 300 |
static const u32 cayman_cgcg_cgls_default[] = |
{ |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff |
}; |
#define CAYMAN_CGCG_CGLS_DEFAULT_LENGTH sizeof(cayman_cgcg_cgls_default) / (3 * sizeof(u32)) |
static const u32 cayman_cgcg_cgls_disable[] = |
{ |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x00000644, 0x000f7902, 0x001f4180, |
0x00000644, 0x000f3802, 0x001f4180 |
}; |
#define CAYMAN_CGCG_CGLS_DISABLE_LENGTH sizeof(cayman_cgcg_cgls_disable) / (3 * sizeof(u32)) |
static const u32 cayman_cgcg_cgls_enable[] = |
{ |
0x00000644, 0x000f7882, 0x001f4080, |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000020, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000021, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000022, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000023, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000024, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000025, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000026, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000027, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000028, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000029, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000002a, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x0000002b, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff |
}; |
#define CAYMAN_CGCG_CGLS_ENABLE_LENGTH sizeof(cayman_cgcg_cgls_enable) / (3 * sizeof(u32)) |
static const u32 cayman_mgcg_default[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x00003fc4, 0xc0000000, 0xffffffff, |
0x00005448, 0x00000100, 0xffffffff, |
0x000055e4, 0x00000100, 0xffffffff, |
0x0000160c, 0x00000100, 0xffffffff, |
0x00008984, 0x06000100, 0xffffffff, |
0x0000c164, 0x00000100, 0xffffffff, |
0x00008a18, 0x00000100, 0xffffffff, |
0x0000897c, 0x06000100, 0xffffffff, |
0x00008b28, 0x00000100, 0xffffffff, |
0x00009144, 0x00800200, 0xffffffff, |
0x00009a60, 0x00000100, 0xffffffff, |
0x00009868, 0x00000100, 0xffffffff, |
0x00008d58, 0x00000100, 0xffffffff, |
0x00009510, 0x00000100, 0xffffffff, |
0x0000949c, 0x00000100, 0xffffffff, |
0x00009654, 0x00000100, 0xffffffff, |
0x00009030, 0x00000100, 0xffffffff, |
0x00009034, 0x00000100, 0xffffffff, |
0x00009038, 0x00000100, 0xffffffff, |
0x0000903c, 0x00000100, 0xffffffff, |
0x00009040, 0x00000100, 0xffffffff, |
0x0000a200, 0x00000100, 0xffffffff, |
0x0000a204, 0x00000100, 0xffffffff, |
0x0000a208, 0x00000100, 0xffffffff, |
0x0000a20c, 0x00000100, 0xffffffff, |
0x00009744, 0x00000100, 0xffffffff, |
0x00003f80, 0x00000100, 0xffffffff, |
0x0000a210, 0x00000100, 0xffffffff, |
0x0000a214, 0x00000100, 0xffffffff, |
0x000004d8, 0x00000100, 0xffffffff, |
0x00009664, 0x00000100, 0xffffffff, |
0x00009698, 0x00000100, 0xffffffff, |
0x000004d4, 0x00000200, 0xffffffff, |
0x000004d0, 0x00000000, 0xffffffff, |
0x000030cc, 0x00000104, 0xffffffff, |
0x0000d0c0, 0x00000100, 0xffffffff, |
0x0000d8c0, 0x00000100, 0xffffffff, |
0x0000802c, 0x40000000, 0xffffffff, |
0x00003fc4, 0x40000000, 0xffffffff, |
0x0000915c, 0x00010000, 0xffffffff, |
0x00009160, 0x00030002, 0xffffffff, |
0x00009164, 0x00050004, 0xffffffff, |
0x00009168, 0x00070006, 0xffffffff, |
0x00009178, 0x00070000, 0xffffffff, |
0x0000917c, 0x00030002, 0xffffffff, |
0x00009180, 0x00050004, 0xffffffff, |
0x0000918c, 0x00010006, 0xffffffff, |
0x00009190, 0x00090008, 0xffffffff, |
0x00009194, 0x00070000, 0xffffffff, |
0x00009198, 0x00030002, 0xffffffff, |
0x0000919c, 0x00050004, 0xffffffff, |
0x000091a8, 0x00010006, 0xffffffff, |
0x000091ac, 0x00090008, 0xffffffff, |
0x000091b0, 0x00070000, 0xffffffff, |
0x000091b4, 0x00030002, 0xffffffff, |
0x000091b8, 0x00050004, 0xffffffff, |
0x000091c4, 0x00010006, 0xffffffff, |
0x000091c8, 0x00090008, 0xffffffff, |
0x000091cc, 0x00070000, 0xffffffff, |
0x000091d0, 0x00030002, 0xffffffff, |
0x000091d4, 0x00050004, 0xffffffff, |
0x000091e0, 0x00010006, 0xffffffff, |
0x000091e4, 0x00090008, 0xffffffff, |
0x000091e8, 0x00000000, 0xffffffff, |
0x000091ec, 0x00070000, 0xffffffff, |
0x000091f0, 0x00030002, 0xffffffff, |
0x000091f4, 0x00050004, 0xffffffff, |
0x00009200, 0x00010006, 0xffffffff, |
0x00009204, 0x00090008, 0xffffffff, |
0x00009208, 0x00070000, 0xffffffff, |
0x0000920c, 0x00030002, 0xffffffff, |
0x00009210, 0x00050004, 0xffffffff, |
0x0000921c, 0x00010006, 0xffffffff, |
0x00009220, 0x00090008, 0xffffffff, |
0x00009224, 0x00070000, 0xffffffff, |
0x00009228, 0x00030002, 0xffffffff, |
0x0000922c, 0x00050004, 0xffffffff, |
0x00009238, 0x00010006, 0xffffffff, |
0x0000923c, 0x00090008, 0xffffffff, |
0x00009240, 0x00070000, 0xffffffff, |
0x00009244, 0x00030002, 0xffffffff, |
0x00009248, 0x00050004, 0xffffffff, |
0x00009254, 0x00010006, 0xffffffff, |
0x00009258, 0x00090008, 0xffffffff, |
0x0000925c, 0x00070000, 0xffffffff, |
0x00009260, 0x00030002, 0xffffffff, |
0x00009264, 0x00050004, 0xffffffff, |
0x00009270, 0x00010006, 0xffffffff, |
0x00009274, 0x00090008, 0xffffffff, |
0x00009278, 0x00070000, 0xffffffff, |
0x0000927c, 0x00030002, 0xffffffff, |
0x00009280, 0x00050004, 0xffffffff, |
0x0000928c, 0x00010006, 0xffffffff, |
0x00009290, 0x00090008, 0xffffffff, |
0x000092a8, 0x00070000, 0xffffffff, |
0x000092ac, 0x00030002, 0xffffffff, |
0x000092b0, 0x00050004, 0xffffffff, |
0x000092bc, 0x00010006, 0xffffffff, |
0x000092c0, 0x00090008, 0xffffffff, |
0x000092c4, 0x00070000, 0xffffffff, |
0x000092c8, 0x00030002, 0xffffffff, |
0x000092cc, 0x00050004, 0xffffffff, |
0x000092d8, 0x00010006, 0xffffffff, |
0x000092dc, 0x00090008, 0xffffffff, |
0x00009294, 0x00000000, 0xffffffff, |
0x0000802c, 0x40010000, 0xffffffff, |
0x00003fc4, 0x40010000, 0xffffffff, |
0x0000915c, 0x00010000, 0xffffffff, |
0x00009160, 0x00030002, 0xffffffff, |
0x00009164, 0x00050004, 0xffffffff, |
0x00009168, 0x00070006, 0xffffffff, |
0x00009178, 0x00070000, 0xffffffff, |
0x0000917c, 0x00030002, 0xffffffff, |
0x00009180, 0x00050004, 0xffffffff, |
0x0000918c, 0x00010006, 0xffffffff, |
0x00009190, 0x00090008, 0xffffffff, |
0x00009194, 0x00070000, 0xffffffff, |
0x00009198, 0x00030002, 0xffffffff, |
0x0000919c, 0x00050004, 0xffffffff, |
0x000091a8, 0x00010006, 0xffffffff, |
0x000091ac, 0x00090008, 0xffffffff, |
0x000091b0, 0x00070000, 0xffffffff, |
0x000091b4, 0x00030002, 0xffffffff, |
0x000091b8, 0x00050004, 0xffffffff, |
0x000091c4, 0x00010006, 0xffffffff, |
0x000091c8, 0x00090008, 0xffffffff, |
0x000091cc, 0x00070000, 0xffffffff, |
0x000091d0, 0x00030002, 0xffffffff, |
0x000091d4, 0x00050004, 0xffffffff, |
0x000091e0, 0x00010006, 0xffffffff, |
0x000091e4, 0x00090008, 0xffffffff, |
0x000091e8, 0x00000000, 0xffffffff, |
0x000091ec, 0x00070000, 0xffffffff, |
0x000091f0, 0x00030002, 0xffffffff, |
0x000091f4, 0x00050004, 0xffffffff, |
0x00009200, 0x00010006, 0xffffffff, |
0x00009204, 0x00090008, 0xffffffff, |
0x00009208, 0x00070000, 0xffffffff, |
0x0000920c, 0x00030002, 0xffffffff, |
0x00009210, 0x00050004, 0xffffffff, |
0x0000921c, 0x00010006, 0xffffffff, |
0x00009220, 0x00090008, 0xffffffff, |
0x00009224, 0x00070000, 0xffffffff, |
0x00009228, 0x00030002, 0xffffffff, |
0x0000922c, 0x00050004, 0xffffffff, |
0x00009238, 0x00010006, 0xffffffff, |
0x0000923c, 0x00090008, 0xffffffff, |
0x00009240, 0x00070000, 0xffffffff, |
0x00009244, 0x00030002, 0xffffffff, |
0x00009248, 0x00050004, 0xffffffff, |
0x00009254, 0x00010006, 0xffffffff, |
0x00009258, 0x00090008, 0xffffffff, |
0x0000925c, 0x00070000, 0xffffffff, |
0x00009260, 0x00030002, 0xffffffff, |
0x00009264, 0x00050004, 0xffffffff, |
0x00009270, 0x00010006, 0xffffffff, |
0x00009274, 0x00090008, 0xffffffff, |
0x00009278, 0x00070000, 0xffffffff, |
0x0000927c, 0x00030002, 0xffffffff, |
0x00009280, 0x00050004, 0xffffffff, |
0x0000928c, 0x00010006, 0xffffffff, |
0x00009290, 0x00090008, 0xffffffff, |
0x000092a8, 0x00070000, 0xffffffff, |
0x000092ac, 0x00030002, 0xffffffff, |
0x000092b0, 0x00050004, 0xffffffff, |
0x000092bc, 0x00010006, 0xffffffff, |
0x000092c0, 0x00090008, 0xffffffff, |
0x000092c4, 0x00070000, 0xffffffff, |
0x000092c8, 0x00030002, 0xffffffff, |
0x000092cc, 0x00050004, 0xffffffff, |
0x000092d8, 0x00010006, 0xffffffff, |
0x000092dc, 0x00090008, 0xffffffff, |
0x00009294, 0x00000000, 0xffffffff, |
0x0000802c, 0xc0000000, 0xffffffff, |
0x00003fc4, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000010, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000011, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000012, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000013, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000014, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000015, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000016, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000017, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000018, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000019, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001a, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x0000001b, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff |
}; |
#define CAYMAN_MGCG_DEFAULT_LENGTH sizeof(cayman_mgcg_default) / (3 * sizeof(u32)) |
static const u32 cayman_mgcg_disable[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000002, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x000008f8, 0x00000003, 0xffffffff, |
0x000008fc, 0xffffffff, 0xffffffff, |
0x00009150, 0x00600000, 0xffffffff |
}; |
#define CAYMAN_MGCG_DISABLE_LENGTH sizeof(cayman_mgcg_disable) / (3 * sizeof(u32)) |
static const u32 cayman_mgcg_enable[] = |
{ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x000008f8, 0x00000002, 0xffffffff, |
0x000008fc, 0x00600000, 0xffffffff, |
0x000008f8, 0x00000003, 0xffffffff, |
0x000008fc, 0x00000000, 0xffffffff, |
0x00009150, 0x96944200, 0xffffffff |
}; |
#define CAYMAN_MGCG_ENABLE_LENGTH sizeof(cayman_mgcg_enable) / (3 * sizeof(u32)) |
#define NISLANDS_SYSLS_SEQUENCE 100 |
static const u32 cayman_sysls_default[] = |
{ |
/* Register, Value, Mask bits */ |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x0000d8bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x000020c0, 0x000c0c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x00002f50, 0x00000404, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x000064ec, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00008dfc, 0x00000000, 0xffffffff |
}; |
#define CAYMAN_SYSLS_DEFAULT_LENGTH sizeof(cayman_sysls_default) / (3 * sizeof(u32)) |
static const u32 cayman_sysls_disable[] = |
{ |
/* Register, Value, Mask bits */ |
0x0000d0c0, 0x00000000, 0xffffffff, |
0x0000d8c0, 0x00000000, 0xffffffff, |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x0000d8bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x00041401, 0xffffffff, |
0x0000264c, 0x00040400, 0xffffffff, |
0x00002648, 0x00040400, 0xffffffff, |
0x00002650, 0x00040400, 0xffffffff, |
0x000020b8, 0x00040400, 0xffffffff, |
0x000020bc, 0x00040400, 0xffffffff, |
0x000020c0, 0x00040c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680000, 0xffffffff, |
0x00002f50, 0x00000404, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x000064ec, 0x00007ffd, 0xffffffff, |
0x00000c7c, 0x0000ff00, 0xffffffff, |
0x00008dfc, 0x0000007f, 0xffffffff |
}; |
#define CAYMAN_SYSLS_DISABLE_LENGTH sizeof(cayman_sysls_disable) / (3 * sizeof(u32)) |
static const u32 cayman_sysls_enable[] = |
{ |
/* Register, Value, Mask bits */ |
0x000055e8, 0x00000001, 0xffffffff, |
0x0000d0bc, 0x00000100, 0xffffffff, |
0x0000d8bc, 0x00000100, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x000020c0, 0x000c0c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x00002f50, 0x00000903, 0xffffffff, |
0x000004c8, 0x00000000, 0xffffffff, |
0x000064ec, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00008dfc, 0x00000000, 0xffffffff |
}; |
#define CAYMAN_SYSLS_ENABLE_LENGTH sizeof(cayman_sysls_enable) / (3 * sizeof(u32)) |
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; |
return pi; |
} |
struct ni_ps *ni_get_ps(struct radeon_ps *rps) |
{ |
struct ni_ps *ps = rps->ps_priv; |
return ps; |
} |
static void ni_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coeffients *coeff, |
u16 v, s32 t, |
u32 ileakage, |
u32 *leakage) |
{ |
s64 kt, kv, leakage_w, i_leakage, vddc, temperature; |
i_leakage = div64_s64(drm_int2fixp(ileakage), 1000); |
vddc = div64_s64(drm_int2fixp(v), 1000); |
temperature = div64_s64(drm_int2fixp(t), 1000); |
kt = drm_fixp_mul(div64_s64(drm_int2fixp(coeff->at), 1000), |
drm_fixp_exp(drm_fixp_mul(div64_s64(drm_int2fixp(coeff->bt), 1000), temperature))); |
kv = drm_fixp_mul(div64_s64(drm_int2fixp(coeff->av), 1000), |
drm_fixp_exp(drm_fixp_mul(div64_s64(drm_int2fixp(coeff->bv), 1000), vddc))); |
leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc); |
*leakage = drm_fixp2int(leakage_w * 1000); |
} |
static void ni_calculate_leakage_for_v_and_t(struct radeon_device *rdev, |
const struct ni_leakage_coeffients *coeff, |
u16 v, |
s32 t, |
u32 i_leakage, |
u32 *leakage) |
{ |
ni_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage); |
} |
bool ni_dpm_vblank_too_short(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 vblank_time = r600_dpm_get_vblank_time(rdev); |
/* we never hit the non-gddr5 limit so disable it */ |
u32 switch_limit = pi->mem_gddr5 ? 450 : 0; |
if (vblank_time < switch_limit) |
return true; |
else |
return false; |
} |
static void ni_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct ni_ps *ps = ni_get_ps(rps); |
struct radeon_clock_and_voltage_limits *max_limits; |
bool disable_mclk_switching; |
u32 mclk; |
u16 vddci; |
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; |
int i; |
if ((rdev->pm.dpm.new_active_crtc_count > 1) || |
ni_dpm_vblank_too_short(rdev)) |
disable_mclk_switching = true; |
else |
disable_mclk_switching = false; |
if (rdev->pm.dpm.ac_power) |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
else |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc; |
if (rdev->pm.dpm.ac_power == false) { |
for (i = 0; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].mclk > max_limits->mclk) |
ps->performance_levels[i].mclk = max_limits->mclk; |
if (ps->performance_levels[i].sclk > max_limits->sclk) |
ps->performance_levels[i].sclk = max_limits->sclk; |
if (ps->performance_levels[i].vddc > max_limits->vddc) |
ps->performance_levels[i].vddc = max_limits->vddc; |
if (ps->performance_levels[i].vddci > max_limits->vddci) |
ps->performance_levels[i].vddci = max_limits->vddci; |
} |
} |
/* limit clocks to max supported clocks based on voltage dependency tables */ |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
&max_sclk_vddc); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
&max_mclk_vddci); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
&max_mclk_vddc); |
for (i = 0; i < ps->performance_level_count; i++) { |
if (max_sclk_vddc) { |
if (ps->performance_levels[i].sclk > max_sclk_vddc) |
ps->performance_levels[i].sclk = max_sclk_vddc; |
} |
if (max_mclk_vddci) { |
if (ps->performance_levels[i].mclk > max_mclk_vddci) |
ps->performance_levels[i].mclk = max_mclk_vddci; |
} |
if (max_mclk_vddc) { |
if (ps->performance_levels[i].mclk > max_mclk_vddc) |
ps->performance_levels[i].mclk = max_mclk_vddc; |
} |
} |
/* XXX validate the min clocks required for display */ |
/* adjust low state */ |
if (disable_mclk_switching) { |
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; |
} |
btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk, |
&ps->performance_levels[0].sclk, |
&ps->performance_levels[0].mclk); |
for (i = 1; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk) |
ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk; |
if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc) |
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; |
ps->performance_levels[i].vddci = vddci; |
} |
} else { |
for (i = 1; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].mclk < ps->performance_levels[i - 1].mclk) |
ps->performance_levels[i].mclk = ps->performance_levels[i - 1].mclk; |
if (ps->performance_levels[i].vddci < ps->performance_levels[i - 1].vddci) |
ps->performance_levels[i].vddci = ps->performance_levels[i - 1].vddci; |
} |
} |
for (i = 1; i < ps->performance_level_count; i++) |
btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk, |
&ps->performance_levels[i].sclk, |
&ps->performance_levels[i].mclk); |
for (i = 0; i < ps->performance_level_count; i++) |
btc_adjust_clock_combinations(rdev, max_limits, |
&ps->performance_levels[i]); |
for (i = 0; i < ps->performance_level_count; i++) { |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
ps->performance_levels[i].sclk, |
max_limits->vddc, &ps->performance_levels[i].vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
ps->performance_levels[i].mclk, |
max_limits->vddci, &ps->performance_levels[i].vddci); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
ps->performance_levels[i].mclk, |
max_limits->vddc, &ps->performance_levels[i].vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk, |
rdev->clock.current_dispclk, |
max_limits->vddc, &ps->performance_levels[i].vddc); |
} |
for (i = 0; i < ps->performance_level_count; i++) { |
btc_apply_voltage_delta_rules(rdev, |
max_limits->vddc, max_limits->vddci, |
&ps->performance_levels[i].vddc, |
&ps->performance_levels[i].vddci); |
} |
ps->dc_compatible = true; |
for (i = 0; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].vddc > rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) |
ps->dc_compatible = false; |
if (ps->performance_levels[i].vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2) |
ps->performance_levels[i].flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2; |
} |
} |
static void ni_cg_clockgating_default(struct radeon_device *rdev) |
{ |
u32 count; |
const u32 *ps = NULL; |
ps = (const u32 *)&cayman_cgcg_cgls_default; |
count = CAYMAN_CGCG_CGLS_DEFAULT_LENGTH; |
btc_program_mgcg_hw_sequence(rdev, ps, count); |
} |
static void ni_gfx_clockgating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 count; |
const u32 *ps = NULL; |
if (enable) { |
ps = (const u32 *)&cayman_cgcg_cgls_enable; |
count = CAYMAN_CGCG_CGLS_ENABLE_LENGTH; |
} else { |
ps = (const u32 *)&cayman_cgcg_cgls_disable; |
count = CAYMAN_CGCG_CGLS_DISABLE_LENGTH; |
} |
btc_program_mgcg_hw_sequence(rdev, ps, count); |
} |
static void ni_mg_clockgating_default(struct radeon_device *rdev) |
{ |
u32 count; |
const u32 *ps = NULL; |
ps = (const u32 *)&cayman_mgcg_default; |
count = CAYMAN_MGCG_DEFAULT_LENGTH; |
btc_program_mgcg_hw_sequence(rdev, ps, count); |
} |
static void ni_mg_clockgating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 count; |
const u32 *ps = NULL; |
if (enable) { |
ps = (const u32 *)&cayman_mgcg_enable; |
count = CAYMAN_MGCG_ENABLE_LENGTH; |
} else { |
ps = (const u32 *)&cayman_mgcg_disable; |
count = CAYMAN_MGCG_DISABLE_LENGTH; |
} |
btc_program_mgcg_hw_sequence(rdev, ps, count); |
} |
static void ni_ls_clockgating_default(struct radeon_device *rdev) |
{ |
u32 count; |
const u32 *ps = NULL; |
ps = (const u32 *)&cayman_sysls_default; |
count = CAYMAN_SYSLS_DEFAULT_LENGTH; |
btc_program_mgcg_hw_sequence(rdev, ps, count); |
} |
static void ni_ls_clockgating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 count; |
const u32 *ps = NULL; |
if (enable) { |
ps = (const u32 *)&cayman_sysls_enable; |
count = CAYMAN_SYSLS_ENABLE_LENGTH; |
} else { |
ps = (const u32 *)&cayman_sysls_disable; |
count = CAYMAN_SYSLS_DISABLE_LENGTH; |
} |
btc_program_mgcg_hw_sequence(rdev, ps, count); |
} |
static int ni_patch_single_dependency_table_based_on_leakage(struct radeon_device *rdev, |
struct radeon_clock_voltage_dependency_table *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 i; |
if (table) { |
for (i = 0; i < table->count; i++) { |
if (0xff01 == table->entries[i].v) { |
if (pi->max_vddc == 0) |
return -EINVAL; |
table->entries[i].v = pi->max_vddc; |
} |
} |
} |
return 0; |
} |
static int ni_patch_dependency_tables_based_on_leakage(struct radeon_device *rdev) |
{ |
int ret = 0; |
ret = ni_patch_single_dependency_table_based_on_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk); |
ret = ni_patch_single_dependency_table_based_on_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk); |
return ret; |
} |
static void ni_stop_dpm(struct radeon_device *rdev) |
{ |
WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); |
} |
#if 0 |
static int ni_notify_hw_of_power_source(struct radeon_device *rdev, |
bool ac_power) |
{ |
if (ac_power) |
return (rv770_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
return 0; |
} |
#endif |
static PPSMC_Result ni_send_msg_to_smc_with_parameter(struct radeon_device *rdev, |
PPSMC_Msg msg, u32 parameter) |
{ |
WREG32(SMC_SCRATCH0, parameter); |
return rv770_send_msg_to_smc(rdev, msg); |
} |
static int ni_restrict_performance_levels_before_switch(struct radeon_device *rdev) |
{ |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK) |
return -EINVAL; |
return (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
int ni_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) |
return -EINVAL; |
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK) |
return -EINVAL; |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) |
return -EINVAL; |
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK) |
return -EINVAL; |
} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { |
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) |
return -EINVAL; |
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) |
return -EINVAL; |
} |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
static void ni_stop_smc(struct radeon_device *rdev) |
{ |
u32 tmp; |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(LB_SYNC_RESET_SEL) & LB_SYNC_RESET_SEL_MASK; |
if (tmp != 1) |
break; |
udelay(1); |
} |
udelay(100); |
r7xx_stop_smc(rdev); |
} |
static int ni_process_firmware_header(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_power_info *ni_pi = ni_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = rv770_read_smc_sram_dword(rdev, |
NISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
NISLANDS_SMC_FIRMWARE_HEADER_stateTable, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->state_table_start = (u16)tmp; |
ret = rv770_read_smc_sram_dword(rdev, |
NISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
NISLANDS_SMC_FIRMWARE_HEADER_softRegisters, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
pi->soft_regs_start = (u16)tmp; |
ret = rv770_read_smc_sram_dword(rdev, |
NISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
NISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
eg_pi->mc_reg_table_start = (u16)tmp; |
ret = rv770_read_smc_sram_dword(rdev, |
NISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
NISLANDS_SMC_FIRMWARE_HEADER_fanTable, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
ni_pi->fan_table_start = (u16)tmp; |
ret = rv770_read_smc_sram_dword(rdev, |
NISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
NISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
ni_pi->arb_table_start = (u16)tmp; |
ret = rv770_read_smc_sram_dword(rdev, |
NISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
NISLANDS_SMC_FIRMWARE_HEADER_cacTable, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
ni_pi->cac_table_start = (u16)tmp; |
ret = rv770_read_smc_sram_dword(rdev, |
NISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
NISLANDS_SMC_FIRMWARE_HEADER_spllTable, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
ni_pi->spll_table_start = (u16)tmp; |
return ret; |
} |
static void ni_read_clock_registers(struct radeon_device *rdev) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
ni_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL); |
ni_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2); |
ni_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3); |
ni_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4); |
ni_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM); |
ni_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2); |
ni_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL); |
ni_pi->clock_registers.mpll_ad_func_cntl_2 = RREG32(MPLL_AD_FUNC_CNTL_2); |
ni_pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL); |
ni_pi->clock_registers.mpll_dq_func_cntl_2 = RREG32(MPLL_DQ_FUNC_CNTL_2); |
ni_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL); |
ni_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL); |
ni_pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1); |
ni_pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2); |
} |
#if 0 |
static int ni_enter_ulp_state(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (pi->gfx_clock_gating) { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); |
RREG32(GB_ADDR_CONFIG); |
} |
WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower), |
~HOST_SMC_MSG_MASK); |
udelay(25000); |
return 0; |
} |
#endif |
static void ni_program_response_times(struct radeon_device *rdev) |
{ |
u32 voltage_response_time, backbias_response_time, acpi_delay_time, vbi_time_out; |
u32 vddc_dly, bb_dly, acpi_dly, vbi_dly, mclk_switch_limit; |
u32 reference_clock; |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mvdd_chg_time, 1); |
voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time; |
backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time; |
if (voltage_response_time == 0) |
voltage_response_time = 1000; |
if (backbias_response_time == 0) |
backbias_response_time = 1000; |
acpi_delay_time = 15000; |
vbi_time_out = 100000; |
reference_clock = radeon_get_xclk(rdev); |
vddc_dly = (voltage_response_time * reference_clock) / 1600; |
bb_dly = (backbias_response_time * reference_clock) / 1600; |
acpi_dly = (acpi_delay_time * reference_clock) / 1600; |
vbi_dly = (vbi_time_out * reference_clock) / 1600; |
mclk_switch_limit = (460 * reference_clock) / 100; |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_vreg, vddc_dly); |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_bbias, bb_dly); |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_acpi, acpi_dly); |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly); |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mc_block_delay, 0xAA); |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mclk_switch_lim, mclk_switch_limit); |
} |
static void ni_populate_smc_voltage_table(struct radeon_device *rdev, |
struct atom_voltage_table *voltage_table, |
NISLANDS_SMC_STATETABLE *table) |
{ |
unsigned int i; |
for (i = 0; i < voltage_table->count; i++) { |
table->highSMIO[i] = 0; |
table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low); |
} |
} |
static void ni_populate_smc_voltage_tables(struct radeon_device *rdev, |
NISLANDS_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
unsigned char i; |
if (eg_pi->vddc_voltage_table.count) { |
ni_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table); |
table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDC] = 0; |
table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDC] = |
cpu_to_be32(eg_pi->vddc_voltage_table.mask_low); |
for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) { |
if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) { |
table->maxVDDCIndexInPPTable = i; |
break; |
} |
} |
} |
if (eg_pi->vddci_voltage_table.count) { |
ni_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table); |
table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] = 0; |
table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] = |
cpu_to_be32(eg_pi->vddci_voltage_table.mask_low); |
} |
} |
static int ni_populate_voltage_value(struct radeon_device *rdev, |
struct atom_voltage_table *table, |
u16 value, |
NISLANDS_SMC_VOLTAGE_VALUE *voltage) |
{ |
unsigned int i; |
for (i = 0; i < table->count; i++) { |
if (value <= table->entries[i].value) { |
voltage->index = (u8)i; |
voltage->value = cpu_to_be16(table->entries[i].value); |
break; |
} |
} |
if (i >= table->count) |
return -EINVAL; |
return 0; |
} |
static void ni_populate_mvdd_value(struct radeon_device *rdev, |
u32 mclk, |
NISLANDS_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (!pi->mvdd_control) { |
voltage->index = eg_pi->mvdd_high_index; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
return; |
} |
if (mclk <= pi->mvdd_split_frequency) { |
voltage->index = eg_pi->mvdd_low_index; |
voltage->value = cpu_to_be16(MVDD_LOW_VALUE); |
} else { |
voltage->index = eg_pi->mvdd_high_index; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
} |
} |
static int ni_get_std_voltage_value(struct radeon_device *rdev, |
NISLANDS_SMC_VOLTAGE_VALUE *voltage, |
u16 *std_voltage) |
{ |
if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries && |
((u32)voltage->index < rdev->pm.dpm.dyn_state.cac_leakage_table.count)) |
*std_voltage = rdev->pm.dpm.dyn_state.cac_leakage_table.entries[voltage->index].vddc; |
else |
*std_voltage = be16_to_cpu(voltage->value); |
return 0; |
} |
static void ni_populate_std_voltage_value(struct radeon_device *rdev, |
u16 value, u8 index, |
NISLANDS_SMC_VOLTAGE_VALUE *voltage) |
{ |
voltage->index = index; |
voltage->value = cpu_to_be16(value); |
} |
static u32 ni_get_smc_power_scaling_factor(struct radeon_device *rdev) |
{ |
u32 xclk_period; |
u32 xclk = radeon_get_xclk(rdev); |
u32 tmp = RREG32(CG_CAC_CTRL) & TID_CNT_MASK; |
xclk_period = (1000000000UL / xclk); |
xclk_period /= 10000UL; |
return tmp * xclk_period; |
} |
static u32 ni_scale_power_for_smc(u32 power_in_watts, u32 scaling_factor) |
{ |
return (power_in_watts * scaling_factor) << 2; |
} |
static u32 ni_calculate_power_boost_limit(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
u32 near_tdp_limit) |
{ |
struct ni_ps *state = ni_get_ps(radeon_state); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 power_boost_limit = 0; |
int ret; |
if (ni_pi->enable_power_containment && |
ni_pi->use_power_boost_limit) { |
NISLANDS_SMC_VOLTAGE_VALUE vddc; |
u16 std_vddc_med; |
u16 std_vddc_high; |
u64 tmp, n, d; |
if (state->performance_level_count < 3) |
return 0; |
ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
state->performance_levels[state->performance_level_count - 2].vddc, |
&vddc); |
if (ret) |
return 0; |
ret = ni_get_std_voltage_value(rdev, &vddc, &std_vddc_med); |
if (ret) |
return 0; |
ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
state->performance_levels[state->performance_level_count - 1].vddc, |
&vddc); |
if (ret) |
return 0; |
ret = ni_get_std_voltage_value(rdev, &vddc, &std_vddc_high); |
if (ret) |
return 0; |
n = ((u64)near_tdp_limit * ((u64)std_vddc_med * (u64)std_vddc_med) * 90); |
d = ((u64)std_vddc_high * (u64)std_vddc_high * 100); |
tmp = div64_u64(n, d); |
if (tmp >> 32) |
return 0; |
power_boost_limit = (u32)tmp; |
} |
return power_boost_limit; |
} |
static int ni_calculate_adjusted_tdp_limits(struct radeon_device *rdev, |
bool adjust_polarity, |
u32 tdp_adjustment, |
u32 *tdp_limit, |
u32 *near_tdp_limit) |
{ |
if (tdp_adjustment > (u32)rdev->pm.dpm.tdp_od_limit) |
return -EINVAL; |
if (adjust_polarity) { |
*tdp_limit = ((100 + tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100; |
*near_tdp_limit = rdev->pm.dpm.near_tdp_limit + (*tdp_limit - rdev->pm.dpm.tdp_limit); |
} else { |
*tdp_limit = ((100 - tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100; |
*near_tdp_limit = rdev->pm.dpm.near_tdp_limit - (rdev->pm.dpm.tdp_limit - *tdp_limit); |
} |
return 0; |
} |
static int ni_populate_smc_tdp_limits(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
if (ni_pi->enable_power_containment) { |
NISLANDS_SMC_STATETABLE *smc_table = &ni_pi->smc_statetable; |
u32 scaling_factor = ni_get_smc_power_scaling_factor(rdev); |
u32 tdp_limit; |
u32 near_tdp_limit; |
u32 power_boost_limit; |
int ret; |
if (scaling_factor == 0) |
return -EINVAL; |
memset(smc_table, 0, sizeof(NISLANDS_SMC_STATETABLE)); |
ret = ni_calculate_adjusted_tdp_limits(rdev, |
false, /* ??? */ |
rdev->pm.dpm.tdp_adjustment, |
&tdp_limit, |
&near_tdp_limit); |
if (ret) |
return ret; |
power_boost_limit = ni_calculate_power_boost_limit(rdev, radeon_state, |
near_tdp_limit); |
smc_table->dpm2Params.TDPLimit = |
cpu_to_be32(ni_scale_power_for_smc(tdp_limit, scaling_factor)); |
smc_table->dpm2Params.NearTDPLimit = |
cpu_to_be32(ni_scale_power_for_smc(near_tdp_limit, scaling_factor)); |
smc_table->dpm2Params.SafePowerLimit = |
cpu_to_be32(ni_scale_power_for_smc((near_tdp_limit * NISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, |
scaling_factor)); |
smc_table->dpm2Params.PowerBoostLimit = |
cpu_to_be32(ni_scale_power_for_smc(power_boost_limit, scaling_factor)); |
ret = rv770_copy_bytes_to_smc(rdev, |
(u16)(pi->state_table_start + offsetof(NISLANDS_SMC_STATETABLE, dpm2Params) + |
offsetof(PP_NIslands_DPM2Parameters, TDPLimit)), |
(u8 *)(&smc_table->dpm2Params.TDPLimit), |
sizeof(u32) * 4, pi->sram_end); |
if (ret) |
return ret; |
} |
return 0; |
} |
int ni_copy_and_switch_arb_sets(struct radeon_device *rdev, |
u32 arb_freq_src, u32 arb_freq_dest) |
{ |
u32 mc_arb_dram_timing; |
u32 mc_arb_dram_timing2; |
u32 burst_time; |
u32 mc_cg_config; |
switch (arb_freq_src) { |
case MC_CG_ARB_FREQ_F0: |
mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE0_MASK) >> STATE0_SHIFT; |
break; |
case MC_CG_ARB_FREQ_F1: |
mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING_1); |
mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_1); |
burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE1_MASK) >> STATE1_SHIFT; |
break; |
case MC_CG_ARB_FREQ_F2: |
mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING_2); |
mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_2); |
burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE2_MASK) >> STATE2_SHIFT; |
break; |
case MC_CG_ARB_FREQ_F3: |
mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING_3); |
mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_3); |
burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE3_MASK) >> STATE3_SHIFT; |
break; |
default: |
return -EINVAL; |
} |
switch (arb_freq_dest) { |
case MC_CG_ARB_FREQ_F0: |
WREG32(MC_ARB_DRAM_TIMING, mc_arb_dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2, mc_arb_dram_timing2); |
WREG32_P(MC_ARB_BURST_TIME, STATE0(burst_time), ~STATE0_MASK); |
break; |
case MC_CG_ARB_FREQ_F1: |
WREG32(MC_ARB_DRAM_TIMING_1, mc_arb_dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2); |
WREG32_P(MC_ARB_BURST_TIME, STATE1(burst_time), ~STATE1_MASK); |
break; |
case MC_CG_ARB_FREQ_F2: |
WREG32(MC_ARB_DRAM_TIMING_2, mc_arb_dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2_2, mc_arb_dram_timing2); |
WREG32_P(MC_ARB_BURST_TIME, STATE2(burst_time), ~STATE2_MASK); |
break; |
case MC_CG_ARB_FREQ_F3: |
WREG32(MC_ARB_DRAM_TIMING_3, mc_arb_dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2_3, mc_arb_dram_timing2); |
WREG32_P(MC_ARB_BURST_TIME, STATE3(burst_time), ~STATE3_MASK); |
break; |
default: |
return -EINVAL; |
} |
mc_cg_config = RREG32(MC_CG_CONFIG) | 0x0000000F; |
WREG32(MC_CG_CONFIG, mc_cg_config); |
WREG32_P(MC_ARB_CG, CG_ARB_REQ(arb_freq_dest), ~CG_ARB_REQ_MASK); |
return 0; |
} |
static int ni_init_arb_table_index(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = rv770_read_smc_sram_dword(rdev, ni_pi->arb_table_start, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
tmp &= 0x00FFFFFF; |
tmp |= ((u32)MC_CG_ARB_FREQ_F1) << 24; |
return rv770_write_smc_sram_dword(rdev, ni_pi->arb_table_start, |
tmp, pi->sram_end); |
} |
static int ni_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev) |
{ |
return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1); |
} |
static int ni_force_switch_to_arb_f0(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = rv770_read_smc_sram_dword(rdev, ni_pi->arb_table_start, |
&tmp, pi->sram_end); |
if (ret) |
return ret; |
tmp = (tmp >> 24) & 0xff; |
if (tmp == MC_CG_ARB_FREQ_F0) |
return 0; |
return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0); |
} |
static int ni_populate_memory_timing_parameters(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
SMC_NIslands_MCArbDramTimingRegisterSet *arb_regs) |
{ |
u32 dram_timing; |
u32 dram_timing2; |
arb_regs->mc_arb_rfsh_rate = |
(u8)rv770_calculate_memory_refresh_rate(rdev, pl->sclk); |
radeon_atom_set_engine_dram_timings(rdev, |
pl->sclk, |
pl->mclk); |
dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
arb_regs->mc_arb_dram_timing = cpu_to_be32(dram_timing); |
arb_regs->mc_arb_dram_timing2 = cpu_to_be32(dram_timing2); |
return 0; |
} |
static int ni_do_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
unsigned int first_arb_set) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
SMC_NIslands_MCArbDramTimingRegisterSet arb_regs = { 0 }; |
int i, ret = 0; |
for (i = 0; i < state->performance_level_count; i++) { |
ret = ni_populate_memory_timing_parameters(rdev, &state->performance_levels[i], &arb_regs); |
if (ret) |
break; |
ret = rv770_copy_bytes_to_smc(rdev, |
(u16)(ni_pi->arb_table_start + |
offsetof(SMC_NIslands_MCArbDramTimingRegisters, data) + |
sizeof(SMC_NIslands_MCArbDramTimingRegisterSet) * (first_arb_set + i)), |
(u8 *)&arb_regs, |
(u16)sizeof(SMC_NIslands_MCArbDramTimingRegisterSet), |
pi->sram_end); |
if (ret) |
break; |
} |
return ret; |
} |
static int ni_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
return ni_do_program_memory_timing_parameters(rdev, radeon_new_state, |
NISLANDS_DRIVER_STATE_ARB_INDEX); |
} |
static void ni_populate_initial_mvdd_value(struct radeon_device *rdev, |
struct NISLANDS_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
voltage->index = eg_pi->mvdd_high_index; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
} |
static int ni_populate_smc_initial_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_initial_state, |
NISLANDS_SMC_STATETABLE *table) |
{ |
struct ni_ps *initial_state = ni_get_ps(radeon_initial_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 reg; |
int ret; |
table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL = |
cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl); |
table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 = |
cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl_2); |
table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL = |
cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl); |
table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 = |
cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl_2); |
table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL = |
cpu_to_be32(ni_pi->clock_registers.mclk_pwrmgt_cntl); |
table->initialState.levels[0].mclk.vDLL_CNTL = |
cpu_to_be32(ni_pi->clock_registers.dll_cntl); |
table->initialState.levels[0].mclk.vMPLL_SS = |
cpu_to_be32(ni_pi->clock_registers.mpll_ss1); |
table->initialState.levels[0].mclk.vMPLL_SS2 = |
cpu_to_be32(ni_pi->clock_registers.mpll_ss2); |
table->initialState.levels[0].mclk.mclk_value = |
cpu_to_be32(initial_state->performance_levels[0].mclk); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = |
cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = |
cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_2); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = |
cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_3); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 = |
cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_4); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM = |
cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 = |
cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum_2); |
table->initialState.levels[0].sclk.sclk_value = |
cpu_to_be32(initial_state->performance_levels[0].sclk); |
table->initialState.levels[0].arbRefreshState = |
NISLANDS_INITIAL_STATE_ARB_INDEX; |
table->initialState.levels[0].ACIndex = 0; |
ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
initial_state->performance_levels[0].vddc, |
&table->initialState.levels[0].vddc); |
if (!ret) { |
u16 std_vddc; |
ret = ni_get_std_voltage_value(rdev, |
&table->initialState.levels[0].vddc, |
&std_vddc); |
if (!ret) |
ni_populate_std_voltage_value(rdev, std_vddc, |
table->initialState.levels[0].vddc.index, |
&table->initialState.levels[0].std_vddc); |
} |
if (eg_pi->vddci_control) |
ni_populate_voltage_value(rdev, |
&eg_pi->vddci_voltage_table, |
initial_state->performance_levels[0].vddci, |
&table->initialState.levels[0].vddci); |
ni_populate_initial_mvdd_value(rdev, &table->initialState.levels[0].mvdd); |
reg = CG_R(0xffff) | CG_L(0); |
table->initialState.levels[0].aT = cpu_to_be32(reg); |
table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp); |
if (pi->boot_in_gen2) |
table->initialState.levels[0].gen2PCIE = 1; |
else |
table->initialState.levels[0].gen2PCIE = 0; |
if (pi->mem_gddr5) { |
table->initialState.levels[0].strobeMode = |
cypress_get_strobe_mode_settings(rdev, |
initial_state->performance_levels[0].mclk); |
if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold) |
table->initialState.levels[0].mcFlags = NISLANDS_SMC_MC_EDC_RD_FLAG | NISLANDS_SMC_MC_EDC_WR_FLAG; |
else |
table->initialState.levels[0].mcFlags = 0; |
} |
table->initialState.levelCount = 1; |
table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC; |
table->initialState.levels[0].dpm2.MaxPS = 0; |
table->initialState.levels[0].dpm2.NearTDPDec = 0; |
table->initialState.levels[0].dpm2.AboveSafeInc = 0; |
table->initialState.levels[0].dpm2.BelowSafeInc = 0; |
reg = MIN_POWER_MASK | MAX_POWER_MASK; |
table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg); |
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; |
table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg); |
return 0; |
} |
static int ni_populate_smc_acpi_state(struct radeon_device *rdev, |
NISLANDS_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 mpll_ad_func_cntl = ni_pi->clock_registers.mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2 = ni_pi->clock_registers.mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl = ni_pi->clock_registers.mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2 = ni_pi->clock_registers.mpll_dq_func_cntl_2; |
u32 spll_func_cntl = ni_pi->clock_registers.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = ni_pi->clock_registers.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = ni_pi->clock_registers.cg_spll_func_cntl_3; |
u32 spll_func_cntl_4 = ni_pi->clock_registers.cg_spll_func_cntl_4; |
u32 mclk_pwrmgt_cntl = ni_pi->clock_registers.mclk_pwrmgt_cntl; |
u32 dll_cntl = ni_pi->clock_registers.dll_cntl; |
u32 reg; |
int ret; |
table->ACPIState = table->initialState; |
table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC; |
if (pi->acpi_vddc) { |
ret = ni_populate_voltage_value(rdev, |
&eg_pi->vddc_voltage_table, |
pi->acpi_vddc, &table->ACPIState.levels[0].vddc); |
if (!ret) { |
u16 std_vddc; |
ret = ni_get_std_voltage_value(rdev, |
&table->ACPIState.levels[0].vddc, &std_vddc); |
if (!ret) |
ni_populate_std_voltage_value(rdev, std_vddc, |
table->ACPIState.levels[0].vddc.index, |
&table->ACPIState.levels[0].std_vddc); |
} |
if (pi->pcie_gen2) { |
if (pi->acpi_pcie_gen2) |
table->ACPIState.levels[0].gen2PCIE = 1; |
else |
table->ACPIState.levels[0].gen2PCIE = 0; |
} else { |
table->ACPIState.levels[0].gen2PCIE = 0; |
} |
} else { |
ret = ni_populate_voltage_value(rdev, |
&eg_pi->vddc_voltage_table, |
pi->min_vddc_in_table, |
&table->ACPIState.levels[0].vddc); |
if (!ret) { |
u16 std_vddc; |
ret = ni_get_std_voltage_value(rdev, |
&table->ACPIState.levels[0].vddc, |
&std_vddc); |
if (!ret) |
ni_populate_std_voltage_value(rdev, std_vddc, |
table->ACPIState.levels[0].vddc.index, |
&table->ACPIState.levels[0].std_vddc); |
} |
table->ACPIState.levels[0].gen2PCIE = 0; |
} |
if (eg_pi->acpi_vddci) { |
if (eg_pi->vddci_control) |
ni_populate_voltage_value(rdev, |
&eg_pi->vddci_voltage_table, |
eg_pi->acpi_vddci, |
&table->ACPIState.levels[0].vddci); |
} |
mpll_ad_func_cntl &= ~PDNB; |
mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN; |
if (pi->mem_gddr5) |
mpll_dq_func_cntl &= ~PDNB; |
mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN | BYPASS; |
mclk_pwrmgt_cntl |= (MRDCKA0_RESET | |
MRDCKA1_RESET | |
MRDCKB0_RESET | |
MRDCKB1_RESET | |
MRDCKC0_RESET | |
MRDCKC1_RESET | |
MRDCKD0_RESET | |
MRDCKD1_RESET); |
mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB | |
MRDCKA1_PDNB | |
MRDCKB0_PDNB | |
MRDCKB1_PDNB | |
MRDCKC0_PDNB | |
MRDCKC1_PDNB | |
MRDCKD0_PDNB | |
MRDCKD1_PDNB); |
dll_cntl |= (MRDCKA0_BYPASS | |
MRDCKA1_BYPASS | |
MRDCKB0_BYPASS | |
MRDCKB1_BYPASS | |
MRDCKC0_BYPASS | |
MRDCKC1_BYPASS | |
MRDCKD0_BYPASS | |
MRDCKD1_BYPASS); |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(4); |
table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); |
table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); |
table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); |
table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); |
table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
table->ACPIState.levels[0].mclk.vDLL_CNTL = cpu_to_be32(dll_cntl); |
table->ACPIState.levels[0].mclk.mclk_value = 0; |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(spll_func_cntl_4); |
table->ACPIState.levels[0].sclk.sclk_value = 0; |
ni_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd); |
if (eg_pi->dynamic_ac_timing) |
table->ACPIState.levels[0].ACIndex = 1; |
table->ACPIState.levels[0].dpm2.MaxPS = 0; |
table->ACPIState.levels[0].dpm2.NearTDPDec = 0; |
table->ACPIState.levels[0].dpm2.AboveSafeInc = 0; |
table->ACPIState.levels[0].dpm2.BelowSafeInc = 0; |
reg = MIN_POWER_MASK | MAX_POWER_MASK; |
table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg); |
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; |
table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg); |
return 0; |
} |
static int ni_init_smc_table(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
int ret; |
struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps; |
NISLANDS_SMC_STATETABLE *table = &ni_pi->smc_statetable; |
memset(table, 0, sizeof(NISLANDS_SMC_STATETABLE)); |
ni_populate_smc_voltage_tables(rdev, table); |
switch (rdev->pm.int_thermal_type) { |
case THERMAL_TYPE_NI: |
case THERMAL_TYPE_EMC2103_WITH_INTERNAL: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL; |
break; |
case THERMAL_TYPE_NONE: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE; |
break; |
default: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL; |
break; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT) |
table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; |
if (pi->mem_gddr5) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5; |
ret = ni_populate_smc_initial_state(rdev, radeon_boot_state, table); |
if (ret) |
return ret; |
ret = ni_populate_smc_acpi_state(rdev, table); |
if (ret) |
return ret; |
table->driverState = table->initialState; |
table->ULVState = table->initialState; |
ret = ni_do_program_memory_timing_parameters(rdev, radeon_boot_state, |
NISLANDS_INITIAL_STATE_ARB_INDEX); |
if (ret) |
return ret; |
return rv770_copy_bytes_to_smc(rdev, pi->state_table_start, (u8 *)table, |
sizeof(NISLANDS_SMC_STATETABLE), pi->sram_end); |
} |
static int ni_calculate_sclk_params(struct radeon_device *rdev, |
u32 engine_clock, |
NISLANDS_SMC_SCLK_VALUE *sclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct atom_clock_dividers dividers; |
u32 spll_func_cntl = ni_pi->clock_registers.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = ni_pi->clock_registers.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = ni_pi->clock_registers.cg_spll_func_cntl_3; |
u32 spll_func_cntl_4 = ni_pi->clock_registers.cg_spll_func_cntl_4; |
u32 cg_spll_spread_spectrum = ni_pi->clock_registers.cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2 = ni_pi->clock_registers.cg_spll_spread_spectrum_2; |
u64 tmp; |
u32 reference_clock = rdev->clock.spll.reference_freq; |
u32 reference_divider; |
u32 fbdiv; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
engine_clock, false, ÷rs); |
if (ret) |
return ret; |
reference_divider = 1 + dividers.ref_div; |
tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16834; |
do_div(tmp, reference_clock); |
fbdiv = (u32) tmp; |
spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK); |
spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div); |
spll_func_cntl |= SPLL_PDIV_A(dividers.post_div); |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(2); |
spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK; |
spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv); |
spll_func_cntl_3 |= SPLL_DITHEN; |
if (pi->sclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = engine_clock * dividers.post_div; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, vco_freq)) { |
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); |
u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000); |
cg_spll_spread_spectrum &= ~CLK_S_MASK; |
cg_spll_spread_spectrum |= CLK_S(clk_s); |
cg_spll_spread_spectrum |= SSEN; |
cg_spll_spread_spectrum_2 &= ~CLK_V_MASK; |
cg_spll_spread_spectrum_2 |= CLK_V(clk_v); |
} |
} |
sclk->sclk_value = engine_clock; |
sclk->vCG_SPLL_FUNC_CNTL = spll_func_cntl; |
sclk->vCG_SPLL_FUNC_CNTL_2 = spll_func_cntl_2; |
sclk->vCG_SPLL_FUNC_CNTL_3 = spll_func_cntl_3; |
sclk->vCG_SPLL_FUNC_CNTL_4 = spll_func_cntl_4; |
sclk->vCG_SPLL_SPREAD_SPECTRUM = cg_spll_spread_spectrum; |
sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cg_spll_spread_spectrum_2; |
return 0; |
} |
static int ni_populate_sclk_value(struct radeon_device *rdev, |
u32 engine_clock, |
NISLANDS_SMC_SCLK_VALUE *sclk) |
{ |
NISLANDS_SMC_SCLK_VALUE sclk_tmp; |
int ret; |
ret = ni_calculate_sclk_params(rdev, engine_clock, &sclk_tmp); |
if (!ret) { |
sclk->sclk_value = cpu_to_be32(sclk_tmp.sclk_value); |
sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL); |
sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_2); |
sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_3); |
sclk->vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_4); |
sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM); |
sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM_2); |
} |
return ret; |
} |
static int ni_init_smc_spll_table(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
SMC_NISLANDS_SPLL_DIV_TABLE *spll_table; |
NISLANDS_SMC_SCLK_VALUE sclk_params; |
u32 fb_div; |
u32 p_div; |
u32 clk_s; |
u32 clk_v; |
u32 sclk = 0; |
int i, ret; |
u32 tmp; |
if (ni_pi->spll_table_start == 0) |
return -EINVAL; |
spll_table = kzalloc(sizeof(SMC_NISLANDS_SPLL_DIV_TABLE), GFP_KERNEL); |
if (spll_table == NULL) |
return -ENOMEM; |
for (i = 0; i < 256; i++) { |
ret = ni_calculate_sclk_params(rdev, sclk, &sclk_params); |
if (ret) |
break; |
p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT; |
fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT; |
clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT; |
clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT; |
fb_div &= ~0x00001FFF; |
fb_div >>= 1; |
clk_v >>= 6; |
if (p_div & ~(SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT)) |
ret = -EINVAL; |
if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT)) |
ret = -EINVAL; |
if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT)) |
ret = -EINVAL; |
if (clk_v & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT)) |
ret = -EINVAL; |
if (ret) |
break; |
tmp = ((fb_div << SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK) | |
((p_div << SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK); |
spll_table->freq[i] = cpu_to_be32(tmp); |
tmp = ((clk_v << SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK) | |
((clk_s << SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK); |
spll_table->ss[i] = cpu_to_be32(tmp); |
sclk += 512; |
} |
if (!ret) |
ret = rv770_copy_bytes_to_smc(rdev, ni_pi->spll_table_start, (u8 *)spll_table, |
sizeof(SMC_NISLANDS_SPLL_DIV_TABLE), pi->sram_end); |
kfree(spll_table); |
return ret; |
} |
static int ni_populate_mclk_value(struct radeon_device *rdev, |
u32 engine_clock, |
u32 memory_clock, |
NISLANDS_SMC_MCLK_VALUE *mclk, |
bool strobe_mode, |
bool dll_state_on) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 mpll_ad_func_cntl = ni_pi->clock_registers.mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2 = ni_pi->clock_registers.mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl = ni_pi->clock_registers.mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2 = ni_pi->clock_registers.mpll_dq_func_cntl_2; |
u32 mclk_pwrmgt_cntl = ni_pi->clock_registers.mclk_pwrmgt_cntl; |
u32 dll_cntl = ni_pi->clock_registers.dll_cntl; |
u32 mpll_ss1 = ni_pi->clock_registers.mpll_ss1; |
u32 mpll_ss2 = ni_pi->clock_registers.mpll_ss2; |
struct atom_clock_dividers dividers; |
u32 ibias; |
u32 dll_speed; |
int ret; |
u32 mc_seq_misc7; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, |
memory_clock, strobe_mode, ÷rs); |
if (ret) |
return ret; |
if (!strobe_mode) { |
mc_seq_misc7 = RREG32(MC_SEQ_MISC7); |
if (mc_seq_misc7 & 0x8000000) |
dividers.post_div = 1; |
} |
ibias = cypress_map_clkf_to_ibias(rdev, dividers.whole_fb_div); |
mpll_ad_func_cntl &= ~(CLKR_MASK | |
YCLK_POST_DIV_MASK | |
CLKF_MASK | |
CLKFRAC_MASK | |
IBIAS_MASK); |
mpll_ad_func_cntl |= CLKR(dividers.ref_div); |
mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div); |
mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div); |
mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div); |
mpll_ad_func_cntl |= IBIAS(ibias); |
if (dividers.vco_mode) |
mpll_ad_func_cntl_2 |= VCO_MODE; |
else |
mpll_ad_func_cntl_2 &= ~VCO_MODE; |
if (pi->mem_gddr5) { |
mpll_dq_func_cntl &= ~(CLKR_MASK | |
YCLK_POST_DIV_MASK | |
CLKF_MASK | |
CLKFRAC_MASK | |
IBIAS_MASK); |
mpll_dq_func_cntl |= CLKR(dividers.ref_div); |
mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div); |
mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div); |
mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div); |
mpll_dq_func_cntl |= IBIAS(ibias); |
if (strobe_mode) |
mpll_dq_func_cntl &= ~PDNB; |
else |
mpll_dq_func_cntl |= PDNB; |
if (dividers.vco_mode) |
mpll_dq_func_cntl_2 |= VCO_MODE; |
else |
mpll_dq_func_cntl_2 &= ~VCO_MODE; |
} |
if (pi->mclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = memory_clock * dividers.post_div; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, vco_freq)) { |
u32 reference_clock = rdev->clock.mpll.reference_freq; |
u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div); |
u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
u32 clk_v = ss.percentage * |
(0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625); |
mpll_ss1 &= ~CLKV_MASK; |
mpll_ss1 |= CLKV(clk_v); |
mpll_ss2 &= ~CLKS_MASK; |
mpll_ss2 |= CLKS(clk_s); |
} |
} |
dll_speed = rv740_get_dll_speed(pi->mem_gddr5, |
memory_clock); |
mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK; |
mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed); |
if (dll_state_on) |
mclk_pwrmgt_cntl |= (MRDCKA0_PDNB | |
MRDCKA1_PDNB | |
MRDCKB0_PDNB | |
MRDCKB1_PDNB | |
MRDCKC0_PDNB | |
MRDCKC1_PDNB | |
MRDCKD0_PDNB | |
MRDCKD1_PDNB); |
else |
mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB | |
MRDCKA1_PDNB | |
MRDCKB0_PDNB | |
MRDCKB1_PDNB | |
MRDCKC0_PDNB | |
MRDCKC1_PDNB | |
MRDCKD0_PDNB | |
MRDCKD1_PDNB); |
mclk->mclk_value = cpu_to_be32(memory_clock); |
mclk->vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); |
mclk->vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); |
mclk->vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); |
mclk->vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); |
mclk->vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
mclk->vDLL_CNTL = cpu_to_be32(dll_cntl); |
mclk->vMPLL_SS = cpu_to_be32(mpll_ss1); |
mclk->vMPLL_SS2 = cpu_to_be32(mpll_ss2); |
return 0; |
} |
static void ni_populate_smc_sp(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
NISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct ni_ps *ps = ni_get_ps(radeon_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int i; |
for (i = 0; i < ps->performance_level_count - 1; i++) |
smc_state->levels[i].bSP = cpu_to_be32(pi->dsp); |
smc_state->levels[ps->performance_level_count - 1].bSP = |
cpu_to_be32(pi->psp); |
} |
static int ni_convert_power_level_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
NISLANDS_SMC_HW_PERFORMANCE_LEVEL *level) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
int ret; |
bool dll_state_on; |
u16 std_vddc; |
u32 tmp = RREG32(DC_STUTTER_CNTL); |
level->gen2PCIE = pi->pcie_gen2 ? |
((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0; |
ret = ni_populate_sclk_value(rdev, pl->sclk, &level->sclk); |
if (ret) |
return ret; |
level->mcFlags = 0; |
if (pi->mclk_stutter_mode_threshold && |
(pl->mclk <= pi->mclk_stutter_mode_threshold) && |
!eg_pi->uvd_enabled && |
(tmp & DC_STUTTER_ENABLE_A) && |
(tmp & DC_STUTTER_ENABLE_B)) |
level->mcFlags |= NISLANDS_SMC_MC_STUTTER_EN; |
if (pi->mem_gddr5) { |
if (pl->mclk > pi->mclk_edc_enable_threshold) |
level->mcFlags |= NISLANDS_SMC_MC_EDC_RD_FLAG; |
if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold) |
level->mcFlags |= NISLANDS_SMC_MC_EDC_WR_FLAG; |
level->strobeMode = cypress_get_strobe_mode_settings(rdev, pl->mclk); |
if (level->strobeMode & NISLANDS_SMC_STROBE_ENABLE) { |
if (cypress_get_mclk_frequency_ratio(rdev, pl->mclk, true) >= |
((RREG32(MC_SEQ_MISC7) >> 16) & 0xf)) |
dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false; |
else |
dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false; |
} else { |
dll_state_on = false; |
if (pl->mclk > ni_pi->mclk_rtt_mode_threshold) |
level->mcFlags |= NISLANDS_SMC_MC_RTT_ENABLE; |
} |
ret = ni_populate_mclk_value(rdev, pl->sclk, pl->mclk, |
&level->mclk, |
(level->strobeMode & NISLANDS_SMC_STROBE_ENABLE) != 0, |
dll_state_on); |
} else |
ret = ni_populate_mclk_value(rdev, pl->sclk, pl->mclk, &level->mclk, 1, 1); |
if (ret) |
return ret; |
ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
pl->vddc, &level->vddc); |
if (ret) |
return ret; |
ret = ni_get_std_voltage_value(rdev, &level->vddc, &std_vddc); |
if (ret) |
return ret; |
ni_populate_std_voltage_value(rdev, std_vddc, |
level->vddc.index, &level->std_vddc); |
if (eg_pi->vddci_control) { |
ret = ni_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table, |
pl->vddci, &level->vddci); |
if (ret) |
return ret; |
} |
ni_populate_mvdd_value(rdev, pl->mclk, &level->mvdd); |
return ret; |
} |
static int ni_populate_smc_t(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
NISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
u32 a_t; |
u32 t_l, t_h; |
u32 high_bsp; |
int i, ret; |
if (state->performance_level_count >= 9) |
return -EINVAL; |
if (state->performance_level_count < 2) { |
a_t = CG_R(0xffff) | CG_L(0); |
smc_state->levels[0].aT = cpu_to_be32(a_t); |
return 0; |
} |
smc_state->levels[0].aT = cpu_to_be32(0); |
for (i = 0; i <= state->performance_level_count - 2; i++) { |
if (eg_pi->uvd_enabled) |
ret = r600_calculate_at( |
1000 * (i * (eg_pi->smu_uvd_hs ? 2 : 8) + 2), |
100 * R600_AH_DFLT, |
state->performance_levels[i + 1].sclk, |
state->performance_levels[i].sclk, |
&t_l, |
&t_h); |
else |
ret = r600_calculate_at( |
1000 * (i + 1), |
100 * R600_AH_DFLT, |
state->performance_levels[i + 1].sclk, |
state->performance_levels[i].sclk, |
&t_l, |
&t_h); |
if (ret) { |
t_h = (i + 1) * 1000 - 50 * R600_AH_DFLT; |
t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT; |
} |
a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK; |
a_t |= CG_R(t_l * pi->bsp / 20000); |
smc_state->levels[i].aT = cpu_to_be32(a_t); |
high_bsp = (i == state->performance_level_count - 2) ? |
pi->pbsp : pi->bsp; |
a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000); |
smc_state->levels[i + 1].aT = cpu_to_be32(a_t); |
} |
return 0; |
} |
static int ni_populate_power_containment_values(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
NISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
u32 prev_sclk; |
u32 max_sclk; |
u32 min_sclk; |
int i, ret; |
u32 tdp_limit; |
u32 near_tdp_limit; |
u32 power_boost_limit; |
u8 max_ps_percent; |
if (ni_pi->enable_power_containment == false) |
return 0; |
if (state->performance_level_count == 0) |
return -EINVAL; |
if (smc_state->levelCount != state->performance_level_count) |
return -EINVAL; |
ret = ni_calculate_adjusted_tdp_limits(rdev, |
false, /* ??? */ |
rdev->pm.dpm.tdp_adjustment, |
&tdp_limit, |
&near_tdp_limit); |
if (ret) |
return ret; |
power_boost_limit = ni_calculate_power_boost_limit(rdev, radeon_state, near_tdp_limit); |
ret = rv770_write_smc_sram_dword(rdev, |
pi->state_table_start + |
offsetof(NISLANDS_SMC_STATETABLE, dpm2Params) + |
offsetof(PP_NIslands_DPM2Parameters, PowerBoostLimit), |
ni_scale_power_for_smc(power_boost_limit, ni_get_smc_power_scaling_factor(rdev)), |
pi->sram_end); |
if (ret) |
power_boost_limit = 0; |
smc_state->levels[0].dpm2.MaxPS = 0; |
smc_state->levels[0].dpm2.NearTDPDec = 0; |
smc_state->levels[0].dpm2.AboveSafeInc = 0; |
smc_state->levels[0].dpm2.BelowSafeInc = 0; |
smc_state->levels[0].stateFlags |= power_boost_limit ? PPSMC_STATEFLAG_POWERBOOST : 0; |
for (i = 1; i < state->performance_level_count; i++) { |
prev_sclk = state->performance_levels[i-1].sclk; |
max_sclk = state->performance_levels[i].sclk; |
max_ps_percent = (i != (state->performance_level_count - 1)) ? |
NISLANDS_DPM2_MAXPS_PERCENT_M : NISLANDS_DPM2_MAXPS_PERCENT_H; |
if (max_sclk < prev_sclk) |
return -EINVAL; |
if ((max_ps_percent == 0) || (prev_sclk == max_sclk) || eg_pi->uvd_enabled) |
min_sclk = max_sclk; |
else if (1 == i) |
min_sclk = prev_sclk; |
else |
min_sclk = (prev_sclk * (u32)max_ps_percent) / 100; |
if (min_sclk < state->performance_levels[0].sclk) |
min_sclk = state->performance_levels[0].sclk; |
if (min_sclk == 0) |
return -EINVAL; |
smc_state->levels[i].dpm2.MaxPS = |
(u8)((NISLANDS_DPM2_MAX_PULSE_SKIP * (max_sclk - min_sclk)) / max_sclk); |
smc_state->levels[i].dpm2.NearTDPDec = NISLANDS_DPM2_NEAR_TDP_DEC; |
smc_state->levels[i].dpm2.AboveSafeInc = NISLANDS_DPM2_ABOVE_SAFE_INC; |
smc_state->levels[i].dpm2.BelowSafeInc = NISLANDS_DPM2_BELOW_SAFE_INC; |
smc_state->levels[i].stateFlags |= |
((i != (state->performance_level_count - 1)) && power_boost_limit) ? |
PPSMC_STATEFLAG_POWERBOOST : 0; |
} |
return 0; |
} |
static int ni_populate_sq_ramping_values(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
NISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
u32 sq_power_throttle; |
u32 sq_power_throttle2; |
bool enable_sq_ramping = ni_pi->enable_sq_ramping; |
int i; |
if (state->performance_level_count == 0) |
return -EINVAL; |
if (smc_state->levelCount != state->performance_level_count) |
return -EINVAL; |
if (rdev->pm.dpm.sq_ramping_threshold == 0) |
return -EINVAL; |
if (NISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT)) |
enable_sq_ramping = false; |
if (NISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT)) |
enable_sq_ramping = false; |
if (NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT)) |
enable_sq_ramping = false; |
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)) |
enable_sq_ramping = false; |
for (i = 0; i < state->performance_level_count; i++) { |
sq_power_throttle = 0; |
sq_power_throttle2 = 0; |
if ((state->performance_levels[i].sclk >= rdev->pm.dpm.sq_ramping_threshold) && |
enable_sq_ramping) { |
sq_power_throttle |= MAX_POWER(NISLANDS_DPM2_SQ_RAMP_MAX_POWER); |
sq_power_throttle |= MIN_POWER(NISLANDS_DPM2_SQ_RAMP_MIN_POWER); |
sq_power_throttle2 |= MAX_POWER_DELTA(NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA); |
sq_power_throttle2 |= STI_SIZE(NISLANDS_DPM2_SQ_RAMP_STI_SIZE); |
sq_power_throttle2 |= LTI_RATIO(NISLANDS_DPM2_SQ_RAMP_LTI_RATIO); |
} else { |
sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK; |
sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; |
} |
smc_state->levels[i].SQPowerThrottle = cpu_to_be32(sq_power_throttle); |
smc_state->levels[i].SQPowerThrottle_2 = cpu_to_be32(sq_power_throttle2); |
} |
return 0; |
} |
static int ni_enable_power_containment(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
bool enable) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
PPSMC_Result smc_result; |
int ret = 0; |
if (ni_pi->enable_power_containment) { |
if (enable) { |
if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) { |
smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingActive); |
if (smc_result != PPSMC_Result_OK) { |
ret = -EINVAL; |
ni_pi->pc_enabled = false; |
} else { |
ni_pi->pc_enabled = true; |
} |
} |
} else { |
smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingInactive); |
if (smc_result != PPSMC_Result_OK) |
ret = -EINVAL; |
ni_pi->pc_enabled = false; |
} |
} |
return ret; |
} |
static int ni_convert_power_state_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
NISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
int i, ret; |
u32 threshold = state->performance_levels[state->performance_level_count - 1].sclk * 100 / 100; |
if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC)) |
smc_state->flags |= PPSMC_SWSTATE_FLAG_DC; |
smc_state->levelCount = 0; |
if (state->performance_level_count > NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE) |
return -EINVAL; |
for (i = 0; i < state->performance_level_count; i++) { |
ret = ni_convert_power_level_to_smc(rdev, &state->performance_levels[i], |
&smc_state->levels[i]); |
smc_state->levels[i].arbRefreshState = |
(u8)(NISLANDS_DRIVER_STATE_ARB_INDEX + i); |
if (ret) |
return ret; |
if (ni_pi->enable_power_containment) |
smc_state->levels[i].displayWatermark = |
(state->performance_levels[i].sclk < threshold) ? |
PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH; |
else |
smc_state->levels[i].displayWatermark = (i < 2) ? |
PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH; |
if (eg_pi->dynamic_ac_timing) |
smc_state->levels[i].ACIndex = NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i; |
else |
smc_state->levels[i].ACIndex = 0; |
smc_state->levelCount++; |
} |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_watermark_threshold, |
cpu_to_be32(threshold / 512)); |
ni_populate_smc_sp(rdev, radeon_state, smc_state); |
ret = ni_populate_power_containment_values(rdev, radeon_state, smc_state); |
if (ret) |
ni_pi->enable_power_containment = false; |
ret = ni_populate_sq_ramping_values(rdev, radeon_state, smc_state); |
if (ret) |
ni_pi->enable_sq_ramping = false; |
return ni_populate_smc_t(rdev, radeon_state, smc_state); |
} |
static int ni_upload_sw_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u16 address = pi->state_table_start + |
offsetof(NISLANDS_SMC_STATETABLE, driverState); |
u16 state_size = sizeof(NISLANDS_SMC_SWSTATE) + |
((NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1) * sizeof(NISLANDS_SMC_HW_PERFORMANCE_LEVEL)); |
int ret; |
NISLANDS_SMC_SWSTATE *smc_state = kzalloc(state_size, GFP_KERNEL); |
if (smc_state == NULL) |
return -ENOMEM; |
ret = ni_convert_power_state_to_smc(rdev, radeon_new_state, smc_state); |
if (ret) |
goto done; |
ret = rv770_copy_bytes_to_smc(rdev, address, (u8 *)smc_state, state_size, pi->sram_end); |
done: |
kfree(smc_state); |
return ret; |
} |
static int ni_set_mc_special_registers(struct radeon_device *rdev, |
struct ni_mc_reg_table *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u8 i, j, k; |
u32 temp_reg; |
for (i = 0, j = table->last; i < table->last; i++) { |
switch (table->mc_reg_address[i].s1) { |
case MC_SEQ_MISC1 >> 2: |
if (j >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
temp_reg = RREG32(MC_PMG_CMD_EMRS); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
for (k = 0; k < table->num_entries; k++) |
table->mc_reg_table_entry[k].mc_data[j] = |
((temp_reg & 0xffff0000)) | |
((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16); |
j++; |
if (j >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
temp_reg = RREG32(MC_PMG_CMD_MRS); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
for(k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
(temp_reg & 0xffff0000) | |
(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); |
if (!pi->mem_gddr5) |
table->mc_reg_table_entry[k].mc_data[j] |= 0x100; |
} |
j++; |
if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
break; |
case MC_SEQ_RESERVE_M >> 2: |
temp_reg = RREG32(MC_PMG_CMD_MRS1); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
for (k = 0; k < table->num_entries; k++) |
table->mc_reg_table_entry[k].mc_data[j] = |
(temp_reg & 0xffff0000) | |
(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); |
j++; |
if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
break; |
default: |
break; |
} |
} |
table->last = j; |
return 0; |
} |
static bool ni_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg) |
{ |
bool result = true; |
switch (in_reg) { |
case MC_SEQ_RAS_TIMING >> 2: |
*out_reg = MC_SEQ_RAS_TIMING_LP >> 2; |
break; |
case MC_SEQ_CAS_TIMING >> 2: |
*out_reg = MC_SEQ_CAS_TIMING_LP >> 2; |
break; |
case MC_SEQ_MISC_TIMING >> 2: |
*out_reg = MC_SEQ_MISC_TIMING_LP >> 2; |
break; |
case MC_SEQ_MISC_TIMING2 >> 2: |
*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2; |
break; |
case MC_SEQ_RD_CTL_D0 >> 2: |
*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2; |
break; |
case MC_SEQ_RD_CTL_D1 >> 2: |
*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_D0 >> 2: |
*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_D1 >> 2: |
*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2; |
break; |
case MC_PMG_CMD_EMRS >> 2: |
*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
break; |
case MC_PMG_CMD_MRS >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
break; |
case MC_PMG_CMD_MRS1 >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
break; |
case MC_SEQ_PMG_TIMING >> 2: |
*out_reg = MC_SEQ_PMG_TIMING_LP >> 2; |
break; |
case MC_PMG_CMD_MRS2 >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2; |
break; |
default: |
result = false; |
break; |
} |
return result; |
} |
static void ni_set_valid_flag(struct ni_mc_reg_table *table) |
{ |
u8 i, j; |
for (i = 0; i < table->last; i++) { |
for (j = 1; j < table->num_entries; j++) { |
if (table->mc_reg_table_entry[j-1].mc_data[i] != table->mc_reg_table_entry[j].mc_data[i]) { |
table->valid_flag |= 1 << i; |
break; |
} |
} |
} |
} |
static void ni_set_s0_mc_reg_index(struct ni_mc_reg_table *table) |
{ |
u32 i; |
u16 address; |
for (i = 0; i < table->last; i++) |
table->mc_reg_address[i].s0 = |
ni_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ? |
address : table->mc_reg_address[i].s1; |
} |
static int ni_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table, |
struct ni_mc_reg_table *ni_table) |
{ |
u8 i, j; |
if (table->last > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
if (table->num_entries > MAX_AC_TIMING_ENTRIES) |
return -EINVAL; |
for (i = 0; i < table->last; i++) |
ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1; |
ni_table->last = table->last; |
for (i = 0; i < table->num_entries; i++) { |
ni_table->mc_reg_table_entry[i].mclk_max = |
table->mc_reg_table_entry[i].mclk_max; |
for (j = 0; j < table->last; j++) |
ni_table->mc_reg_table_entry[i].mc_data[j] = |
table->mc_reg_table_entry[i].mc_data[j]; |
} |
ni_table->num_entries = table->num_entries; |
return 0; |
} |
static int ni_initialize_mc_reg_table(struct radeon_device *rdev) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
int ret; |
struct atom_mc_reg_table *table; |
struct ni_mc_reg_table *ni_table = &ni_pi->mc_reg_table; |
u8 module_index = rv770_get_memory_module_index(rdev); |
table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL); |
if (!table) |
return -ENOMEM; |
WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING)); |
WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING)); |
WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING)); |
WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2)); |
WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS)); |
WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS)); |
WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1)); |
WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0)); |
WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1)); |
WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0)); |
WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1)); |
WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING)); |
WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2)); |
ret = radeon_atom_init_mc_reg_table(rdev, module_index, table); |
if (ret) |
goto init_mc_done; |
ret = ni_copy_vbios_mc_reg_table(table, ni_table); |
if (ret) |
goto init_mc_done; |
ni_set_s0_mc_reg_index(ni_table); |
ret = ni_set_mc_special_registers(rdev, ni_table); |
if (ret) |
goto init_mc_done; |
ni_set_valid_flag(ni_table); |
init_mc_done: |
kfree(table); |
return ret; |
} |
static void ni_populate_mc_reg_addresses(struct radeon_device *rdev, |
SMC_NIslands_MCRegisters *mc_reg_table) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 i, j; |
for (i = 0, j = 0; j < ni_pi->mc_reg_table.last; j++) { |
if (ni_pi->mc_reg_table.valid_flag & (1 << j)) { |
if (i >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE) |
break; |
mc_reg_table->address[i].s0 = |
cpu_to_be16(ni_pi->mc_reg_table.mc_reg_address[j].s0); |
mc_reg_table->address[i].s1 = |
cpu_to_be16(ni_pi->mc_reg_table.mc_reg_address[j].s1); |
i++; |
} |
} |
mc_reg_table->last = (u8)i; |
} |
static void ni_convert_mc_registers(struct ni_mc_reg_entry *entry, |
SMC_NIslands_MCRegisterSet *data, |
u32 num_entries, u32 valid_flag) |
{ |
u32 i, j; |
for (i = 0, j = 0; j < num_entries; j++) { |
if (valid_flag & (1 << j)) { |
data->value[i] = cpu_to_be32(entry->mc_data[j]); |
i++; |
} |
} |
} |
static void ni_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
SMC_NIslands_MCRegisterSet *mc_reg_table_data) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 i = 0; |
for (i = 0; i < ni_pi->mc_reg_table.num_entries; i++) { |
if (pl->mclk <= ni_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max) |
break; |
} |
if ((i == ni_pi->mc_reg_table.num_entries) && (i > 0)) |
--i; |
ni_convert_mc_registers(&ni_pi->mc_reg_table.mc_reg_table_entry[i], |
mc_reg_table_data, |
ni_pi->mc_reg_table.last, |
ni_pi->mc_reg_table.valid_flag); |
} |
static void ni_convert_mc_reg_table_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
SMC_NIslands_MCRegisters *mc_reg_table) |
{ |
struct ni_ps *state = ni_get_ps(radeon_state); |
int i; |
for (i = 0; i < state->performance_level_count; i++) { |
ni_convert_mc_reg_table_entry_to_smc(rdev, |
&state->performance_levels[i], |
&mc_reg_table->data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i]); |
} |
} |
static int ni_populate_mc_reg_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct ni_ps *boot_state = ni_get_ps(radeon_boot_state); |
SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table; |
memset(mc_reg_table, 0, sizeof(SMC_NIslands_MCRegisters)); |
rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_seq_index, 1); |
ni_populate_mc_reg_addresses(rdev, mc_reg_table); |
ni_convert_mc_reg_table_entry_to_smc(rdev, &boot_state->performance_levels[0], |
&mc_reg_table->data[0]); |
ni_convert_mc_registers(&ni_pi->mc_reg_table.mc_reg_table_entry[0], |
&mc_reg_table->data[1], |
ni_pi->mc_reg_table.last, |
ni_pi->mc_reg_table.valid_flag); |
ni_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, mc_reg_table); |
return rv770_copy_bytes_to_smc(rdev, eg_pi->mc_reg_table_start, |
(u8 *)mc_reg_table, |
sizeof(SMC_NIslands_MCRegisters), |
pi->sram_end); |
} |
static int ni_upload_mc_reg_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct ni_ps *ni_new_state = ni_get_ps(radeon_new_state); |
SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table; |
u16 address; |
memset(mc_reg_table, 0, sizeof(SMC_NIslands_MCRegisters)); |
ni_convert_mc_reg_table_to_smc(rdev, radeon_new_state, mc_reg_table); |
address = eg_pi->mc_reg_table_start + |
(u16)offsetof(SMC_NIslands_MCRegisters, data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT]); |
return rv770_copy_bytes_to_smc(rdev, address, |
(u8 *)&mc_reg_table->data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT], |
sizeof(SMC_NIslands_MCRegisterSet) * ni_new_state->performance_level_count, |
pi->sram_end); |
} |
static int ni_init_driver_calculated_leakage_table(struct radeon_device *rdev, |
PP_NIslands_CACTABLES *cac_tables) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 leakage = 0; |
unsigned int i, j, table_size; |
s32 t; |
u32 smc_leakage, max_leakage = 0; |
u32 scaling_factor; |
table_size = eg_pi->vddc_voltage_table.count; |
if (SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES < table_size) |
table_size = SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; |
scaling_factor = ni_get_smc_power_scaling_factor(rdev); |
for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++) { |
for (j = 0; j < table_size; j++) { |
t = (1000 * ((i + 1) * 8)); |
if (t < ni_pi->cac_data.leakage_minimum_temperature) |
t = ni_pi->cac_data.leakage_minimum_temperature; |
ni_calculate_leakage_for_v_and_t(rdev, |
&ni_pi->cac_data.leakage_coefficients, |
eg_pi->vddc_voltage_table.entries[j].value, |
t, |
ni_pi->cac_data.i_leakage, |
&leakage); |
smc_leakage = ni_scale_power_for_smc(leakage, scaling_factor) / 1000; |
if (smc_leakage > max_leakage) |
max_leakage = smc_leakage; |
cac_tables->cac_lkge_lut[i][j] = cpu_to_be32(smc_leakage); |
} |
} |
for (j = table_size; j < SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) { |
for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++) |
cac_tables->cac_lkge_lut[i][j] = cpu_to_be32(max_leakage); |
} |
return 0; |
} |
static int ni_init_simplified_leakage_table(struct radeon_device *rdev, |
PP_NIslands_CACTABLES *cac_tables) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_cac_leakage_table *leakage_table = |
&rdev->pm.dpm.dyn_state.cac_leakage_table; |
u32 i, j, table_size; |
u32 smc_leakage, max_leakage = 0; |
u32 scaling_factor; |
if (!leakage_table) |
return -EINVAL; |
table_size = leakage_table->count; |
if (eg_pi->vddc_voltage_table.count != table_size) |
table_size = (eg_pi->vddc_voltage_table.count < leakage_table->count) ? |
eg_pi->vddc_voltage_table.count : leakage_table->count; |
if (SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES < table_size) |
table_size = SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; |
if (table_size == 0) |
return -EINVAL; |
scaling_factor = ni_get_smc_power_scaling_factor(rdev); |
for (j = 0; j < table_size; j++) { |
smc_leakage = leakage_table->entries[j].leakage; |
if (smc_leakage > max_leakage) |
max_leakage = smc_leakage; |
for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++) |
cac_tables->cac_lkge_lut[i][j] = |
cpu_to_be32(ni_scale_power_for_smc(smc_leakage, scaling_factor)); |
} |
for (j = table_size; j < SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) { |
for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++) |
cac_tables->cac_lkge_lut[i][j] = |
cpu_to_be32(ni_scale_power_for_smc(max_leakage, scaling_factor)); |
} |
return 0; |
} |
static int ni_initialize_smc_cac_tables(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
PP_NIslands_CACTABLES *cac_tables = NULL; |
int i, ret; |
u32 reg; |
if (ni_pi->enable_cac == false) |
return 0; |
cac_tables = kzalloc(sizeof(PP_NIslands_CACTABLES), GFP_KERNEL); |
if (!cac_tables) |
return -ENOMEM; |
reg = RREG32(CG_CAC_CTRL) & ~(TID_CNT_MASK | TID_UNIT_MASK); |
reg |= (TID_CNT(ni_pi->cac_weights->tid_cnt) | |
TID_UNIT(ni_pi->cac_weights->tid_unit)); |
WREG32(CG_CAC_CTRL, reg); |
for (i = 0; i < NISLANDS_DCCAC_MAX_LEVELS; i++) |
ni_pi->dc_cac_table[i] = ni_pi->cac_weights->dc_cac[i]; |
for (i = 0; i < SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES; i++) |
cac_tables->cac_bif_lut[i] = ni_pi->cac_weights->pcie_cac[i]; |
ni_pi->cac_data.i_leakage = rdev->pm.dpm.cac_leakage; |
ni_pi->cac_data.pwr_const = 0; |
ni_pi->cac_data.dc_cac_value = ni_pi->dc_cac_table[NISLANDS_DCCAC_LEVEL_0]; |
ni_pi->cac_data.bif_cac_value = 0; |
ni_pi->cac_data.mc_wr_weight = ni_pi->cac_weights->mc_write_weight; |
ni_pi->cac_data.mc_rd_weight = ni_pi->cac_weights->mc_read_weight; |
ni_pi->cac_data.allow_ovrflw = 0; |
ni_pi->cac_data.l2num_win_tdp = ni_pi->lta_window_size; |
ni_pi->cac_data.num_win_tdp = 0; |
ni_pi->cac_data.lts_truncate_n = ni_pi->lts_truncate; |
if (ni_pi->driver_calculate_cac_leakage) |
ret = ni_init_driver_calculated_leakage_table(rdev, cac_tables); |
else |
ret = ni_init_simplified_leakage_table(rdev, cac_tables); |
if (ret) |
goto done_free; |
cac_tables->pwr_const = cpu_to_be32(ni_pi->cac_data.pwr_const); |
cac_tables->dc_cacValue = cpu_to_be32(ni_pi->cac_data.dc_cac_value); |
cac_tables->bif_cacValue = cpu_to_be32(ni_pi->cac_data.bif_cac_value); |
cac_tables->AllowOvrflw = ni_pi->cac_data.allow_ovrflw; |
cac_tables->MCWrWeight = ni_pi->cac_data.mc_wr_weight; |
cac_tables->MCRdWeight = ni_pi->cac_data.mc_rd_weight; |
cac_tables->numWin_TDP = ni_pi->cac_data.num_win_tdp; |
cac_tables->l2numWin_TDP = ni_pi->cac_data.l2num_win_tdp; |
cac_tables->lts_truncate_n = ni_pi->cac_data.lts_truncate_n; |
ret = rv770_copy_bytes_to_smc(rdev, ni_pi->cac_table_start, (u8 *)cac_tables, |
sizeof(PP_NIslands_CACTABLES), pi->sram_end); |
done_free: |
if (ret) { |
ni_pi->enable_cac = false; |
ni_pi->enable_power_containment = false; |
} |
kfree(cac_tables); |
return 0; |
} |
static int ni_initialize_hardware_cac_manager(struct radeon_device *rdev) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
u32 reg; |
if (!ni_pi->enable_cac || |
!ni_pi->cac_configuration_required) |
return 0; |
if (ni_pi->cac_weights == NULL) |
return -EINVAL; |
reg = RREG32_CG(CG_CAC_REGION_1_WEIGHT_0) & ~(WEIGHT_TCP_SIG0_MASK | |
WEIGHT_TCP_SIG1_MASK | |
WEIGHT_TA_SIG_MASK); |
reg |= (WEIGHT_TCP_SIG0(ni_pi->cac_weights->weight_tcp_sig0) | |
WEIGHT_TCP_SIG1(ni_pi->cac_weights->weight_tcp_sig1) | |
WEIGHT_TA_SIG(ni_pi->cac_weights->weight_ta_sig)); |
WREG32_CG(CG_CAC_REGION_1_WEIGHT_0, reg); |
reg = RREG32_CG(CG_CAC_REGION_1_WEIGHT_1) & ~(WEIGHT_TCC_EN0_MASK | |
WEIGHT_TCC_EN1_MASK | |
WEIGHT_TCC_EN2_MASK); |
reg |= (WEIGHT_TCC_EN0(ni_pi->cac_weights->weight_tcc_en0) | |
WEIGHT_TCC_EN1(ni_pi->cac_weights->weight_tcc_en1) | |
WEIGHT_TCC_EN2(ni_pi->cac_weights->weight_tcc_en2)); |
WREG32_CG(CG_CAC_REGION_1_WEIGHT_1, reg); |
reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_0) & ~(WEIGHT_CB_EN0_MASK | |
WEIGHT_CB_EN1_MASK | |
WEIGHT_CB_EN2_MASK | |
WEIGHT_CB_EN3_MASK); |
reg |= (WEIGHT_CB_EN0(ni_pi->cac_weights->weight_cb_en0) | |
WEIGHT_CB_EN1(ni_pi->cac_weights->weight_cb_en1) | |
WEIGHT_CB_EN2(ni_pi->cac_weights->weight_cb_en2) | |
WEIGHT_CB_EN3(ni_pi->cac_weights->weight_cb_en3)); |
WREG32_CG(CG_CAC_REGION_2_WEIGHT_0, reg); |
reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_1) & ~(WEIGHT_DB_SIG0_MASK | |
WEIGHT_DB_SIG1_MASK | |
WEIGHT_DB_SIG2_MASK | |
WEIGHT_DB_SIG3_MASK); |
reg |= (WEIGHT_DB_SIG0(ni_pi->cac_weights->weight_db_sig0) | |
WEIGHT_DB_SIG1(ni_pi->cac_weights->weight_db_sig1) | |
WEIGHT_DB_SIG2(ni_pi->cac_weights->weight_db_sig2) | |
WEIGHT_DB_SIG3(ni_pi->cac_weights->weight_db_sig3)); |
WREG32_CG(CG_CAC_REGION_2_WEIGHT_1, reg); |
reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_2) & ~(WEIGHT_SXM_SIG0_MASK | |
WEIGHT_SXM_SIG1_MASK | |
WEIGHT_SXM_SIG2_MASK | |
WEIGHT_SXS_SIG0_MASK | |
WEIGHT_SXS_SIG1_MASK); |
reg |= (WEIGHT_SXM_SIG0(ni_pi->cac_weights->weight_sxm_sig0) | |
WEIGHT_SXM_SIG1(ni_pi->cac_weights->weight_sxm_sig1) | |
WEIGHT_SXM_SIG2(ni_pi->cac_weights->weight_sxm_sig2) | |
WEIGHT_SXS_SIG0(ni_pi->cac_weights->weight_sxs_sig0) | |
WEIGHT_SXS_SIG1(ni_pi->cac_weights->weight_sxs_sig1)); |
WREG32_CG(CG_CAC_REGION_2_WEIGHT_2, reg); |
reg = RREG32_CG(CG_CAC_REGION_3_WEIGHT_0) & ~(WEIGHT_XBR_0_MASK | |
WEIGHT_XBR_1_MASK | |
WEIGHT_XBR_2_MASK | |
WEIGHT_SPI_SIG0_MASK); |
reg |= (WEIGHT_XBR_0(ni_pi->cac_weights->weight_xbr_0) | |
WEIGHT_XBR_1(ni_pi->cac_weights->weight_xbr_1) | |
WEIGHT_XBR_2(ni_pi->cac_weights->weight_xbr_2) | |
WEIGHT_SPI_SIG0(ni_pi->cac_weights->weight_spi_sig0)); |
WREG32_CG(CG_CAC_REGION_3_WEIGHT_0, reg); |
reg = RREG32_CG(CG_CAC_REGION_3_WEIGHT_1) & ~(WEIGHT_SPI_SIG1_MASK | |
WEIGHT_SPI_SIG2_MASK | |
WEIGHT_SPI_SIG3_MASK | |
WEIGHT_SPI_SIG4_MASK | |
WEIGHT_SPI_SIG5_MASK); |
reg |= (WEIGHT_SPI_SIG1(ni_pi->cac_weights->weight_spi_sig1) | |
WEIGHT_SPI_SIG2(ni_pi->cac_weights->weight_spi_sig2) | |
WEIGHT_SPI_SIG3(ni_pi->cac_weights->weight_spi_sig3) | |
WEIGHT_SPI_SIG4(ni_pi->cac_weights->weight_spi_sig4) | |
WEIGHT_SPI_SIG5(ni_pi->cac_weights->weight_spi_sig5)); |
WREG32_CG(CG_CAC_REGION_3_WEIGHT_1, reg); |
reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_0) & ~(WEIGHT_LDS_SIG0_MASK | |
WEIGHT_LDS_SIG1_MASK | |
WEIGHT_SC_MASK); |
reg |= (WEIGHT_LDS_SIG0(ni_pi->cac_weights->weight_lds_sig0) | |
WEIGHT_LDS_SIG1(ni_pi->cac_weights->weight_lds_sig1) | |
WEIGHT_SC(ni_pi->cac_weights->weight_sc)); |
WREG32_CG(CG_CAC_REGION_4_WEIGHT_0, reg); |
reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_1) & ~(WEIGHT_BIF_MASK | |
WEIGHT_CP_MASK | |
WEIGHT_PA_SIG0_MASK | |
WEIGHT_PA_SIG1_MASK | |
WEIGHT_VGT_SIG0_MASK); |
reg |= (WEIGHT_BIF(ni_pi->cac_weights->weight_bif) | |
WEIGHT_CP(ni_pi->cac_weights->weight_cp) | |
WEIGHT_PA_SIG0(ni_pi->cac_weights->weight_pa_sig0) | |
WEIGHT_PA_SIG1(ni_pi->cac_weights->weight_pa_sig1) | |
WEIGHT_VGT_SIG0(ni_pi->cac_weights->weight_vgt_sig0)); |
WREG32_CG(CG_CAC_REGION_4_WEIGHT_1, reg); |
reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_2) & ~(WEIGHT_VGT_SIG1_MASK | |
WEIGHT_VGT_SIG2_MASK | |
WEIGHT_DC_SIG0_MASK | |
WEIGHT_DC_SIG1_MASK | |
WEIGHT_DC_SIG2_MASK); |
reg |= (WEIGHT_VGT_SIG1(ni_pi->cac_weights->weight_vgt_sig1) | |
WEIGHT_VGT_SIG2(ni_pi->cac_weights->weight_vgt_sig2) | |
WEIGHT_DC_SIG0(ni_pi->cac_weights->weight_dc_sig0) | |
WEIGHT_DC_SIG1(ni_pi->cac_weights->weight_dc_sig1) | |
WEIGHT_DC_SIG2(ni_pi->cac_weights->weight_dc_sig2)); |
WREG32_CG(CG_CAC_REGION_4_WEIGHT_2, reg); |
reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_3) & ~(WEIGHT_DC_SIG3_MASK | |
WEIGHT_UVD_SIG0_MASK | |
WEIGHT_UVD_SIG1_MASK | |
WEIGHT_SPARE0_MASK | |
WEIGHT_SPARE1_MASK); |
reg |= (WEIGHT_DC_SIG3(ni_pi->cac_weights->weight_dc_sig3) | |
WEIGHT_UVD_SIG0(ni_pi->cac_weights->weight_uvd_sig0) | |
WEIGHT_UVD_SIG1(ni_pi->cac_weights->weight_uvd_sig1) | |
WEIGHT_SPARE0(ni_pi->cac_weights->weight_spare0) | |
WEIGHT_SPARE1(ni_pi->cac_weights->weight_spare1)); |
WREG32_CG(CG_CAC_REGION_4_WEIGHT_3, reg); |
reg = RREG32_CG(CG_CAC_REGION_5_WEIGHT_0) & ~(WEIGHT_SQ_VSP_MASK | |
WEIGHT_SQ_VSP0_MASK); |
reg |= (WEIGHT_SQ_VSP(ni_pi->cac_weights->weight_sq_vsp) | |
WEIGHT_SQ_VSP0(ni_pi->cac_weights->weight_sq_vsp0)); |
WREG32_CG(CG_CAC_REGION_5_WEIGHT_0, reg); |
reg = RREG32_CG(CG_CAC_REGION_5_WEIGHT_1) & ~(WEIGHT_SQ_GPR_MASK); |
reg |= WEIGHT_SQ_GPR(ni_pi->cac_weights->weight_sq_gpr); |
WREG32_CG(CG_CAC_REGION_5_WEIGHT_1, reg); |
reg = RREG32_CG(CG_CAC_REGION_4_OVERRIDE_4) & ~(OVR_MODE_SPARE_0_MASK | |
OVR_VAL_SPARE_0_MASK | |
OVR_MODE_SPARE_1_MASK | |
OVR_VAL_SPARE_1_MASK); |
reg |= (OVR_MODE_SPARE_0(ni_pi->cac_weights->ovr_mode_spare_0) | |
OVR_VAL_SPARE_0(ni_pi->cac_weights->ovr_val_spare_0) | |
OVR_MODE_SPARE_1(ni_pi->cac_weights->ovr_mode_spare_1) | |
OVR_VAL_SPARE_1(ni_pi->cac_weights->ovr_val_spare_1)); |
WREG32_CG(CG_CAC_REGION_4_OVERRIDE_4, reg); |
reg = RREG32(SQ_CAC_THRESHOLD) & ~(VSP_MASK | |
VSP0_MASK | |
GPR_MASK); |
reg |= (VSP(ni_pi->cac_weights->vsp) | |
VSP0(ni_pi->cac_weights->vsp0) | |
GPR(ni_pi->cac_weights->gpr)); |
WREG32(SQ_CAC_THRESHOLD, reg); |
reg = (MCDW_WR_ENABLE | |
MCDX_WR_ENABLE | |
MCDY_WR_ENABLE | |
MCDZ_WR_ENABLE | |
INDEX(0x09D4)); |
WREG32(MC_CG_CONFIG, reg); |
reg = (READ_WEIGHT(ni_pi->cac_weights->mc_read_weight) | |
WRITE_WEIGHT(ni_pi->cac_weights->mc_write_weight) | |
ALLOW_OVERFLOW); |
WREG32(MC_CG_DATAPORT, reg); |
return 0; |
} |
static int ni_enable_smc_cac(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
bool enable) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
int ret = 0; |
PPSMC_Result smc_result; |
if (ni_pi->enable_cac) { |
if (enable) { |
if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) { |
smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_CollectCAC_PowerCorreln); |
if (ni_pi->support_cac_long_term_average) { |
smc_result = rv770_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgEnable); |
if (PPSMC_Result_OK != smc_result) |
ni_pi->support_cac_long_term_average = false; |
} |
smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac); |
if (PPSMC_Result_OK != smc_result) |
ret = -EINVAL; |
ni_pi->cac_enabled = (PPSMC_Result_OK == smc_result) ? true : false; |
} |
} else if (ni_pi->cac_enabled) { |
smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac); |
ni_pi->cac_enabled = false; |
if (ni_pi->support_cac_long_term_average) { |
smc_result = rv770_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgDisable); |
if (PPSMC_Result_OK != smc_result) |
ni_pi->support_cac_long_term_average = false; |
} |
} |
} |
return ret; |
} |
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 ((perf_req == PCIE_PERF_REQ_PECI_GEN1) || |
(perf_req == PCIE_PERF_REQ_PECI_GEN2)) { |
if (eg_pi->pcie_performance_request_registered == false) |
radeon_acpi_pcie_notify_device_ready(rdev); |
eg_pi->pcie_performance_request_registered = true; |
return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise); |
} else if ((perf_req == PCIE_PERF_REQ_REMOVE_REGISTRY) && |
eg_pi->pcie_performance_request_registered) { |
eg_pi->pcie_performance_request_registered = false; |
return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise); |
} |
#endif |
return 0; |
} |
static int ni_advertise_gen2_capability(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) |
pi->pcie_gen2 = true; |
else |
pi->pcie_gen2 = false; |
if (!pi->pcie_gen2) |
ni_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, true); |
return 0; |
} |
static void ni_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp, bif; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) { |
if (enable) { |
if (!pi->boot_in_gen2) { |
bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK; |
bif |= CG_CLIENT_REQ(0xd); |
WREG32(CG_BIF_REQ_AND_RSP, bif); |
} |
tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); |
tmp |= LC_GEN2_EN_STRAP; |
tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
udelay(10); |
tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} else { |
if (!pi->boot_in_gen2) { |
bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK; |
bif |= CG_CLIENT_REQ(0xd); |
WREG32(CG_BIF_REQ_AND_RSP, bif); |
tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
tmp &= ~LC_GEN2_EN_STRAP; |
} |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
} |
} |
static void ni_enable_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
ni_enable_bif_dynamic_pcie_gen2(rdev, enable); |
if (enable) |
WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE); |
} |
void ni_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct ni_ps *new_state = ni_get_ps(new_ps); |
struct ni_ps *current_state = ni_get_ps(old_ps); |
if ((new_ps->vclk == old_ps->vclk) && |
(new_ps->dclk == old_ps->dclk)) |
return; |
if (new_state->performance_levels[new_state->performance_level_count - 1].sclk >= |
current_state->performance_levels[current_state->performance_level_count - 1].sclk) |
return; |
radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); |
} |
void ni_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct ni_ps *new_state = ni_get_ps(new_ps); |
struct ni_ps *current_state = ni_get_ps(old_ps); |
if ((new_ps->vclk == old_ps->vclk) && |
(new_ps->dclk == old_ps->dclk)) |
return; |
if (new_state->performance_levels[new_state->performance_level_count - 1].sclk < |
current_state->performance_levels[current_state->performance_level_count - 1].sclk) |
return; |
radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); |
} |
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); |
if (eg_pi->pcie_performance_request) |
ni_advertise_gen2_capability(rdev); |
rv770_get_pcie_gen2_status(rdev); |
rv770_enable_acpi_pm(rdev); |
} |
void ni_update_current_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct ni_ps *new_ps = ni_get_ps(rps); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
eg_pi->current_rps = *rps; |
ni_pi->current_ps = *new_ps; |
eg_pi->current_rps.ps_priv = &ni_pi->current_ps; |
} |
void ni_update_requested_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct ni_ps *new_ps = ni_get_ps(rps); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
eg_pi->requested_rps = *rps; |
ni_pi->requested_ps = *new_ps; |
eg_pi->requested_rps.ps_priv = &ni_pi->requested_ps; |
} |
int ni_dpm_enable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
int ret; |
if (pi->gfx_clock_gating) |
ni_cg_clockgating_default(rdev); |
if (btc_dpm_enabled(rdev)) |
return -EINVAL; |
if (pi->mg_clock_gating) |
ni_mg_clockgating_default(rdev); |
if (eg_pi->ls_clock_gating) |
ni_ls_clockgating_default(rdev); |
if (pi->voltage_control) { |
rv770_enable_voltage_control(rdev, true); |
ret = cypress_construct_voltage_tables(rdev); |
if (ret) { |
DRM_ERROR("cypress_construct_voltage_tables failed\n"); |
return ret; |
} |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = ni_initialize_mc_reg_table(rdev); |
if (ret) |
eg_pi->dynamic_ac_timing = false; |
} |
if (pi->dynamic_ss) |
cypress_enable_spread_spectrum(rdev, true); |
if (pi->thermal_protection) |
rv770_enable_thermal_protection(rdev, true); |
rv770_setup_bsp(rdev); |
rv770_program_git(rdev); |
rv770_program_tp(rdev); |
rv770_program_tpp(rdev); |
rv770_program_sstp(rdev); |
cypress_enable_display_gap(rdev); |
rv770_program_vc(rdev); |
if (pi->dynamic_pcie_gen2) |
ni_enable_dynamic_pcie_gen2(rdev, true); |
ret = rv770_upload_firmware(rdev); |
if (ret) { |
DRM_ERROR("rv770_upload_firmware failed\n"); |
return ret; |
} |
ret = ni_process_firmware_header(rdev); |
if (ret) { |
DRM_ERROR("ni_process_firmware_header failed\n"); |
return ret; |
} |
ret = ni_initial_switch_from_arb_f0_to_f1(rdev); |
if (ret) { |
DRM_ERROR("ni_initial_switch_from_arb_f0_to_f1 failed\n"); |
return ret; |
} |
ret = ni_init_smc_table(rdev); |
if (ret) { |
DRM_ERROR("ni_init_smc_table failed\n"); |
return ret; |
} |
ret = ni_init_smc_spll_table(rdev); |
if (ret) { |
DRM_ERROR("ni_init_smc_spll_table failed\n"); |
return ret; |
} |
ret = ni_init_arb_table_index(rdev); |
if (ret) { |
DRM_ERROR("ni_init_arb_table_index failed\n"); |
return ret; |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = ni_populate_mc_reg_table(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("ni_populate_mc_reg_table failed\n"); |
return ret; |
} |
} |
ret = ni_initialize_smc_cac_tables(rdev); |
if (ret) { |
DRM_ERROR("ni_initialize_smc_cac_tables failed\n"); |
return ret; |
} |
ret = ni_initialize_hardware_cac_manager(rdev); |
if (ret) { |
DRM_ERROR("ni_initialize_hardware_cac_manager failed\n"); |
return ret; |
} |
ret = ni_populate_smc_tdp_limits(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("ni_populate_smc_tdp_limits failed\n"); |
return ret; |
} |
ni_program_response_times(rdev); |
r7xx_start_smc(rdev); |
ret = cypress_notify_smc_display_change(rdev, false); |
if (ret) { |
DRM_ERROR("cypress_notify_smc_display_change failed\n"); |
return ret; |
} |
cypress_enable_sclk_control(rdev, true); |
if (eg_pi->memory_transition) |
cypress_enable_mclk_control(rdev, true); |
cypress_start_dpm(rdev); |
if (pi->gfx_clock_gating) |
ni_gfx_clockgating_enable(rdev, true); |
if (pi->mg_clock_gating) |
ni_mg_clockgating_enable(rdev, true); |
if (eg_pi->ls_clock_gating) |
ni_ls_clockgating_enable(rdev, true); |
rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); |
ni_update_current_ps(rdev, boot_ps); |
return 0; |
} |
void ni_dpm_disable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
if (!btc_dpm_enabled(rdev)) |
return; |
rv770_clear_vc(rdev); |
if (pi->thermal_protection) |
rv770_enable_thermal_protection(rdev, false); |
ni_enable_power_containment(rdev, boot_ps, false); |
ni_enable_smc_cac(rdev, boot_ps, false); |
cypress_enable_spread_spectrum(rdev, false); |
rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false); |
if (pi->dynamic_pcie_gen2) |
ni_enable_dynamic_pcie_gen2(rdev, false); |
if (rdev->irq.installed && |
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { |
rdev->irq.dpm_thermal = false; |
radeon_irq_set(rdev); |
} |
if (pi->gfx_clock_gating) |
ni_gfx_clockgating_enable(rdev, false); |
if (pi->mg_clock_gating) |
ni_mg_clockgating_enable(rdev, false); |
if (eg_pi->ls_clock_gating) |
ni_ls_clockgating_enable(rdev, false); |
ni_stop_dpm(rdev); |
btc_reset_to_default(rdev); |
ni_stop_smc(rdev); |
ni_force_switch_to_arb_f0(rdev); |
ni_update_current_ps(rdev, boot_ps); |
} |
static int ni_power_control_set_level(struct radeon_device *rdev) |
{ |
struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; |
int ret; |
ret = ni_restrict_performance_levels_before_switch(rdev); |
if (ret) |
return ret; |
ret = rv770_halt_smc(rdev); |
if (ret) |
return ret; |
ret = ni_populate_smc_tdp_limits(rdev, new_ps); |
if (ret) |
return ret; |
ret = rv770_resume_smc(rdev); |
if (ret) |
return ret; |
ret = rv770_set_sw_state(rdev); |
if (ret) |
return ret; |
return 0; |
} |
int ni_dpm_pre_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; |
struct radeon_ps *new_ps = &requested_ps; |
ni_update_requested_ps(rdev, new_ps); |
ni_apply_state_adjust_rules(rdev, &eg_pi->requested_rps); |
return 0; |
} |
int ni_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *new_ps = &eg_pi->requested_rps; |
struct radeon_ps *old_ps = &eg_pi->current_rps; |
int ret; |
ret = ni_restrict_performance_levels_before_switch(rdev); |
if (ret) { |
DRM_ERROR("ni_restrict_performance_levels_before_switch failed\n"); |
return ret; |
} |
ni_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
ret = ni_enable_power_containment(rdev, new_ps, false); |
if (ret) { |
DRM_ERROR("ni_enable_power_containment failed\n"); |
return ret; |
} |
ret = ni_enable_smc_cac(rdev, new_ps, false); |
if (ret) { |
DRM_ERROR("ni_enable_smc_cac failed\n"); |
return ret; |
} |
ret = rv770_halt_smc(rdev); |
if (ret) { |
DRM_ERROR("rv770_halt_smc failed\n"); |
return ret; |
} |
if (eg_pi->smu_uvd_hs) |
btc_notify_uvd_to_smc(rdev, new_ps); |
ret = ni_upload_sw_state(rdev, new_ps); |
if (ret) { |
DRM_ERROR("ni_upload_sw_state failed\n"); |
return ret; |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = ni_upload_mc_reg_table(rdev, new_ps); |
if (ret) { |
DRM_ERROR("ni_upload_mc_reg_table failed\n"); |
return ret; |
} |
} |
ret = ni_program_memory_timing_parameters(rdev, new_ps); |
if (ret) { |
DRM_ERROR("ni_program_memory_timing_parameters failed\n"); |
return ret; |
} |
ret = rv770_resume_smc(rdev); |
if (ret) { |
DRM_ERROR("rv770_resume_smc failed\n"); |
return ret; |
} |
ret = rv770_set_sw_state(rdev); |
if (ret) { |
DRM_ERROR("rv770_set_sw_state failed\n"); |
return ret; |
} |
ni_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
ret = ni_enable_smc_cac(rdev, new_ps, true); |
if (ret) { |
DRM_ERROR("ni_enable_smc_cac failed\n"); |
return ret; |
} |
ret = ni_enable_power_containment(rdev, new_ps, true); |
if (ret) { |
DRM_ERROR("ni_enable_power_containment failed\n"); |
return ret; |
} |
/* update tdp */ |
ret = ni_power_control_set_level(rdev); |
if (ret) { |
DRM_ERROR("ni_power_control_set_level failed\n"); |
return ret; |
} |
return 0; |
} |
void ni_dpm_post_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *new_ps = &eg_pi->requested_rps; |
ni_update_current_ps(rdev, new_ps); |
} |
void ni_dpm_reset_asic(struct radeon_device *rdev) |
{ |
ni_restrict_performance_levels_before_switch(rdev); |
rv770_set_boot_state(rdev); |
} |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void ni_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, |
u8 table_rev) |
{ |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { |
rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); |
rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); |
} else if (r600_is_uvd_state(rps->class, rps->class2)) { |
rps->vclk = RV770_DEFAULT_VCLK_FREQ; |
rps->dclk = RV770_DEFAULT_DCLK_FREQ; |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) |
rdev->pm.dpm.boot_ps = rps; |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void ni_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, int index, |
union pplib_clock_info *clock_info) |
{ |
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); |
struct rv7xx_pl *pl = &ps->performance_levels[index]; |
ps->performance_level_count = index + 1; |
pl->sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); |
pl->sclk |= clock_info->evergreen.ucEngineClockHigh << 16; |
pl->mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow); |
pl->mclk |= clock_info->evergreen.ucMemoryClockHigh << 16; |
pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC); |
pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI); |
pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags); |
/* patch up vddc if necessary */ |
if (pl->vddc == 0xff01) { |
if (pi->max_vddc) |
pl->vddc = pi->max_vddc; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { |
pi->acpi_vddc = pl->vddc; |
eg_pi->acpi_vddci = pl->vddci; |
if (ps->performance_levels[0].flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) |
pi->acpi_pcie_gen2 = true; |
else |
pi->acpi_pcie_gen2 = false; |
} |
if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) { |
eg_pi->ulv.supported = true; |
eg_pi->ulv.pl = pl; |
} |
if (pi->min_vddc_in_table > pl->vddc) |
pi->min_vddc_in_table = pl->vddc; |
if (pi->max_vddc_in_table < pl->vddc) |
pi->max_vddc_in_table = pl->vddc; |
/* patch up boot state */ |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
u16 vddc, vddci, mvdd; |
radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); |
pl->mclk = rdev->clock.default_mclk; |
pl->sclk = rdev->clock.default_sclk; |
pl->vddc = vddc; |
pl->vddci = 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; |
} |
} |
static int ni_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i, j; |
union pplib_clock_info *clock_info; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
struct ni_ps *ps; |
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.ps = kzalloc(sizeof(struct radeon_ps) * |
power_info->pplib.ucNumStates, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
for (i = 0; i < power_info->pplib.ucNumStates; i++) { |
power_state = (union pplib_power_state *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset) + |
i * power_info->pplib.ucStateEntrySize); |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + |
(power_state->v1.ucNonClockStateIndex * |
power_info->pplib.ucNonClockSize)); |
if (power_info->pplib.ucStateEntrySize - 1) { |
u8 *idx; |
ps = kzalloc(sizeof(struct ni_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
ni_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info, |
power_info->pplib.ucNonClockSize); |
idx = (u8 *)&power_state->v1.ucClockStateIndices[0]; |
for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { |
clock_info = (union pplib_clock_info *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + |
(idx[j] * power_info->pplib.ucClockInfoSize)); |
ni_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], j, |
clock_info); |
} |
} |
} |
rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates; |
return 0; |
} |
int ni_dpm_init(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi; |
struct evergreen_power_info *eg_pi; |
struct ni_power_info *ni_pi; |
struct atom_clock_dividers dividers; |
int ret; |
ni_pi = kzalloc(sizeof(struct ni_power_info), GFP_KERNEL); |
if (ni_pi == NULL) |
return -ENOMEM; |
rdev->pm.dpm.priv = ni_pi; |
eg_pi = &ni_pi->eg; |
pi = &eg_pi->rv7xx; |
rv770_get_max_vddc(rdev); |
eg_pi->ulv.supported = false; |
pi->acpi_vddc = 0; |
eg_pi->acpi_vddci = 0; |
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; |
ret = r600_parse_extended_power_table(rdev); |
if (ret) |
return ret; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = |
kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900; |
ni_patch_dependency_tables_based_on_leakage(rdev); |
if (rdev->pm.dpm.voltage_response_time == 0) |
rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; |
if (rdev->pm.dpm.backbias_response_time == 0) |
rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
0, false, ÷rs); |
if (ret) |
pi->ref_div = dividers.ref_div + 1; |
else |
pi->ref_div = R600_REFERENCEDIVIDER_DFLT; |
pi->rlp = RV770_RLP_DFLT; |
pi->rmp = RV770_RMP_DFLT; |
pi->lhp = RV770_LHP_DFLT; |
pi->lmp = RV770_LMP_DFLT; |
eg_pi->ats[0].rlp = RV770_RLP_DFLT; |
eg_pi->ats[0].rmp = RV770_RMP_DFLT; |
eg_pi->ats[0].lhp = RV770_LHP_DFLT; |
eg_pi->ats[0].lmp = RV770_LMP_DFLT; |
eg_pi->ats[1].rlp = BTC_RLP_UVD_DFLT; |
eg_pi->ats[1].rmp = BTC_RMP_UVD_DFLT; |
eg_pi->ats[1].lhp = BTC_LHP_UVD_DFLT; |
eg_pi->ats[1].lmp = BTC_LMP_UVD_DFLT; |
eg_pi->smu_uvd_hs = true; |
if (rdev->pdev->device == 0x6707) { |
pi->mclk_strobe_mode_threshold = 55000; |
pi->mclk_edc_enable_threshold = 55000; |
eg_pi->mclk_edc_wr_enable_threshold = 55000; |
} else { |
pi->mclk_strobe_mode_threshold = 40000; |
pi->mclk_edc_enable_threshold = 40000; |
eg_pi->mclk_edc_wr_enable_threshold = 40000; |
} |
ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold; |
pi->voltage_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0); |
pi->mvdd_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0); |
eg_pi->vddci_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0); |
rv770_get_engine_memory_ss(rdev); |
pi->asi = RV770_ASI_DFLT; |
pi->pasi = CYPRESS_HASI_DFLT; |
pi->vrc = CYPRESS_VRC_DFLT; |
pi->power_gating = false; |
pi->gfx_clock_gating = true; |
pi->mg_clock_gating = true; |
pi->mgcgtssm = true; |
eg_pi->ls_clock_gating = false; |
eg_pi->sclk_deep_sleep = false; |
pi->dynamic_pcie_gen2 = true; |
if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) |
pi->thermal_protection = true; |
else |
pi->thermal_protection = false; |
pi->display_gap = true; |
pi->dcodt = true; |
pi->ulps = true; |
eg_pi->dynamic_ac_timing = true; |
eg_pi->abm = true; |
eg_pi->mcls = true; |
eg_pi->light_sleep = true; |
eg_pi->memory_transition = true; |
#if defined(CONFIG_ACPI) |
eg_pi->pcie_performance_request = |
radeon_acpi_is_pcie_performance_request_supported(rdev); |
#else |
eg_pi->pcie_performance_request = false; |
#endif |
eg_pi->dll_default_on = false; |
eg_pi->sclk_deep_sleep = false; |
pi->mclk_stutter_mode_threshold = 0; |
pi->sram_end = SMC_RAM_END; |
rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 3; |
rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200; |
rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2 = 900; |
rdev->pm.dpm.dyn_state.valid_sclk_values.count = ARRAY_SIZE(btc_valid_sclk); |
rdev->pm.dpm.dyn_state.valid_sclk_values.values = btc_valid_sclk; |
rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0; |
rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL; |
rdev->pm.dpm.dyn_state.sclk_mclk_delta = 12500; |
ni_pi->cac_data.leakage_coefficients.at = 516; |
ni_pi->cac_data.leakage_coefficients.bt = 18; |
ni_pi->cac_data.leakage_coefficients.av = 51; |
ni_pi->cac_data.leakage_coefficients.bv = 2957; |
switch (rdev->pdev->device) { |
case 0x6700: |
case 0x6701: |
case 0x6702: |
case 0x6703: |
case 0x6718: |
ni_pi->cac_weights = &cac_weights_cayman_xt; |
break; |
case 0x6705: |
case 0x6719: |
case 0x671D: |
case 0x671C: |
default: |
ni_pi->cac_weights = &cac_weights_cayman_pro; |
break; |
case 0x6704: |
case 0x6706: |
case 0x6707: |
case 0x6708: |
case 0x6709: |
ni_pi->cac_weights = &cac_weights_cayman_le; |
break; |
} |
if (ni_pi->cac_weights->enable_power_containment_by_default) { |
ni_pi->enable_power_containment = true; |
ni_pi->enable_cac = true; |
ni_pi->enable_sq_ramping = true; |
} else { |
ni_pi->enable_power_containment = false; |
ni_pi->enable_cac = false; |
ni_pi->enable_sq_ramping = false; |
} |
ni_pi->driver_calculate_cac_leakage = false; |
ni_pi->cac_configuration_required = true; |
if (ni_pi->cac_configuration_required) { |
ni_pi->support_cac_long_term_average = true; |
ni_pi->lta_window_size = ni_pi->cac_weights->l2_lta_window_size; |
ni_pi->lts_truncate = ni_pi->cac_weights->lts_truncate; |
} else { |
ni_pi->support_cac_long_term_average = false; |
ni_pi->lta_window_size = 0; |
ni_pi->lts_truncate = 0; |
} |
ni_pi->use_power_boost_limit = true; |
/* make sure dc limits are valid */ |
if ((rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) || |
(rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0)) |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc = |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
return 0; |
} |
void ni_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries); |
r600_free_extended_power_table(rdev); |
} |
void ni_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct ni_ps *ps = ni_get_ps(rps); |
struct rv7xx_pl *pl; |
int i; |
r600_dpm_print_class_info(rps->class, rps->class2); |
r600_dpm_print_cap_info(rps->caps); |
printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
for (i = 0; i < ps->performance_level_count; i++) { |
pl = &ps->performance_levels[i]; |
if (rdev->family >= CHIP_TAHITI) |
printk("\t\tpower level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n", |
i, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1); |
else |
printk("\t\tpower level %d sclk: %u mclk: %u vddc: %u vddci: %u\n", |
i, pl->sclk, pl->mclk, pl->vddc, pl->vddci); |
} |
r600_dpm_print_ps_status(rdev, rps); |
} |
void ni_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 ni_ps *ps = ni_get_ps(rps); |
struct rv7xx_pl *pl; |
u32 current_index = |
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >> |
CURRENT_STATE_INDEX_SHIFT; |
if (current_index >= ps->performance_level_count) { |
seq_printf(m, "invalid dpm profile %d\n", current_index); |
} else { |
pl = &ps->performance_levels[current_index]; |
seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
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); |
} |
} |
u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_ps *requested_state = ni_get_ps(&eg_pi->requested_rps); |
if (low) |
return requested_state->performance_levels[0].sclk; |
else |
return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk; |
} |
u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_ps *requested_state = ni_get_ps(&eg_pi->requested_rps); |
if (low) |
return requested_state->performance_levels[0].mclk; |
else |
return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk; |
} |
/drivers/video/drm/radeon/ni_dpm.h |
---|
0,0 → 1,250 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __NI_DPM_H__ |
#define __NI_DPM_H__ |
#include "cypress_dpm.h" |
#include "btc_dpm.h" |
#include "nislands_smc.h" |
struct ni_clock_registers { |
u32 cg_spll_func_cntl; |
u32 cg_spll_func_cntl_2; |
u32 cg_spll_func_cntl_3; |
u32 cg_spll_func_cntl_4; |
u32 cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2; |
u32 mclk_pwrmgt_cntl; |
u32 dll_cntl; |
u32 mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2; |
u32 mpll_ss1; |
u32 mpll_ss2; |
}; |
struct ni_mc_reg_entry { |
u32 mclk_max; |
u32 mc_data[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE]; |
}; |
struct ni_mc_reg_table { |
u8 last; |
u8 num_entries; |
u16 valid_flag; |
struct ni_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES]; |
SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE]; |
}; |
#define NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT 2 |
enum ni_dc_cac_level |
{ |
NISLANDS_DCCAC_LEVEL_0 = 0, |
NISLANDS_DCCAC_LEVEL_1, |
NISLANDS_DCCAC_LEVEL_2, |
NISLANDS_DCCAC_LEVEL_3, |
NISLANDS_DCCAC_LEVEL_4, |
NISLANDS_DCCAC_LEVEL_5, |
NISLANDS_DCCAC_LEVEL_6, |
NISLANDS_DCCAC_LEVEL_7, |
NISLANDS_DCCAC_MAX_LEVELS |
}; |
struct ni_leakage_coeffients |
{ |
u32 at; |
u32 bt; |
u32 av; |
u32 bv; |
s32 t_slope; |
s32 t_intercept; |
u32 t_ref; |
}; |
struct ni_cac_data |
{ |
struct ni_leakage_coeffients leakage_coefficients; |
u32 i_leakage; |
s32 leakage_minimum_temperature; |
u32 pwr_const; |
u32 dc_cac_value; |
u32 bif_cac_value; |
u32 lkge_pwr; |
u8 mc_wr_weight; |
u8 mc_rd_weight; |
u8 allow_ovrflw; |
u8 num_win_tdp; |
u8 l2num_win_tdp; |
u8 lts_truncate_n; |
}; |
struct ni_cac_weights |
{ |
u32 weight_tcp_sig0; |
u32 weight_tcp_sig1; |
u32 weight_ta_sig; |
u32 weight_tcc_en0; |
u32 weight_tcc_en1; |
u32 weight_tcc_en2; |
u32 weight_cb_en0; |
u32 weight_cb_en1; |
u32 weight_cb_en2; |
u32 weight_cb_en3; |
u32 weight_db_sig0; |
u32 weight_db_sig1; |
u32 weight_db_sig2; |
u32 weight_db_sig3; |
u32 weight_sxm_sig0; |
u32 weight_sxm_sig1; |
u32 weight_sxm_sig2; |
u32 weight_sxs_sig0; |
u32 weight_sxs_sig1; |
u32 weight_xbr_0; |
u32 weight_xbr_1; |
u32 weight_xbr_2; |
u32 weight_spi_sig0; |
u32 weight_spi_sig1; |
u32 weight_spi_sig2; |
u32 weight_spi_sig3; |
u32 weight_spi_sig4; |
u32 weight_spi_sig5; |
u32 weight_lds_sig0; |
u32 weight_lds_sig1; |
u32 weight_sc; |
u32 weight_bif; |
u32 weight_cp; |
u32 weight_pa_sig0; |
u32 weight_pa_sig1; |
u32 weight_vgt_sig0; |
u32 weight_vgt_sig1; |
u32 weight_vgt_sig2; |
u32 weight_dc_sig0; |
u32 weight_dc_sig1; |
u32 weight_dc_sig2; |
u32 weight_dc_sig3; |
u32 weight_uvd_sig0; |
u32 weight_uvd_sig1; |
u32 weight_spare0; |
u32 weight_spare1; |
u32 weight_sq_vsp; |
u32 weight_sq_vsp0; |
u32 weight_sq_gpr; |
u32 ovr_mode_spare_0; |
u32 ovr_val_spare_0; |
u32 ovr_mode_spare_1; |
u32 ovr_val_spare_1; |
u32 vsp; |
u32 vsp0; |
u32 gpr; |
u8 mc_read_weight; |
u8 mc_write_weight; |
u32 tid_cnt; |
u32 tid_unit; |
u32 l2_lta_window_size; |
u32 lts_truncate; |
u32 dc_cac[NISLANDS_DCCAC_MAX_LEVELS]; |
u32 pcie_cac[SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES]; |
bool enable_power_containment_by_default; |
}; |
struct ni_ps { |
u16 performance_level_count; |
bool dc_compatible; |
struct rv7xx_pl performance_levels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE]; |
}; |
struct ni_power_info { |
/* must be first! */ |
struct evergreen_power_info eg; |
struct ni_clock_registers clock_registers; |
struct ni_mc_reg_table mc_reg_table; |
u32 mclk_rtt_mode_threshold; |
/* flags */ |
bool use_power_boost_limit; |
bool support_cac_long_term_average; |
bool cac_enabled; |
bool cac_configuration_required; |
bool driver_calculate_cac_leakage; |
bool pc_enabled; |
bool enable_power_containment; |
bool enable_cac; |
bool enable_sq_ramping; |
/* smc offsets */ |
u16 arb_table_start; |
u16 fan_table_start; |
u16 cac_table_start; |
u16 spll_table_start; |
/* CAC stuff */ |
struct ni_cac_data cac_data; |
u32 dc_cac_table[NISLANDS_DCCAC_MAX_LEVELS]; |
const struct ni_cac_weights *cac_weights; |
u8 lta_window_size; |
u8 lts_truncate; |
struct ni_ps current_ps; |
struct ni_ps requested_ps; |
/* scratch structs */ |
SMC_NIslands_MCRegisters smc_mc_reg_table; |
NISLANDS_SMC_STATETABLE smc_statetable; |
}; |
#define NISLANDS_INITIAL_STATE_ARB_INDEX 0 |
#define NISLANDS_ACPI_STATE_ARB_INDEX 1 |
#define NISLANDS_ULV_STATE_ARB_INDEX 2 |
#define NISLANDS_DRIVER_STATE_ARB_INDEX 3 |
#define NISLANDS_DPM2_MAX_PULSE_SKIP 256 |
#define NISLANDS_DPM2_NEAR_TDP_DEC 10 |
#define NISLANDS_DPM2_ABOVE_SAFE_INC 5 |
#define NISLANDS_DPM2_BELOW_SAFE_INC 20 |
#define NISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT 80 |
#define NISLANDS_DPM2_MAXPS_PERCENT_H 90 |
#define NISLANDS_DPM2_MAXPS_PERCENT_M 0 |
#define NISLANDS_DPM2_SQ_RAMP_MAX_POWER 0x3FFF |
#define NISLANDS_DPM2_SQ_RAMP_MIN_POWER 0x12 |
#define NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15 |
#define NISLANDS_DPM2_SQ_RAMP_STI_SIZE 0x1E |
#define NISLANDS_DPM2_SQ_RAMP_LTI_RATIO 0xF |
int ni_copy_and_switch_arb_sets(struct radeon_device *rdev, |
u32 arb_freq_src, u32 arb_freq_dest); |
void ni_update_current_ps(struct radeon_device *rdev, |
struct radeon_ps *rps); |
void ni_update_requested_ps(struct radeon_device *rdev, |
struct radeon_ps *rps); |
void ni_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps); |
void ni_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps); |
bool ni_dpm_vblank_too_short(struct radeon_device *rdev); |
#endif |
/drivers/video/drm/radeon/nid.h |
---|
128,11 → 128,28 |
#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 |
#define VM_INVALIDATE_REQUEST 0x1478 |
#define VM_INVALIDATE_RESPONSE 0x147c |
#define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC |
#define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC |
#define PROTECTIONS_MASK (0xf << 0) |
#define PROTECTIONS_SHIFT 0 |
/* bit 0: range |
* bit 2: pde0 |
* bit 3: valid |
* bit 4: read |
* bit 5: write |
*/ |
#define MEMORY_CLIENT_ID_MASK (0xff << 12) |
#define MEMORY_CLIENT_ID_SHIFT 12 |
#define MEMORY_CLIENT_RW_MASK (1 << 24) |
#define MEMORY_CLIENT_RW_SHIFT 24 |
#define FAULT_VMID_MASK (0x7 << 25) |
#define FAULT_VMID_SHIFT 25 |
#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR 0x1518 |
#define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR 0x151c |
#define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153C |
489,6 → 506,571 |
# define CACHE_FLUSH_AND_INV_EVENT_TS (0x14 << 0) |
# define CACHE_FLUSH_AND_INV_EVENT (0x16 << 0) |
/* TN SMU registers */ |
#define TN_CURRENT_GNB_TEMP 0x1F390 |
/* pm registers */ |
#define SMC_MSG 0x20c |
#define HOST_SMC_MSG(x) ((x) << 0) |
#define HOST_SMC_MSG_MASK (0xff << 0) |
#define HOST_SMC_MSG_SHIFT 0 |
#define HOST_SMC_RESP(x) ((x) << 8) |
#define HOST_SMC_RESP_MASK (0xff << 8) |
#define HOST_SMC_RESP_SHIFT 8 |
#define SMC_HOST_MSG(x) ((x) << 16) |
#define SMC_HOST_MSG_MASK (0xff << 16) |
#define SMC_HOST_MSG_SHIFT 16 |
#define SMC_HOST_RESP(x) ((x) << 24) |
#define SMC_HOST_RESP_MASK (0xff << 24) |
#define SMC_HOST_RESP_SHIFT 24 |
#define CG_SPLL_FUNC_CNTL 0x600 |
#define SPLL_RESET (1 << 0) |
#define SPLL_SLEEP (1 << 1) |
#define SPLL_BYPASS_EN (1 << 3) |
#define SPLL_REF_DIV(x) ((x) << 4) |
#define SPLL_REF_DIV_MASK (0x3f << 4) |
#define SPLL_PDIV_A(x) ((x) << 20) |
#define SPLL_PDIV_A_MASK (0x7f << 20) |
#define SPLL_PDIV_A_SHIFT 20 |
#define CG_SPLL_FUNC_CNTL_2 0x604 |
#define SCLK_MUX_SEL(x) ((x) << 0) |
#define SCLK_MUX_SEL_MASK (0x1ff << 0) |
#define CG_SPLL_FUNC_CNTL_3 0x608 |
#define SPLL_FB_DIV(x) ((x) << 0) |
#define SPLL_FB_DIV_MASK (0x3ffffff << 0) |
#define SPLL_FB_DIV_SHIFT 0 |
#define SPLL_DITHEN (1 << 28) |
#define MPLL_CNTL_MODE 0x61c |
# define SS_SSEN (1 << 24) |
# define SS_DSMODE_EN (1 << 25) |
#define MPLL_AD_FUNC_CNTL 0x624 |
#define CLKF(x) ((x) << 0) |
#define CLKF_MASK (0x7f << 0) |
#define CLKR(x) ((x) << 7) |
#define CLKR_MASK (0x1f << 7) |
#define CLKFRAC(x) ((x) << 12) |
#define CLKFRAC_MASK (0x1f << 12) |
#define YCLK_POST_DIV(x) ((x) << 17) |
#define YCLK_POST_DIV_MASK (3 << 17) |
#define IBIAS(x) ((x) << 20) |
#define IBIAS_MASK (0x3ff << 20) |
#define RESET (1 << 30) |
#define PDNB (1 << 31) |
#define MPLL_AD_FUNC_CNTL_2 0x628 |
#define BYPASS (1 << 19) |
#define BIAS_GEN_PDNB (1 << 24) |
#define RESET_EN (1 << 25) |
#define VCO_MODE (1 << 29) |
#define MPLL_DQ_FUNC_CNTL 0x62c |
#define MPLL_DQ_FUNC_CNTL_2 0x630 |
#define GENERAL_PWRMGT 0x63c |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define THERMAL_PROTECTION_DIS (1 << 2) |
# define THERMAL_PROTECTION_TYPE (1 << 3) |
# define ENABLE_GEN2PCIE (1 << 4) |
# define ENABLE_GEN2XSP (1 << 5) |
# define SW_SMIO_INDEX(x) ((x) << 6) |
# define SW_SMIO_INDEX_MASK (3 << 6) |
# define SW_SMIO_INDEX_SHIFT 6 |
# define LOW_VOLT_D2_ACPI (1 << 8) |
# define LOW_VOLT_D3_ACPI (1 << 9) |
# define VOLT_PWRMGT_EN (1 << 10) |
# define BACKBIAS_PAD_EN (1 << 18) |
# define BACKBIAS_VALUE (1 << 19) |
# define DYN_SPREAD_SPECTRUM_EN (1 << 23) |
# define AC_DC_SW (1 << 24) |
#define SCLK_PWRMGT_CNTL 0x644 |
# define SCLK_PWRMGT_OFF (1 << 0) |
# define SCLK_LOW_D1 (1 << 1) |
# define FIR_RESET (1 << 4) |
# define FIR_FORCE_TREND_SEL (1 << 5) |
# define FIR_TREND_MODE (1 << 6) |
# define DYN_GFX_CLK_OFF_EN (1 << 7) |
# define GFX_CLK_FORCE_ON (1 << 8) |
# define GFX_CLK_REQUEST_OFF (1 << 9) |
# define GFX_CLK_FORCE_OFF (1 << 10) |
# define GFX_CLK_OFF_ACPI_D1 (1 << 11) |
# define GFX_CLK_OFF_ACPI_D2 (1 << 12) |
# define GFX_CLK_OFF_ACPI_D3 (1 << 13) |
# define DYN_LIGHT_SLEEP_EN (1 << 14) |
#define MCLK_PWRMGT_CNTL 0x648 |
# define DLL_SPEED(x) ((x) << 0) |
# define DLL_SPEED_MASK (0x1f << 0) |
# define MPLL_PWRMGT_OFF (1 << 5) |
# define DLL_READY (1 << 6) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCKA0_PDNB (1 << 8) |
# define MRDCKA1_PDNB (1 << 9) |
# define MRDCKB0_PDNB (1 << 10) |
# define MRDCKB1_PDNB (1 << 11) |
# define MRDCKC0_PDNB (1 << 12) |
# define MRDCKC1_PDNB (1 << 13) |
# define MRDCKD0_PDNB (1 << 14) |
# define MRDCKD1_PDNB (1 << 15) |
# define MRDCKA0_RESET (1 << 16) |
# define MRDCKA1_RESET (1 << 17) |
# define MRDCKB0_RESET (1 << 18) |
# define MRDCKB1_RESET (1 << 19) |
# define MRDCKC0_RESET (1 << 20) |
# define MRDCKC1_RESET (1 << 21) |
# define MRDCKD0_RESET (1 << 22) |
# define MRDCKD1_RESET (1 << 23) |
# define DLL_READY_READ (1 << 24) |
# define USE_DISPLAY_GAP (1 << 25) |
# define USE_DISPLAY_URGENT_NORMAL (1 << 26) |
# define MPLL_TURNOFF_D2 (1 << 28) |
#define DLL_CNTL 0x64c |
# define MRDCKA0_BYPASS (1 << 24) |
# define MRDCKA1_BYPASS (1 << 25) |
# define MRDCKB0_BYPASS (1 << 26) |
# define MRDCKB1_BYPASS (1 << 27) |
# define MRDCKC0_BYPASS (1 << 28) |
# define MRDCKC1_BYPASS (1 << 29) |
# define MRDCKD0_BYPASS (1 << 30) |
# define MRDCKD1_BYPASS (1 << 31) |
#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c |
# define CURRENT_STATE_INDEX_MASK (0xf << 4) |
# define CURRENT_STATE_INDEX_SHIFT 4 |
#define CG_AT 0x6d4 |
# define CG_R(x) ((x) << 0) |
# define CG_R_MASK (0xffff << 0) |
# define CG_L(x) ((x) << 16) |
# define CG_L_MASK (0xffff << 16) |
#define CG_BIF_REQ_AND_RSP 0x7f4 |
#define CG_CLIENT_REQ(x) ((x) << 0) |
#define CG_CLIENT_REQ_MASK (0xff << 0) |
#define CG_CLIENT_REQ_SHIFT 0 |
#define CG_CLIENT_RESP(x) ((x) << 8) |
#define CG_CLIENT_RESP_MASK (0xff << 8) |
#define CG_CLIENT_RESP_SHIFT 8 |
#define CLIENT_CG_REQ(x) ((x) << 16) |
#define CLIENT_CG_REQ_MASK (0xff << 16) |
#define CLIENT_CG_REQ_SHIFT 16 |
#define CLIENT_CG_RESP(x) ((x) << 24) |
#define CLIENT_CG_RESP_MASK (0xff << 24) |
#define CLIENT_CG_RESP_SHIFT 24 |
#define CG_SPLL_SPREAD_SPECTRUM 0x790 |
#define SSEN (1 << 0) |
#define CLK_S(x) ((x) << 4) |
#define CLK_S_MASK (0xfff << 4) |
#define CLK_S_SHIFT 4 |
#define CG_SPLL_SPREAD_SPECTRUM_2 0x794 |
#define CLK_V(x) ((x) << 0) |
#define CLK_V_MASK (0x3ffffff << 0) |
#define CLK_V_SHIFT 0 |
#define SMC_SCRATCH0 0x81c |
#define CG_SPLL_FUNC_CNTL_4 0x850 |
#define MPLL_SS1 0x85c |
#define CLKV(x) ((x) << 0) |
#define CLKV_MASK (0x3ffffff << 0) |
#define MPLL_SS2 0x860 |
#define CLKS(x) ((x) << 0) |
#define CLKS_MASK (0xfff << 0) |
#define CG_CAC_CTRL 0x88c |
#define TID_CNT(x) ((x) << 0) |
#define TID_CNT_MASK (0x3fff << 0) |
#define TID_UNIT(x) ((x) << 14) |
#define TID_UNIT_MASK (0xf << 14) |
#define CG_IND_ADDR 0x8f8 |
#define CG_IND_DATA 0x8fc |
/* CGIND regs */ |
#define CG_CGTT_LOCAL_0 0x00 |
#define CG_CGTT_LOCAL_1 0x01 |
#define MC_CG_CONFIG 0x25bc |
#define MCDW_WR_ENABLE (1 << 0) |
#define MCDX_WR_ENABLE (1 << 1) |
#define MCDY_WR_ENABLE (1 << 2) |
#define MCDZ_WR_ENABLE (1 << 3) |
#define MC_RD_ENABLE(x) ((x) << 4) |
#define MC_RD_ENABLE_MASK (3 << 4) |
#define INDEX(x) ((x) << 6) |
#define INDEX_MASK (0xfff << 6) |
#define INDEX_SHIFT 6 |
#define MC_ARB_CAC_CNTL 0x2750 |
#define ENABLE (1 << 0) |
#define READ_WEIGHT(x) ((x) << 1) |
#define READ_WEIGHT_MASK (0x3f << 1) |
#define READ_WEIGHT_SHIFT 1 |
#define WRITE_WEIGHT(x) ((x) << 7) |
#define WRITE_WEIGHT_MASK (0x3f << 7) |
#define WRITE_WEIGHT_SHIFT 7 |
#define ALLOW_OVERFLOW (1 << 13) |
#define MC_ARB_DRAM_TIMING 0x2774 |
#define MC_ARB_DRAM_TIMING2 0x2778 |
#define MC_ARB_RFSH_RATE 0x27b0 |
#define POWERMODE0(x) ((x) << 0) |
#define POWERMODE0_MASK (0xff << 0) |
#define POWERMODE0_SHIFT 0 |
#define POWERMODE1(x) ((x) << 8) |
#define POWERMODE1_MASK (0xff << 8) |
#define POWERMODE1_SHIFT 8 |
#define POWERMODE2(x) ((x) << 16) |
#define POWERMODE2_MASK (0xff << 16) |
#define POWERMODE2_SHIFT 16 |
#define POWERMODE3(x) ((x) << 24) |
#define POWERMODE3_MASK (0xff << 24) |
#define POWERMODE3_SHIFT 24 |
#define MC_ARB_CG 0x27e8 |
#define CG_ARB_REQ(x) ((x) << 0) |
#define CG_ARB_REQ_MASK (0xff << 0) |
#define CG_ARB_REQ_SHIFT 0 |
#define CG_ARB_RESP(x) ((x) << 8) |
#define CG_ARB_RESP_MASK (0xff << 8) |
#define CG_ARB_RESP_SHIFT 8 |
#define ARB_CG_REQ(x) ((x) << 16) |
#define ARB_CG_REQ_MASK (0xff << 16) |
#define ARB_CG_REQ_SHIFT 16 |
#define ARB_CG_RESP(x) ((x) << 24) |
#define ARB_CG_RESP_MASK (0xff << 24) |
#define ARB_CG_RESP_SHIFT 24 |
#define MC_ARB_DRAM_TIMING_1 0x27f0 |
#define MC_ARB_DRAM_TIMING_2 0x27f4 |
#define MC_ARB_DRAM_TIMING_3 0x27f8 |
#define MC_ARB_DRAM_TIMING2_1 0x27fc |
#define MC_ARB_DRAM_TIMING2_2 0x2800 |
#define MC_ARB_DRAM_TIMING2_3 0x2804 |
#define MC_ARB_BURST_TIME 0x2808 |
#define STATE0(x) ((x) << 0) |
#define STATE0_MASK (0x1f << 0) |
#define STATE0_SHIFT 0 |
#define STATE1(x) ((x) << 5) |
#define STATE1_MASK (0x1f << 5) |
#define STATE1_SHIFT 5 |
#define STATE2(x) ((x) << 10) |
#define STATE2_MASK (0x1f << 10) |
#define STATE2_SHIFT 10 |
#define STATE3(x) ((x) << 15) |
#define STATE3_MASK (0x1f << 15) |
#define STATE3_SHIFT 15 |
#define MC_CG_DATAPORT 0x2884 |
#define MC_SEQ_RAS_TIMING 0x28a0 |
#define MC_SEQ_CAS_TIMING 0x28a4 |
#define MC_SEQ_MISC_TIMING 0x28a8 |
#define MC_SEQ_MISC_TIMING2 0x28ac |
#define MC_SEQ_PMG_TIMING 0x28b0 |
#define MC_SEQ_RD_CTL_D0 0x28b4 |
#define MC_SEQ_RD_CTL_D1 0x28b8 |
#define MC_SEQ_WR_CTL_D0 0x28bc |
#define MC_SEQ_WR_CTL_D1 0x28c0 |
#define MC_SEQ_MISC0 0x2a00 |
#define MC_SEQ_MISC0_GDDR5_SHIFT 28 |
#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000 |
#define MC_SEQ_MISC0_GDDR5_VALUE 5 |
#define MC_SEQ_MISC1 0x2a04 |
#define MC_SEQ_RESERVE_M 0x2a08 |
#define MC_PMG_CMD_EMRS 0x2a0c |
#define MC_SEQ_MISC3 0x2a2c |
#define MC_SEQ_MISC5 0x2a54 |
#define MC_SEQ_MISC6 0x2a58 |
#define MC_SEQ_MISC7 0x2a64 |
#define MC_SEQ_RAS_TIMING_LP 0x2a6c |
#define MC_SEQ_CAS_TIMING_LP 0x2a70 |
#define MC_SEQ_MISC_TIMING_LP 0x2a74 |
#define MC_SEQ_MISC_TIMING2_LP 0x2a78 |
#define MC_SEQ_WR_CTL_D0_LP 0x2a7c |
#define MC_SEQ_WR_CTL_D1_LP 0x2a80 |
#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84 |
#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88 |
#define MC_PMG_CMD_MRS 0x2aac |
#define MC_SEQ_RD_CTL_D0_LP 0x2b1c |
#define MC_SEQ_RD_CTL_D1_LP 0x2b20 |
#define MC_PMG_CMD_MRS1 0x2b44 |
#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48 |
#define MC_SEQ_PMG_TIMING_LP 0x2b4c |
#define MC_PMG_CMD_MRS2 0x2b5c |
#define MC_SEQ_PMG_CMD_MRS2_LP 0x2b60 |
#define LB_SYNC_RESET_SEL 0x6b28 |
#define LB_SYNC_RESET_SEL_MASK (3 << 0) |
#define LB_SYNC_RESET_SEL_SHIFT 0 |
#define DC_STUTTER_CNTL 0x6b30 |
#define DC_STUTTER_ENABLE_A (1 << 0) |
#define DC_STUTTER_ENABLE_B (1 << 1) |
#define SQ_CAC_THRESHOLD 0x8e4c |
#define VSP(x) ((x) << 0) |
#define VSP_MASK (0xff << 0) |
#define VSP_SHIFT 0 |
#define VSP0(x) ((x) << 8) |
#define VSP0_MASK (0xff << 8) |
#define VSP0_SHIFT 8 |
#define GPR(x) ((x) << 16) |
#define GPR_MASK (0xff << 16) |
#define GPR_SHIFT 16 |
#define SQ_POWER_THROTTLE 0x8e58 |
#define MIN_POWER(x) ((x) << 0) |
#define MIN_POWER_MASK (0x3fff << 0) |
#define MIN_POWER_SHIFT 0 |
#define MAX_POWER(x) ((x) << 16) |
#define MAX_POWER_MASK (0x3fff << 16) |
#define MAX_POWER_SHIFT 0 |
#define SQ_POWER_THROTTLE2 0x8e5c |
#define MAX_POWER_DELTA(x) ((x) << 0) |
#define MAX_POWER_DELTA_MASK (0x3fff << 0) |
#define MAX_POWER_DELTA_SHIFT 0 |
#define STI_SIZE(x) ((x) << 16) |
#define STI_SIZE_MASK (0x3ff << 16) |
#define STI_SIZE_SHIFT 16 |
#define LTI_RATIO(x) ((x) << 27) |
#define LTI_RATIO_MASK (0xf << 27) |
#define LTI_RATIO_SHIFT 27 |
/* CG indirect registers */ |
#define CG_CAC_REGION_1_WEIGHT_0 0x83 |
#define WEIGHT_TCP_SIG0(x) ((x) << 0) |
#define WEIGHT_TCP_SIG0_MASK (0x3f << 0) |
#define WEIGHT_TCP_SIG0_SHIFT 0 |
#define WEIGHT_TCP_SIG1(x) ((x) << 6) |
#define WEIGHT_TCP_SIG1_MASK (0x3f << 6) |
#define WEIGHT_TCP_SIG1_SHIFT 6 |
#define WEIGHT_TA_SIG(x) ((x) << 12) |
#define WEIGHT_TA_SIG_MASK (0x3f << 12) |
#define WEIGHT_TA_SIG_SHIFT 12 |
#define CG_CAC_REGION_1_WEIGHT_1 0x84 |
#define WEIGHT_TCC_EN0(x) ((x) << 0) |
#define WEIGHT_TCC_EN0_MASK (0x3f << 0) |
#define WEIGHT_TCC_EN0_SHIFT 0 |
#define WEIGHT_TCC_EN1(x) ((x) << 6) |
#define WEIGHT_TCC_EN1_MASK (0x3f << 6) |
#define WEIGHT_TCC_EN1_SHIFT 6 |
#define WEIGHT_TCC_EN2(x) ((x) << 12) |
#define WEIGHT_TCC_EN2_MASK (0x3f << 12) |
#define WEIGHT_TCC_EN2_SHIFT 12 |
#define WEIGHT_TCC_EN3(x) ((x) << 18) |
#define WEIGHT_TCC_EN3_MASK (0x3f << 18) |
#define WEIGHT_TCC_EN3_SHIFT 18 |
#define CG_CAC_REGION_2_WEIGHT_0 0x85 |
#define WEIGHT_CB_EN0(x) ((x) << 0) |
#define WEIGHT_CB_EN0_MASK (0x3f << 0) |
#define WEIGHT_CB_EN0_SHIFT 0 |
#define WEIGHT_CB_EN1(x) ((x) << 6) |
#define WEIGHT_CB_EN1_MASK (0x3f << 6) |
#define WEIGHT_CB_EN1_SHIFT 6 |
#define WEIGHT_CB_EN2(x) ((x) << 12) |
#define WEIGHT_CB_EN2_MASK (0x3f << 12) |
#define WEIGHT_CB_EN2_SHIFT 12 |
#define WEIGHT_CB_EN3(x) ((x) << 18) |
#define WEIGHT_CB_EN3_MASK (0x3f << 18) |
#define WEIGHT_CB_EN3_SHIFT 18 |
#define CG_CAC_REGION_2_WEIGHT_1 0x86 |
#define WEIGHT_DB_SIG0(x) ((x) << 0) |
#define WEIGHT_DB_SIG0_MASK (0x3f << 0) |
#define WEIGHT_DB_SIG0_SHIFT 0 |
#define WEIGHT_DB_SIG1(x) ((x) << 6) |
#define WEIGHT_DB_SIG1_MASK (0x3f << 6) |
#define WEIGHT_DB_SIG1_SHIFT 6 |
#define WEIGHT_DB_SIG2(x) ((x) << 12) |
#define WEIGHT_DB_SIG2_MASK (0x3f << 12) |
#define WEIGHT_DB_SIG2_SHIFT 12 |
#define WEIGHT_DB_SIG3(x) ((x) << 18) |
#define WEIGHT_DB_SIG3_MASK (0x3f << 18) |
#define WEIGHT_DB_SIG3_SHIFT 18 |
#define CG_CAC_REGION_2_WEIGHT_2 0x87 |
#define WEIGHT_SXM_SIG0(x) ((x) << 0) |
#define WEIGHT_SXM_SIG0_MASK (0x3f << 0) |
#define WEIGHT_SXM_SIG0_SHIFT 0 |
#define WEIGHT_SXM_SIG1(x) ((x) << 6) |
#define WEIGHT_SXM_SIG1_MASK (0x3f << 6) |
#define WEIGHT_SXM_SIG1_SHIFT 6 |
#define WEIGHT_SXM_SIG2(x) ((x) << 12) |
#define WEIGHT_SXM_SIG2_MASK (0x3f << 12) |
#define WEIGHT_SXM_SIG2_SHIFT 12 |
#define WEIGHT_SXS_SIG0(x) ((x) << 18) |
#define WEIGHT_SXS_SIG0_MASK (0x3f << 18) |
#define WEIGHT_SXS_SIG0_SHIFT 18 |
#define WEIGHT_SXS_SIG1(x) ((x) << 24) |
#define WEIGHT_SXS_SIG1_MASK (0x3f << 24) |
#define WEIGHT_SXS_SIG1_SHIFT 24 |
#define CG_CAC_REGION_3_WEIGHT_0 0x88 |
#define WEIGHT_XBR_0(x) ((x) << 0) |
#define WEIGHT_XBR_0_MASK (0x3f << 0) |
#define WEIGHT_XBR_0_SHIFT 0 |
#define WEIGHT_XBR_1(x) ((x) << 6) |
#define WEIGHT_XBR_1_MASK (0x3f << 6) |
#define WEIGHT_XBR_1_SHIFT 6 |
#define WEIGHT_XBR_2(x) ((x) << 12) |
#define WEIGHT_XBR_2_MASK (0x3f << 12) |
#define WEIGHT_XBR_2_SHIFT 12 |
#define WEIGHT_SPI_SIG0(x) ((x) << 18) |
#define WEIGHT_SPI_SIG0_MASK (0x3f << 18) |
#define WEIGHT_SPI_SIG0_SHIFT 18 |
#define CG_CAC_REGION_3_WEIGHT_1 0x89 |
#define WEIGHT_SPI_SIG1(x) ((x) << 0) |
#define WEIGHT_SPI_SIG1_MASK (0x3f << 0) |
#define WEIGHT_SPI_SIG1_SHIFT 0 |
#define WEIGHT_SPI_SIG2(x) ((x) << 6) |
#define WEIGHT_SPI_SIG2_MASK (0x3f << 6) |
#define WEIGHT_SPI_SIG2_SHIFT 6 |
#define WEIGHT_SPI_SIG3(x) ((x) << 12) |
#define WEIGHT_SPI_SIG3_MASK (0x3f << 12) |
#define WEIGHT_SPI_SIG3_SHIFT 12 |
#define WEIGHT_SPI_SIG4(x) ((x) << 18) |
#define WEIGHT_SPI_SIG4_MASK (0x3f << 18) |
#define WEIGHT_SPI_SIG4_SHIFT 18 |
#define WEIGHT_SPI_SIG5(x) ((x) << 24) |
#define WEIGHT_SPI_SIG5_MASK (0x3f << 24) |
#define WEIGHT_SPI_SIG5_SHIFT 24 |
#define CG_CAC_REGION_4_WEIGHT_0 0x8a |
#define WEIGHT_LDS_SIG0(x) ((x) << 0) |
#define WEIGHT_LDS_SIG0_MASK (0x3f << 0) |
#define WEIGHT_LDS_SIG0_SHIFT 0 |
#define WEIGHT_LDS_SIG1(x) ((x) << 6) |
#define WEIGHT_LDS_SIG1_MASK (0x3f << 6) |
#define WEIGHT_LDS_SIG1_SHIFT 6 |
#define WEIGHT_SC(x) ((x) << 24) |
#define WEIGHT_SC_MASK (0x3f << 24) |
#define WEIGHT_SC_SHIFT 24 |
#define CG_CAC_REGION_4_WEIGHT_1 0x8b |
#define WEIGHT_BIF(x) ((x) << 0) |
#define WEIGHT_BIF_MASK (0x3f << 0) |
#define WEIGHT_BIF_SHIFT 0 |
#define WEIGHT_CP(x) ((x) << 6) |
#define WEIGHT_CP_MASK (0x3f << 6) |
#define WEIGHT_CP_SHIFT 6 |
#define WEIGHT_PA_SIG0(x) ((x) << 12) |
#define WEIGHT_PA_SIG0_MASK (0x3f << 12) |
#define WEIGHT_PA_SIG0_SHIFT 12 |
#define WEIGHT_PA_SIG1(x) ((x) << 18) |
#define WEIGHT_PA_SIG1_MASK (0x3f << 18) |
#define WEIGHT_PA_SIG1_SHIFT 18 |
#define WEIGHT_VGT_SIG0(x) ((x) << 24) |
#define WEIGHT_VGT_SIG0_MASK (0x3f << 24) |
#define WEIGHT_VGT_SIG0_SHIFT 24 |
#define CG_CAC_REGION_4_WEIGHT_2 0x8c |
#define WEIGHT_VGT_SIG1(x) ((x) << 0) |
#define WEIGHT_VGT_SIG1_MASK (0x3f << 0) |
#define WEIGHT_VGT_SIG1_SHIFT 0 |
#define WEIGHT_VGT_SIG2(x) ((x) << 6) |
#define WEIGHT_VGT_SIG2_MASK (0x3f << 6) |
#define WEIGHT_VGT_SIG2_SHIFT 6 |
#define WEIGHT_DC_SIG0(x) ((x) << 12) |
#define WEIGHT_DC_SIG0_MASK (0x3f << 12) |
#define WEIGHT_DC_SIG0_SHIFT 12 |
#define WEIGHT_DC_SIG1(x) ((x) << 18) |
#define WEIGHT_DC_SIG1_MASK (0x3f << 18) |
#define WEIGHT_DC_SIG1_SHIFT 18 |
#define WEIGHT_DC_SIG2(x) ((x) << 24) |
#define WEIGHT_DC_SIG2_MASK (0x3f << 24) |
#define WEIGHT_DC_SIG2_SHIFT 24 |
#define CG_CAC_REGION_4_WEIGHT_3 0x8d |
#define WEIGHT_DC_SIG3(x) ((x) << 0) |
#define WEIGHT_DC_SIG3_MASK (0x3f << 0) |
#define WEIGHT_DC_SIG3_SHIFT 0 |
#define WEIGHT_UVD_SIG0(x) ((x) << 6) |
#define WEIGHT_UVD_SIG0_MASK (0x3f << 6) |
#define WEIGHT_UVD_SIG0_SHIFT 6 |
#define WEIGHT_UVD_SIG1(x) ((x) << 12) |
#define WEIGHT_UVD_SIG1_MASK (0x3f << 12) |
#define WEIGHT_UVD_SIG1_SHIFT 12 |
#define WEIGHT_SPARE0(x) ((x) << 18) |
#define WEIGHT_SPARE0_MASK (0x3f << 18) |
#define WEIGHT_SPARE0_SHIFT 18 |
#define WEIGHT_SPARE1(x) ((x) << 24) |
#define WEIGHT_SPARE1_MASK (0x3f << 24) |
#define WEIGHT_SPARE1_SHIFT 24 |
#define CG_CAC_REGION_5_WEIGHT_0 0x8e |
#define WEIGHT_SQ_VSP(x) ((x) << 0) |
#define WEIGHT_SQ_VSP_MASK (0x3fff << 0) |
#define WEIGHT_SQ_VSP_SHIFT 0 |
#define WEIGHT_SQ_VSP0(x) ((x) << 14) |
#define WEIGHT_SQ_VSP0_MASK (0x3fff << 14) |
#define WEIGHT_SQ_VSP0_SHIFT 14 |
#define CG_CAC_REGION_4_OVERRIDE_4 0xab |
#define OVR_MODE_SPARE_0(x) ((x) << 16) |
#define OVR_MODE_SPARE_0_MASK (0x1 << 16) |
#define OVR_MODE_SPARE_0_SHIFT 16 |
#define OVR_VAL_SPARE_0(x) ((x) << 17) |
#define OVR_VAL_SPARE_0_MASK (0x1 << 17) |
#define OVR_VAL_SPARE_0_SHIFT 17 |
#define OVR_MODE_SPARE_1(x) ((x) << 18) |
#define OVR_MODE_SPARE_1_MASK (0x3f << 18) |
#define OVR_MODE_SPARE_1_SHIFT 18 |
#define OVR_VAL_SPARE_1(x) ((x) << 19) |
#define OVR_VAL_SPARE_1_MASK (0x3f << 19) |
#define OVR_VAL_SPARE_1_SHIFT 19 |
#define CG_CAC_REGION_5_WEIGHT_1 0xb7 |
#define WEIGHT_SQ_GPR(x) ((x) << 0) |
#define WEIGHT_SQ_GPR_MASK (0x3fff << 0) |
#define WEIGHT_SQ_GPR_SHIFT 0 |
#define WEIGHT_SQ_LDS(x) ((x) << 14) |
#define WEIGHT_SQ_LDS_MASK (0x3fff << 14) |
#define WEIGHT_SQ_LDS_SHIFT 14 |
/* PCIE link stuff */ |
#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */ |
#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ |
# define LC_LINK_WIDTH_SHIFT 0 |
# define LC_LINK_WIDTH_MASK 0x7 |
# define LC_LINK_WIDTH_X0 0 |
# define LC_LINK_WIDTH_X1 1 |
# define LC_LINK_WIDTH_X2 2 |
# define LC_LINK_WIDTH_X4 3 |
# define LC_LINK_WIDTH_X8 4 |
# define LC_LINK_WIDTH_X16 6 |
# define LC_LINK_WIDTH_RD_SHIFT 4 |
# define LC_LINK_WIDTH_RD_MASK 0x70 |
# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) |
# define LC_RECONFIG_NOW (1 << 8) |
# define LC_RENEGOTIATION_SUPPORT (1 << 9) |
# define LC_RENEGOTIATE_EN (1 << 10) |
# define LC_SHORT_RECONFIG_EN (1 << 11) |
# define LC_UPCONFIGURE_SUPPORT (1 << 12) |
# define LC_UPCONFIGURE_DIS (1 << 13) |
#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ |
# define LC_GEN2_EN_STRAP (1 << 0) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) |
# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5) |
# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 |
# define LC_CURRENT_DATA_RATE (1 << 11) |
# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12 |
# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) |
# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) |
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) |
# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) |
#define MM_CFGREGS_CNTL 0x544c |
# define MM_WR_TO_CFG_EN (1 << 3) |
#define LINK_CNTL2 0x88 /* F0 */ |
# define TARGET_LINK_SPEED_MASK (0xf << 0) |
# define SELECTABLE_DEEMPHASIS (1 << 6) |
/* |
* UVD |
*/ |
573,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 |
/drivers/video/drm/radeon/nislands_smc.h |
---|
0,0 → 1,329 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __NISLANDS_SMC_H__ |
#define __NISLANDS_SMC_H__ |
#pragma pack(push, 1) |
#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16 |
struct PP_NIslands_Dpm2PerfLevel |
{ |
uint8_t MaxPS; |
uint8_t TgtAct; |
uint8_t MaxPS_StepInc; |
uint8_t MaxPS_StepDec; |
uint8_t PSST; |
uint8_t NearTDPDec; |
uint8_t AboveSafeInc; |
uint8_t BelowSafeInc; |
uint8_t PSDeltaLimit; |
uint8_t PSDeltaWin; |
uint8_t Reserved[6]; |
}; |
typedef struct PP_NIslands_Dpm2PerfLevel PP_NIslands_Dpm2PerfLevel; |
struct PP_NIslands_DPM2Parameters |
{ |
uint32_t TDPLimit; |
uint32_t NearTDPLimit; |
uint32_t SafePowerLimit; |
uint32_t PowerBoostLimit; |
}; |
typedef struct PP_NIslands_DPM2Parameters PP_NIslands_DPM2Parameters; |
struct NISLANDS_SMC_SCLK_VALUE |
{ |
uint32_t vCG_SPLL_FUNC_CNTL; |
uint32_t vCG_SPLL_FUNC_CNTL_2; |
uint32_t vCG_SPLL_FUNC_CNTL_3; |
uint32_t vCG_SPLL_FUNC_CNTL_4; |
uint32_t vCG_SPLL_SPREAD_SPECTRUM; |
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2; |
uint32_t sclk_value; |
}; |
typedef struct NISLANDS_SMC_SCLK_VALUE NISLANDS_SMC_SCLK_VALUE; |
struct NISLANDS_SMC_MCLK_VALUE |
{ |
uint32_t vMPLL_FUNC_CNTL; |
uint32_t vMPLL_FUNC_CNTL_1; |
uint32_t vMPLL_FUNC_CNTL_2; |
uint32_t vMPLL_AD_FUNC_CNTL; |
uint32_t vMPLL_AD_FUNC_CNTL_2; |
uint32_t vMPLL_DQ_FUNC_CNTL; |
uint32_t vMPLL_DQ_FUNC_CNTL_2; |
uint32_t vMCLK_PWRMGT_CNTL; |
uint32_t vDLL_CNTL; |
uint32_t vMPLL_SS; |
uint32_t vMPLL_SS2; |
uint32_t mclk_value; |
}; |
typedef struct NISLANDS_SMC_MCLK_VALUE NISLANDS_SMC_MCLK_VALUE; |
struct NISLANDS_SMC_VOLTAGE_VALUE |
{ |
uint16_t value; |
uint8_t index; |
uint8_t padding; |
}; |
typedef struct NISLANDS_SMC_VOLTAGE_VALUE NISLANDS_SMC_VOLTAGE_VALUE; |
struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL |
{ |
uint8_t arbValue; |
uint8_t ACIndex; |
uint8_t displayWatermark; |
uint8_t gen2PCIE; |
uint8_t reserved1; |
uint8_t reserved2; |
uint8_t strobeMode; |
uint8_t mcFlags; |
uint32_t aT; |
uint32_t bSP; |
NISLANDS_SMC_SCLK_VALUE sclk; |
NISLANDS_SMC_MCLK_VALUE mclk; |
NISLANDS_SMC_VOLTAGE_VALUE vddc; |
NISLANDS_SMC_VOLTAGE_VALUE mvdd; |
NISLANDS_SMC_VOLTAGE_VALUE vddci; |
NISLANDS_SMC_VOLTAGE_VALUE std_vddc; |
uint32_t powergate_en; |
uint8_t hUp; |
uint8_t hDown; |
uint8_t stateFlags; |
uint8_t arbRefreshState; |
uint32_t SQPowerThrottle; |
uint32_t SQPowerThrottle_2; |
uint32_t reserved[2]; |
PP_NIslands_Dpm2PerfLevel dpm2; |
}; |
#define NISLANDS_SMC_STROBE_RATIO 0x0F |
#define NISLANDS_SMC_STROBE_ENABLE 0x10 |
#define NISLANDS_SMC_MC_EDC_RD_FLAG 0x01 |
#define NISLANDS_SMC_MC_EDC_WR_FLAG 0x02 |
#define NISLANDS_SMC_MC_RTT_ENABLE 0x04 |
#define NISLANDS_SMC_MC_STUTTER_EN 0x08 |
typedef struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL NISLANDS_SMC_HW_PERFORMANCE_LEVEL; |
struct NISLANDS_SMC_SWSTATE |
{ |
uint8_t flags; |
uint8_t levelCount; |
uint8_t padding2; |
uint8_t padding3; |
NISLANDS_SMC_HW_PERFORMANCE_LEVEL levels[1]; |
}; |
typedef struct NISLANDS_SMC_SWSTATE NISLANDS_SMC_SWSTATE; |
#define NISLANDS_SMC_VOLTAGEMASK_VDDC 0 |
#define NISLANDS_SMC_VOLTAGEMASK_MVDD 1 |
#define NISLANDS_SMC_VOLTAGEMASK_VDDCI 2 |
#define NISLANDS_SMC_VOLTAGEMASK_MAX 4 |
struct NISLANDS_SMC_VOLTAGEMASKTABLE |
{ |
uint8_t highMask[NISLANDS_SMC_VOLTAGEMASK_MAX]; |
uint32_t lowMask[NISLANDS_SMC_VOLTAGEMASK_MAX]; |
}; |
typedef struct NISLANDS_SMC_VOLTAGEMASKTABLE NISLANDS_SMC_VOLTAGEMASKTABLE; |
#define NISLANDS_MAX_NO_VREG_STEPS 32 |
struct NISLANDS_SMC_STATETABLE |
{ |
uint8_t thermalProtectType; |
uint8_t systemFlags; |
uint8_t maxVDDCIndexInPPTable; |
uint8_t extraFlags; |
uint8_t highSMIO[NISLANDS_MAX_NO_VREG_STEPS]; |
uint32_t lowSMIO[NISLANDS_MAX_NO_VREG_STEPS]; |
NISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable; |
PP_NIslands_DPM2Parameters dpm2Params; |
NISLANDS_SMC_SWSTATE initialState; |
NISLANDS_SMC_SWSTATE ACPIState; |
NISLANDS_SMC_SWSTATE ULVState; |
NISLANDS_SMC_SWSTATE driverState; |
NISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1]; |
}; |
typedef struct NISLANDS_SMC_STATETABLE NISLANDS_SMC_STATETABLE; |
#define NI_SMC_SOFT_REGISTERS_START 0x108 |
#define NI_SMC_SOFT_REGISTER_mclk_chg_timeout 0x0 |
#define NI_SMC_SOFT_REGISTER_delay_bbias 0xC |
#define NI_SMC_SOFT_REGISTER_delay_vreg 0x10 |
#define NI_SMC_SOFT_REGISTER_delay_acpi 0x2C |
#define NI_SMC_SOFT_REGISTER_seq_index 0x64 |
#define NI_SMC_SOFT_REGISTER_mvdd_chg_time 0x68 |
#define NI_SMC_SOFT_REGISTER_mclk_switch_lim 0x78 |
#define NI_SMC_SOFT_REGISTER_watermark_threshold 0x80 |
#define NI_SMC_SOFT_REGISTER_mc_block_delay 0x84 |
#define NI_SMC_SOFT_REGISTER_uvd_enabled 0x98 |
#define SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES 16 |
#define SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16 |
#define SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16 |
#define SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES 4 |
struct SMC_NISLANDS_MC_TPP_CAC_TABLE |
{ |
uint32_t tpp[SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES]; |
uint32_t cacValue[SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES]; |
}; |
typedef struct SMC_NISLANDS_MC_TPP_CAC_TABLE SMC_NISLANDS_MC_TPP_CAC_TABLE; |
struct PP_NIslands_CACTABLES |
{ |
uint32_t cac_bif_lut[SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES]; |
uint32_t cac_lkge_lut[SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES][SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES]; |
uint32_t pwr_const; |
uint32_t dc_cacValue; |
uint32_t bif_cacValue; |
uint32_t lkge_pwr; |
uint8_t cac_width; |
uint8_t window_size_p2; |
uint8_t num_drop_lsb; |
uint8_t padding_0; |
uint32_t last_power; |
uint8_t AllowOvrflw; |
uint8_t MCWrWeight; |
uint8_t MCRdWeight; |
uint8_t padding_1[9]; |
uint8_t enableWinAvg; |
uint8_t numWin_TDP; |
uint8_t l2numWin_TDP; |
uint8_t WinIndex; |
uint32_t dynPwr_TDP[4]; |
uint32_t lkgePwr_TDP[4]; |
uint32_t power_TDP[4]; |
uint32_t avg_dynPwr_TDP; |
uint32_t avg_lkgePwr_TDP; |
uint32_t avg_power_TDP; |
uint32_t lts_power_TDP; |
uint8_t lts_truncate_n; |
uint8_t padding_2[7]; |
}; |
typedef struct PP_NIslands_CACTABLES PP_NIslands_CACTABLES; |
#define SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE 32 |
#define SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20 |
struct SMC_NIslands_MCRegisterAddress |
{ |
uint16_t s0; |
uint16_t s1; |
}; |
typedef struct SMC_NIslands_MCRegisterAddress SMC_NIslands_MCRegisterAddress; |
struct SMC_NIslands_MCRegisterSet |
{ |
uint32_t value[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE]; |
}; |
typedef struct SMC_NIslands_MCRegisterSet SMC_NIslands_MCRegisterSet; |
struct SMC_NIslands_MCRegisters |
{ |
uint8_t last; |
uint8_t reserved[3]; |
SMC_NIslands_MCRegisterAddress address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE]; |
SMC_NIslands_MCRegisterSet data[SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT]; |
}; |
typedef struct SMC_NIslands_MCRegisters SMC_NIslands_MCRegisters; |
struct SMC_NIslands_MCArbDramTimingRegisterSet |
{ |
uint32_t mc_arb_dram_timing; |
uint32_t mc_arb_dram_timing2; |
uint8_t mc_arb_rfsh_rate; |
uint8_t padding[3]; |
}; |
typedef struct SMC_NIslands_MCArbDramTimingRegisterSet SMC_NIslands_MCArbDramTimingRegisterSet; |
struct SMC_NIslands_MCArbDramTimingRegisters |
{ |
uint8_t arb_current; |
uint8_t reserved[3]; |
SMC_NIslands_MCArbDramTimingRegisterSet data[20]; |
}; |
typedef struct SMC_NIslands_MCArbDramTimingRegisters SMC_NIslands_MCArbDramTimingRegisters; |
struct SMC_NISLANDS_SPLL_DIV_TABLE |
{ |
uint32_t freq[256]; |
uint32_t ss[256]; |
}; |
#define SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK 0x01ffffff |
#define SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT 0 |
#define SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK 0xfe000000 |
#define SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT 25 |
#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK 0x000fffff |
#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT 0 |
#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK 0xfff00000 |
#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT 20 |
typedef struct SMC_NISLANDS_SPLL_DIV_TABLE SMC_NISLANDS_SPLL_DIV_TABLE; |
#define NISLANDS_SMC_FIRMWARE_HEADER_LOCATION 0x100 |
#define NISLANDS_SMC_FIRMWARE_HEADER_version 0x0 |
#define NISLANDS_SMC_FIRMWARE_HEADER_flags 0x4 |
#define NISLANDS_SMC_FIRMWARE_HEADER_softRegisters 0x8 |
#define NISLANDS_SMC_FIRMWARE_HEADER_stateTable 0xC |
#define NISLANDS_SMC_FIRMWARE_HEADER_fanTable 0x10 |
#define NISLANDS_SMC_FIRMWARE_HEADER_cacTable 0x14 |
#define NISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20 |
#define NISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable 0x2C |
#define NISLANDS_SMC_FIRMWARE_HEADER_spllTable 0x30 |
#pragma pack(pop) |
#endif |
/drivers/video/drm/radeon/pci.c |
---|
8,6 → 8,12 |
#include <pci.h> |
#include <syscall.h> |
static inline __attribute__((const)) |
bool is_power_of_2(unsigned long n) |
{ |
return (n != 0 && ((n & (n - 1)) == 0)); |
} |
extern int pci_scan_filter(u32_t id, u32_t busnr, u32_t devfn); |
static LIST_HEAD(devices); |
1051,3 → 1057,52 |
} |
EXPORT_SYMBOL(pcie_capability_write_dword); |
int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, |
u16 clear, u16 set) |
{ |
int ret; |
u16 val; |
ret = pcie_capability_read_word(dev, pos, &val); |
if (!ret) { |
val &= ~clear; |
val |= set; |
ret = pcie_capability_write_word(dev, pos, val); |
} |
return ret; |
} |
int pcie_get_readrq(struct pci_dev *dev) |
{ |
u16 ctl; |
pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl); |
return 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12); |
} |
EXPORT_SYMBOL(pcie_get_readrq); |
/** |
* pcie_set_readrq - set PCI Express maximum memory read request |
* @dev: PCI device to query |
* @rq: maximum memory read count in bytes |
* valid values are 128, 256, 512, 1024, 2048, 4096 |
* |
* If possible sets maximum memory read request in bytes |
*/ |
int pcie_set_readrq(struct pci_dev *dev, int rq) |
{ |
u16 v; |
if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) |
return -EINVAL; |
v = (ffs(rq) - 8) << 12; |
return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, |
PCI_EXP_DEVCTL_READRQ, v); |
} |
/drivers/video/drm/radeon/ppsmc.h |
---|
0,0 → 1,175 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef PP_SMC_H |
#define PP_SMC_H |
#pragma pack(push, 1) |
#define PPSMC_SWSTATE_FLAG_DC 0x01 |
#define PPSMC_SWSTATE_FLAG_UVD 0x02 |
#define PPSMC_SWSTATE_FLAG_VCE 0x04 |
#define PPSMC_SWSTATE_FLAG_PCIE_X1 0x08 |
#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00 |
#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01 |
#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff |
#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01 |
#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02 |
#define PPSMC_SYSTEMFLAG_GDDR5 0x04 |
#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08 |
#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10 |
#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20 |
#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_PROG_GPIO 0x40 |
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07 |
#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08 |
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00 |
#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01 |
#define PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH 0x02 |
#define PPSMC_DISPLAY_WATERMARK_LOW 0 |
#define PPSMC_DISPLAY_WATERMARK_HIGH 1 |
#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01 |
#define PPSMC_STATEFLAG_POWERBOOST 0x02 |
#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20 |
#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40 |
#define PPSMC_Result_OK ((uint8_t)0x01) |
#define PPSMC_Result_Failed ((uint8_t)0xFF) |
typedef uint8_t PPSMC_Result; |
#define PPSMC_MSG_Halt ((uint8_t)0x10) |
#define PPSMC_MSG_Resume ((uint8_t)0x11) |
#define PPSMC_MSG_ZeroLevelsDisabled ((uint8_t)0x13) |
#define PPSMC_MSG_OneLevelsDisabled ((uint8_t)0x14) |
#define PPSMC_MSG_TwoLevelsDisabled ((uint8_t)0x15) |
#define PPSMC_MSG_EnableThermalInterrupt ((uint8_t)0x16) |
#define PPSMC_MSG_RunningOnAC ((uint8_t)0x17) |
#define PPSMC_MSG_SwitchToSwState ((uint8_t)0x20) |
#define PPSMC_MSG_SwitchToInitialState ((uint8_t)0x40) |
#define PPSMC_MSG_NoForcedLevel ((uint8_t)0x41) |
#define PPSMC_MSG_ForceHigh ((uint8_t)0x42) |
#define PPSMC_MSG_ForceMediumOrHigh ((uint8_t)0x43) |
#define PPSMC_MSG_SwitchToMinimumPower ((uint8_t)0x51) |
#define PPSMC_MSG_ResumeFromMinimumPower ((uint8_t)0x52) |
#define PPSMC_MSG_EnableCac ((uint8_t)0x53) |
#define PPSMC_MSG_DisableCac ((uint8_t)0x54) |
#define PPSMC_TDPClampingActive ((uint8_t)0x59) |
#define PPSMC_TDPClampingInactive ((uint8_t)0x5A) |
#define PPSMC_MSG_NoDisplay ((uint8_t)0x5D) |
#define PPSMC_MSG_HasDisplay ((uint8_t)0x5E) |
#define PPSMC_MSG_UVDPowerOFF ((uint8_t)0x60) |
#define PPSMC_MSG_UVDPowerON ((uint8_t)0x61) |
#define PPSMC_MSG_EnableULV ((uint8_t)0x62) |
#define PPSMC_MSG_DisableULV ((uint8_t)0x63) |
#define PPSMC_MSG_EnterULV ((uint8_t)0x64) |
#define PPSMC_MSG_ExitULV ((uint8_t)0x65) |
#define PPSMC_CACLongTermAvgEnable ((uint8_t)0x6E) |
#define PPSMC_CACLongTermAvgDisable ((uint8_t)0x6F) |
#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint8_t)0x7A) |
#define PPSMC_FlushDataCache ((uint8_t)0x80) |
#define PPSMC_MSG_SetEnabledLevels ((uint8_t)0x82) |
#define PPSMC_MSG_SetForcedLevels ((uint8_t)0x83) |
#define PPSMC_MSG_ResetToDefaults ((uint8_t)0x84) |
#define PPSMC_MSG_EnableDTE ((uint8_t)0x87) |
#define PPSMC_MSG_DisableDTE ((uint8_t)0x88) |
#define PPSMC_MSG_ThrottleOVRDSCLKDS ((uint8_t)0x96) |
#define PPSMC_MSG_CancelThrottleOVRDSCLKDS ((uint8_t)0x97) |
/* CI/KV/KB */ |
#define PPSMC_MSG_UVDDPM_SetEnabledMask ((uint16_t) 0x12D) |
#define PPSMC_MSG_VCEDPM_SetEnabledMask ((uint16_t) 0x12E) |
#define PPSMC_MSG_ACPDPM_SetEnabledMask ((uint16_t) 0x12F) |
#define PPSMC_MSG_SAMUDPM_SetEnabledMask ((uint16_t) 0x130) |
#define PPSMC_MSG_MCLKDPM_ForceState ((uint16_t) 0x131) |
#define PPSMC_MSG_MCLKDPM_NoForcedLevel ((uint16_t) 0x132) |
#define PPSMC_MSG_Voltage_Cntl_Disable ((uint16_t) 0x135) |
#define PPSMC_MSG_PCIeDPM_Enable ((uint16_t) 0x136) |
#define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d) |
#define PPSMC_MSG_ACPPowerOFF ((uint16_t) 0x137) |
#define PPSMC_MSG_ACPPowerON ((uint16_t) 0x138) |
#define PPSMC_MSG_SAMPowerOFF ((uint16_t) 0x139) |
#define PPSMC_MSG_SAMPowerON ((uint16_t) 0x13a) |
#define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d) |
#define PPSMC_MSG_NBDPM_Enable ((uint16_t) 0x140) |
#define PPSMC_MSG_NBDPM_Disable ((uint16_t) 0x141) |
#define PPSMC_MSG_SCLKDPM_SetEnabledMask ((uint16_t) 0x145) |
#define PPSMC_MSG_MCLKDPM_SetEnabledMask ((uint16_t) 0x146) |
#define PPSMC_MSG_PCIeDPM_ForceLevel ((uint16_t) 0x147) |
#define PPSMC_MSG_PCIeDPM_UnForceLevel ((uint16_t) 0x148) |
#define PPSMC_MSG_EnableVRHotGPIOInterrupt ((uint16_t) 0x14a) |
#define PPSMC_MSG_DPM_Enable ((uint16_t) 0x14e) |
#define PPSMC_MSG_DPM_Disable ((uint16_t) 0x14f) |
#define PPSMC_MSG_MCLKDPM_Enable ((uint16_t) 0x150) |
#define PPSMC_MSG_MCLKDPM_Disable ((uint16_t) 0x151) |
#define PPSMC_MSG_UVDDPM_Enable ((uint16_t) 0x154) |
#define PPSMC_MSG_UVDDPM_Disable ((uint16_t) 0x155) |
#define PPSMC_MSG_SAMUDPM_Enable ((uint16_t) 0x156) |
#define PPSMC_MSG_SAMUDPM_Disable ((uint16_t) 0x157) |
#define PPSMC_MSG_ACPDPM_Enable ((uint16_t) 0x158) |
#define PPSMC_MSG_ACPDPM_Disable ((uint16_t) 0x159) |
#define PPSMC_MSG_VCEDPM_Enable ((uint16_t) 0x15a) |
#define PPSMC_MSG_VCEDPM_Disable ((uint16_t) 0x15b) |
#define PPSMC_MSG_VddC_Request ((uint16_t) 0x15f) |
#define PPSMC_MSG_SCLKDPM_GetEnabledMask ((uint16_t) 0x162) |
#define PPSMC_MSG_PCIeDPM_SetEnabledMask ((uint16_t) 0x167) |
#define PPSMC_MSG_TDCLimitEnable ((uint16_t) 0x169) |
#define PPSMC_MSG_TDCLimitDisable ((uint16_t) 0x16a) |
#define PPSMC_MSG_PkgPwrLimitEnable ((uint16_t) 0x185) |
#define PPSMC_MSG_PkgPwrLimitDisable ((uint16_t) 0x186) |
#define PPSMC_MSG_PkgPwrSetLimit ((uint16_t) 0x187) |
#define PPSMC_MSG_OverDriveSetTargetTdp ((uint16_t) 0x188) |
#define PPSMC_MSG_SCLKDPM_FreezeLevel ((uint16_t) 0x189) |
#define PPSMC_MSG_SCLKDPM_UnfreezeLevel ((uint16_t) 0x18A) |
#define PPSMC_MSG_MCLKDPM_FreezeLevel ((uint16_t) 0x18B) |
#define PPSMC_MSG_MCLKDPM_UnfreezeLevel ((uint16_t) 0x18C) |
#define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F) |
#define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190) |
#define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191) |
#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200) |
#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201) |
/* TN */ |
#define PPSMC_MSG_DPM_Config ((uint32_t) 0x102) |
#define PPSMC_MSG_DPM_ForceState ((uint32_t) 0x104) |
#define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108) |
#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112) |
#define PPSMC_MSG_Voltage_Cntl_Enable ((uint32_t) 0x109) |
#define PPSMC_MSG_VCEPowerOFF ((uint32_t) 0x10e) |
#define PPSMC_MSG_VCEPowerON ((uint32_t) 0x10f) |
#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d) |
#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e) |
#define PPSMC_MSG_EnableBAPM ((uint32_t) 0x120) |
#define PPSMC_MSG_DisableBAPM ((uint32_t) 0x121) |
#define PPSMC_MSG_UVD_DPM_Config ((uint32_t) 0x124) |
typedef uint16_t PPSMC_Msg; |
#pragma pack(pop) |
#endif |
/drivers/video/drm/radeon/pptable.h |
---|
0,0 → 1,682 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
*/ |
#ifndef _PPTABLE_H |
#define _PPTABLE_H |
#pragma pack(1) |
typedef struct _ATOM_PPLIB_THERMALCONTROLLER |
{ |
UCHAR ucType; // one of ATOM_PP_THERMALCONTROLLER_* |
UCHAR ucI2cLine; // as interpreted by DAL I2C |
UCHAR ucI2cAddress; |
UCHAR ucFanParameters; // Fan Control Parameters. |
UCHAR ucFanMinRPM; // Fan Minimum RPM (hundreds) -- for display purposes only. |
UCHAR ucFanMaxRPM; // Fan Maximum RPM (hundreds) -- for display purposes only. |
UCHAR ucReserved; // ---- |
UCHAR ucFlags; // to be defined |
} ATOM_PPLIB_THERMALCONTROLLER; |
#define ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f |
#define ATOM_PP_FANPARAMETERS_NOFAN 0x80 // No fan is connected to this controller. |
#define ATOM_PP_THERMALCONTROLLER_NONE 0 |
#define ATOM_PP_THERMALCONTROLLER_LM63 1 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_ADM1032 2 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_ADM1030 3 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_MUA6649 4 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_LM64 5 |
#define ATOM_PP_THERMALCONTROLLER_F75375 6 // Not used by PPLib |
#define ATOM_PP_THERMALCONTROLLER_RV6xx 7 |
#define ATOM_PP_THERMALCONTROLLER_RV770 8 |
#define ATOM_PP_THERMALCONTROLLER_ADT7473 9 |
#define ATOM_PP_THERMALCONTROLLER_KONG 10 |
#define ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO 11 |
#define ATOM_PP_THERMALCONTROLLER_EVERGREEN 12 |
#define ATOM_PP_THERMALCONTROLLER_EMC2103 13 /* 0x0D */ // Only fan control will be implemented, do NOT show this in PPGen. |
#define ATOM_PP_THERMALCONTROLLER_SUMO 14 /* 0x0E */ // Sumo type, used internally |
#define ATOM_PP_THERMALCONTROLLER_NISLANDS 15 |
#define ATOM_PP_THERMALCONTROLLER_SISLANDS 16 |
#define ATOM_PP_THERMALCONTROLLER_LM96163 17 |
#define ATOM_PP_THERMALCONTROLLER_CISLANDS 18 |
#define ATOM_PP_THERMALCONTROLLER_KAVERI 19 |
// Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal. |
// We probably should reserve the bit 0x80 for this use. |
// To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here). |
// The driver can pick the correct internal controller based on the ASIC. |
#define ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 // ADT7473 Fan Control + Internal Thermal Controller |
#define ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL 0x8D // EMC2103 Fan Control + Internal Thermal Controller |
typedef struct _ATOM_PPLIB_STATE |
{ |
UCHAR ucNonClockStateIndex; |
UCHAR ucClockStateIndices[1]; // variable-sized |
} ATOM_PPLIB_STATE; |
typedef struct _ATOM_PPLIB_FANTABLE |
{ |
UCHAR ucFanTableFormat; // Change this if the table format changes or version changes so that the other fields are not the same. |
UCHAR ucTHyst; // Temperature hysteresis. Integer. |
USHORT usTMin; // The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. |
USHORT usTMed; // The middle temperature where we change slopes. |
USHORT usTHigh; // The high point above TMed for adjusting the second slope. |
USHORT usPWMMin; // The minimum PWM value in percent (0.01% increments). |
USHORT usPWMMed; // The PWM value (in percent) at TMed. |
USHORT usPWMHigh; // The PWM value at THigh. |
} ATOM_PPLIB_FANTABLE; |
typedef struct _ATOM_PPLIB_FANTABLE2 |
{ |
ATOM_PPLIB_FANTABLE basicTable; |
USHORT usTMax; // The max temperature |
} ATOM_PPLIB_FANTABLE2; |
typedef struct _ATOM_PPLIB_EXTENDEDHEADER |
{ |
USHORT usSize; |
ULONG ulMaxEngineClock; // For Overdrive. |
ULONG ulMaxMemoryClock; // For Overdrive. |
// Add extra system parameters here, always adjust size to include all fields. |
USHORT usVCETableOffset; //points to ATOM_PPLIB_VCE_Table |
USHORT usUVDTableOffset; //points to ATOM_PPLIB_UVD_Table |
USHORT usSAMUTableOffset; //points to ATOM_PPLIB_SAMU_Table |
USHORT usPPMTableOffset; //points to ATOM_PPLIB_PPM_Table |
USHORT usACPTableOffset; //points to ATOM_PPLIB_ACP_Table |
USHORT usPowerTuneTableOffset; //points to ATOM_PPLIB_POWERTUNE_Table |
} ATOM_PPLIB_EXTENDEDHEADER; |
//// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps |
#define ATOM_PP_PLATFORM_CAP_BACKBIAS 1 |
#define ATOM_PP_PLATFORM_CAP_POWERPLAY 2 |
#define ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 4 |
#define ATOM_PP_PLATFORM_CAP_ASPM_L0s 8 |
#define ATOM_PP_PLATFORM_CAP_ASPM_L1 16 |
#define ATOM_PP_PLATFORM_CAP_HARDWAREDC 32 |
#define ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY 64 |
#define ATOM_PP_PLATFORM_CAP_STEPVDDC 128 |
#define ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL 256 |
#define ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL 512 |
#define ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 1024 |
#define ATOM_PP_PLATFORM_CAP_HTLINKCONTROL 2048 |
#define ATOM_PP_PLATFORM_CAP_MVDDCONTROL 4096 |
#define ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT 0x2000 // Go to boot state on alerts, e.g. on an AC->DC transition. |
#define ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT 0x4000 // Do NOT wait for VBLANK during an alert (e.g. AC->DC transition). |
#define ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000 // Does the driver control VDDCI independently from VDDC. |
#define ATOM_PP_PLATFORM_CAP_REGULATOR_HOT 0x00010000 // Enable the 'regulator hot' feature. |
#define ATOM_PP_PLATFORM_CAP_BACO 0x00020000 // Does the driver supports BACO state. |
#define ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE 0x00040000 // Does the driver supports new CAC voltage table. |
#define ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY 0x00080000 // Does the driver supports revert GPIO5 polarity. |
#define ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17 0x00100000 // Does the driver supports thermal2GPIO17. |
#define ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE 0x00200000 // Does the driver supports VR HOT GPIO Configurable. |
#define ATOM_PP_PLATFORM_CAP_TEMP_INVERSION 0x00400000 // Does the driver supports Temp Inversion feature. |
#define ATOM_PP_PLATFORM_CAP_EVV 0x00800000 |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE |
{ |
ATOM_COMMON_TABLE_HEADER sHeader; |
UCHAR ucDataRevision; |
UCHAR ucNumStates; |
UCHAR ucStateEntrySize; |
UCHAR ucClockInfoSize; |
UCHAR ucNonClockSize; |
// offset from start of this table to array of ucNumStates ATOM_PPLIB_STATE structures |
USHORT usStateArrayOffset; |
// offset from start of this table to array of ASIC-specific structures, |
// currently ATOM_PPLIB_CLOCK_INFO. |
USHORT usClockInfoArrayOffset; |
// offset from start of this table to array of ATOM_PPLIB_NONCLOCK_INFO |
USHORT usNonClockInfoArrayOffset; |
USHORT usBackbiasTime; // in microseconds |
USHORT usVoltageTime; // in microseconds |
USHORT usTableSize; //the size of this structure, or the extended structure |
ULONG ulPlatformCaps; // See ATOM_PPLIB_CAPS_* |
ATOM_PPLIB_THERMALCONTROLLER sThermalController; |
USHORT usBootClockInfoOffset; |
USHORT usBootNonClockInfoOffset; |
} ATOM_PPLIB_POWERPLAYTABLE; |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE2 |
{ |
ATOM_PPLIB_POWERPLAYTABLE basicTable; |
UCHAR ucNumCustomThermalPolicy; |
USHORT usCustomThermalPolicyArrayOffset; |
}ATOM_PPLIB_POWERPLAYTABLE2, *LPATOM_PPLIB_POWERPLAYTABLE2; |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE3 |
{ |
ATOM_PPLIB_POWERPLAYTABLE2 basicTable2; |
USHORT usFormatID; // To be used ONLY by PPGen. |
USHORT usFanTableOffset; |
USHORT usExtendendedHeaderOffset; |
} ATOM_PPLIB_POWERPLAYTABLE3, *LPATOM_PPLIB_POWERPLAYTABLE3; |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE4 |
{ |
ATOM_PPLIB_POWERPLAYTABLE3 basicTable3; |
ULONG ulGoldenPPID; // PPGen use only |
ULONG ulGoldenRevision; // PPGen use only |
USHORT usVddcDependencyOnSCLKOffset; |
USHORT usVddciDependencyOnMCLKOffset; |
USHORT usVddcDependencyOnMCLKOffset; |
USHORT usMaxClockVoltageOnDCOffset; |
USHORT usVddcPhaseShedLimitsTableOffset; // Points to ATOM_PPLIB_PhaseSheddingLimits_Table |
USHORT usMvddDependencyOnMCLKOffset; |
} ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4; |
typedef struct _ATOM_PPLIB_POWERPLAYTABLE5 |
{ |
ATOM_PPLIB_POWERPLAYTABLE4 basicTable4; |
ULONG ulTDPLimit; |
ULONG ulNearTDPLimit; |
ULONG ulSQRampingThreshold; |
USHORT usCACLeakageTableOffset; // Points to ATOM_PPLIB_CAC_Leakage_Table |
ULONG ulCACLeakage; // The iLeakage for driver calculated CAC leakage table |
USHORT usTDPODLimit; |
USHORT usLoadLineSlope; // in milliOhms * 100 |
} ATOM_PPLIB_POWERPLAYTABLE5, *LPATOM_PPLIB_POWERPLAYTABLE5; |
//// ATOM_PPLIB_NONCLOCK_INFO::usClassification |
#define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007 |
#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0 |
#define ATOM_PPLIB_CLASSIFICATION_UI_NONE 0 |
#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY 1 |
#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED 3 |
#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE 5 |
// 2, 4, 6, 7 are reserved |
#define ATOM_PPLIB_CLASSIFICATION_BOOT 0x0008 |
#define ATOM_PPLIB_CLASSIFICATION_THERMAL 0x0010 |
#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE 0x0020 |
#define ATOM_PPLIB_CLASSIFICATION_REST 0x0040 |
#define ATOM_PPLIB_CLASSIFICATION_FORCED 0x0080 |
#define ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE 0x0100 |
#define ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE 0x0200 |
#define ATOM_PPLIB_CLASSIFICATION_UVDSTATE 0x0400 |
#define ATOM_PPLIB_CLASSIFICATION_3DLOW 0x0800 |
#define ATOM_PPLIB_CLASSIFICATION_ACPI 0x1000 |
#define ATOM_PPLIB_CLASSIFICATION_HD2STATE 0x2000 |
#define ATOM_PPLIB_CLASSIFICATION_HDSTATE 0x4000 |
#define ATOM_PPLIB_CLASSIFICATION_SDSTATE 0x8000 |
//// ATOM_PPLIB_NONCLOCK_INFO::usClassification2 |
#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001 |
#define ATOM_PPLIB_CLASSIFICATION2_ULV 0x0002 |
#define ATOM_PPLIB_CLASSIFICATION2_MVC 0x0004 //Multi-View Codec (BD-3D) |
//// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings |
#define ATOM_PPLIB_SINGLE_DISPLAY_ONLY 0x00000001 |
#define ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK 0x00000002 |
// 0 is 2.5Gb/s, 1 is 5Gb/s |
#define ATOM_PPLIB_PCIE_LINK_SPEED_MASK 0x00000004 |
#define ATOM_PPLIB_PCIE_LINK_SPEED_SHIFT 2 |
// lanes - 1: 1, 2, 4, 8, 12, 16 permitted by PCIE spec |
#define ATOM_PPLIB_PCIE_LINK_WIDTH_MASK 0x000000F8 |
#define ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT 3 |
// lookup into reduced refresh-rate table |
#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK 0x00000F00 |
#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT 8 |
#define ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED 0 |
#define ATOM_PPLIB_LIMITED_REFRESHRATE_50HZ 1 |
// 2-15 TBD as needed. |
#define ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING 0x00001000 |
#define ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS 0x00002000 |
#define ATOM_PPLIB_DISALLOW_ON_DC 0x00004000 |
#define ATOM_PPLIB_ENABLE_VARIBRIGHT 0x00008000 |
//memory related flags |
#define ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF 0x000010000 |
//M3 Arb //2bits, current 3 sets of parameters in total |
#define ATOM_PPLIB_M3ARB_MASK 0x00060000 |
#define ATOM_PPLIB_M3ARB_SHIFT 17 |
#define ATOM_PPLIB_ENABLE_DRR 0x00080000 |
// remaining 16 bits are reserved |
typedef struct _ATOM_PPLIB_THERMAL_STATE |
{ |
UCHAR ucMinTemperature; |
UCHAR ucMaxTemperature; |
UCHAR ucThermalAction; |
}ATOM_PPLIB_THERMAL_STATE, *LPATOM_PPLIB_THERMAL_STATE; |
// Contained in an array starting at the offset |
// in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset. |
// referenced from ATOM_PPLIB_STATE_INFO::ucNonClockStateIndex |
#define ATOM_PPLIB_NONCLOCKINFO_VER1 12 |
#define ATOM_PPLIB_NONCLOCKINFO_VER2 24 |
typedef struct _ATOM_PPLIB_NONCLOCK_INFO |
{ |
USHORT usClassification; |
UCHAR ucMinTemperature; |
UCHAR ucMaxTemperature; |
ULONG ulCapsAndSettings; |
UCHAR ucRequiredPower; |
USHORT usClassification2; |
ULONG ulVCLK; |
ULONG ulDCLK; |
UCHAR ucUnused[5]; |
} ATOM_PPLIB_NONCLOCK_INFO; |
// Contained in an array starting at the offset |
// in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset. |
// referenced from ATOM_PPLIB_STATE::ucClockStateIndices |
typedef struct _ATOM_PPLIB_R600_CLOCK_INFO |
{ |
USHORT usEngineClockLow; |
UCHAR ucEngineClockHigh; |
USHORT usMemoryClockLow; |
UCHAR ucMemoryClockHigh; |
USHORT usVDDC; |
USHORT usUnused1; |
USHORT usUnused2; |
ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_* |
} ATOM_PPLIB_R600_CLOCK_INFO; |
// ulFlags in ATOM_PPLIB_R600_CLOCK_INFO |
#define ATOM_PPLIB_R600_FLAGS_PCIEGEN2 1 |
#define ATOM_PPLIB_R600_FLAGS_UVDSAFE 2 |
#define ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE 4 |
#define ATOM_PPLIB_R600_FLAGS_MEMORY_ODT_OFF 8 |
#define ATOM_PPLIB_R600_FLAGS_MEMORY_DLL_OFF 16 |
#define ATOM_PPLIB_R600_FLAGS_LOWPOWER 32 // On the RV770 use 'low power' setting (sequencer S0). |
typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO |
{ |
USHORT usLowEngineClockLow; // Low Engine clock in MHz (the same way as on the R600). |
UCHAR ucLowEngineClockHigh; |
USHORT usHighEngineClockLow; // High Engine clock in MHz. |
UCHAR ucHighEngineClockHigh; |
USHORT usMemoryClockLow; // For now one of the ATOM_PPLIB_RS780_SPMCLK_XXXX constants. |
UCHAR ucMemoryClockHigh; // Currentyl unused. |
UCHAR ucPadding; // For proper alignment and size. |
USHORT usVDDC; // For the 780, use: None, Low, High, Variable |
UCHAR ucMaxHTLinkWidth; // From SBIOS - {2, 4, 8, 16} |
UCHAR ucMinHTLinkWidth; // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could |
USHORT usHTLinkFreq; // See definition ATOM_PPLIB_RS780_HTLINKFREQ_xxx or in MHz(>=200). |
ULONG ulFlags; |
} ATOM_PPLIB_RS780_CLOCK_INFO; |
#define ATOM_PPLIB_RS780_VOLTAGE_NONE 0 |
#define ATOM_PPLIB_RS780_VOLTAGE_LOW 1 |
#define ATOM_PPLIB_RS780_VOLTAGE_HIGH 2 |
#define ATOM_PPLIB_RS780_VOLTAGE_VARIABLE 3 |
#define ATOM_PPLIB_RS780_SPMCLK_NONE 0 // We cannot change the side port memory clock, leave it as it is. |
#define ATOM_PPLIB_RS780_SPMCLK_LOW 1 |
#define ATOM_PPLIB_RS780_SPMCLK_HIGH 2 |
#define ATOM_PPLIB_RS780_HTLINKFREQ_NONE 0 |
#define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1 |
#define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2 |
typedef struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO |
{ |
USHORT usEngineClockLow; |
UCHAR ucEngineClockHigh; |
USHORT usMemoryClockLow; |
UCHAR ucMemoryClockHigh; |
USHORT usVDDC; |
USHORT usVDDCI; |
USHORT usUnused; |
ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_* |
} ATOM_PPLIB_EVERGREEN_CLOCK_INFO; |
typedef struct _ATOM_PPLIB_SI_CLOCK_INFO |
{ |
USHORT usEngineClockLow; |
UCHAR ucEngineClockHigh; |
USHORT usMemoryClockLow; |
UCHAR ucMemoryClockHigh; |
USHORT usVDDC; |
USHORT usVDDCI; |
UCHAR ucPCIEGen; |
UCHAR ucUnused1; |
ULONG ulFlags; // ATOM_PPLIB_SI_FLAGS_*, no flag is necessary for now |
} ATOM_PPLIB_SI_CLOCK_INFO; |
typedef struct _ATOM_PPLIB_CI_CLOCK_INFO |
{ |
USHORT usEngineClockLow; |
UCHAR ucEngineClockHigh; |
USHORT usMemoryClockLow; |
UCHAR ucMemoryClockHigh; |
UCHAR ucPCIEGen; |
USHORT usPCIELane; |
} ATOM_PPLIB_CI_CLOCK_INFO; |
typedef struct _ATOM_PPLIB_SUMO_CLOCK_INFO{ |
USHORT usEngineClockLow; //clockfrequency & 0xFFFF. The unit is in 10khz |
UCHAR ucEngineClockHigh; //clockfrequency >> 16. |
UCHAR vddcIndex; //2-bit vddc index; |
USHORT tdpLimit; |
//please initalize to 0 |
USHORT rsv1; |
//please initialize to 0s |
ULONG rsv2[2]; |
}ATOM_PPLIB_SUMO_CLOCK_INFO; |
typedef struct _ATOM_PPLIB_STATE_V2 |
{ |
//number of valid dpm levels in this state; Driver uses it to calculate the whole |
//size of the state: sizeof(ATOM_PPLIB_STATE_V2) + (ucNumDPMLevels - 1) * sizeof(UCHAR) |
UCHAR ucNumDPMLevels; |
//a index to the array of nonClockInfos |
UCHAR nonClockInfoIndex; |
/** |
* Driver will read the first ucNumDPMLevels in this array |
*/ |
UCHAR clockInfoIndex[1]; |
} ATOM_PPLIB_STATE_V2; |
typedef struct _StateArray{ |
//how many states we have |
UCHAR ucNumEntries; |
ATOM_PPLIB_STATE_V2 states[1]; |
}StateArray; |
typedef struct _ClockInfoArray{ |
//how many clock levels we have |
UCHAR ucNumEntries; |
//sizeof(ATOM_PPLIB_CLOCK_INFO) |
UCHAR ucEntrySize; |
UCHAR clockInfo[1]; |
}ClockInfoArray; |
typedef struct _NonClockInfoArray{ |
//how many non-clock levels we have. normally should be same as number of states |
UCHAR ucNumEntries; |
//sizeof(ATOM_PPLIB_NONCLOCK_INFO) |
UCHAR ucEntrySize; |
ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[1]; |
}NonClockInfoArray; |
typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Record |
{ |
USHORT usClockLow; |
UCHAR ucClockHigh; |
USHORT usVoltage; |
}ATOM_PPLIB_Clock_Voltage_Dependency_Record; |
typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Table |
{ |
UCHAR ucNumEntries; // Number of entries. |
ATOM_PPLIB_Clock_Voltage_Dependency_Record entries[1]; // Dynamically allocate entries. |
}ATOM_PPLIB_Clock_Voltage_Dependency_Table; |
typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Record |
{ |
USHORT usSclkLow; |
UCHAR ucSclkHigh; |
USHORT usMclkLow; |
UCHAR ucMclkHigh; |
USHORT usVddc; |
USHORT usVddci; |
}ATOM_PPLIB_Clock_Voltage_Limit_Record; |
typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table |
{ |
UCHAR ucNumEntries; // Number of entries. |
ATOM_PPLIB_Clock_Voltage_Limit_Record entries[1]; // Dynamically allocate entries. |
}ATOM_PPLIB_Clock_Voltage_Limit_Table; |
union _ATOM_PPLIB_CAC_Leakage_Record |
{ |
struct |
{ |
USHORT usVddc; // We use this field for the "fake" standardized VDDC for power calculations; For CI and newer, we use this as the real VDDC value. in CI we read it as StdVoltageHiSidd |
ULONG ulLeakageValue; // For CI and newer we use this as the "fake" standar VDDC value. in CI we read it as StdVoltageLoSidd |
}; |
struct |
{ |
USHORT usVddc1; |
USHORT usVddc2; |
USHORT usVddc3; |
}; |
}; |
typedef union _ATOM_PPLIB_CAC_Leakage_Record ATOM_PPLIB_CAC_Leakage_Record; |
typedef struct _ATOM_PPLIB_CAC_Leakage_Table |
{ |
UCHAR ucNumEntries; // Number of entries. |
ATOM_PPLIB_CAC_Leakage_Record entries[1]; // Dynamically allocate entries. |
}ATOM_PPLIB_CAC_Leakage_Table; |
typedef struct _ATOM_PPLIB_PhaseSheddingLimits_Record |
{ |
USHORT usVoltage; |
USHORT usSclkLow; |
UCHAR ucSclkHigh; |
USHORT usMclkLow; |
UCHAR ucMclkHigh; |
}ATOM_PPLIB_PhaseSheddingLimits_Record; |
typedef struct _ATOM_PPLIB_PhaseSheddingLimits_Table |
{ |
UCHAR ucNumEntries; // Number of entries. |
ATOM_PPLIB_PhaseSheddingLimits_Record entries[1]; // Dynamically allocate entries. |
}ATOM_PPLIB_PhaseSheddingLimits_Table; |
typedef struct _VCEClockInfo{ |
USHORT usEVClkLow; |
UCHAR ucEVClkHigh; |
USHORT usECClkLow; |
UCHAR ucECClkHigh; |
}VCEClockInfo; |
typedef struct _VCEClockInfoArray{ |
UCHAR ucNumEntries; |
VCEClockInfo entries[1]; |
}VCEClockInfoArray; |
typedef struct _ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record |
{ |
USHORT usVoltage; |
UCHAR ucVCEClockInfoIndex; |
}ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record; |
typedef struct _ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table |
{ |
UCHAR numEntries; |
ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record entries[1]; |
}ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table; |
typedef struct _ATOM_PPLIB_VCE_State_Record |
{ |
UCHAR ucVCEClockInfoIndex; |
UCHAR ucClockInfoIndex; //highest 2 bits indicates memory p-states, lower 6bits indicates index to ClockInfoArrary |
}ATOM_PPLIB_VCE_State_Record; |
typedef struct _ATOM_PPLIB_VCE_State_Table |
{ |
UCHAR numEntries; |
ATOM_PPLIB_VCE_State_Record entries[1]; |
}ATOM_PPLIB_VCE_State_Table; |
typedef struct _ATOM_PPLIB_VCE_Table |
{ |
UCHAR revid; |
// VCEClockInfoArray array; |
// ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table limits; |
// ATOM_PPLIB_VCE_State_Table states; |
}ATOM_PPLIB_VCE_Table; |
typedef struct _UVDClockInfo{ |
USHORT usVClkLow; |
UCHAR ucVClkHigh; |
USHORT usDClkLow; |
UCHAR ucDClkHigh; |
}UVDClockInfo; |
typedef struct _UVDClockInfoArray{ |
UCHAR ucNumEntries; |
UVDClockInfo entries[1]; |
}UVDClockInfoArray; |
typedef struct _ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record |
{ |
USHORT usVoltage; |
UCHAR ucUVDClockInfoIndex; |
}ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record; |
typedef struct _ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table |
{ |
UCHAR numEntries; |
ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record entries[1]; |
}ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table; |
typedef struct _ATOM_PPLIB_UVD_Table |
{ |
UCHAR revid; |
// UVDClockInfoArray array; |
// ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table limits; |
}ATOM_PPLIB_UVD_Table; |
typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Record |
{ |
USHORT usVoltage; |
USHORT usSAMClockLow; |
UCHAR ucSAMClockHigh; |
}ATOM_PPLIB_SAMClk_Voltage_Limit_Record; |
typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Table{ |
UCHAR numEntries; |
ATOM_PPLIB_SAMClk_Voltage_Limit_Record entries[1]; |
}ATOM_PPLIB_SAMClk_Voltage_Limit_Table; |
typedef struct _ATOM_PPLIB_SAMU_Table |
{ |
UCHAR revid; |
ATOM_PPLIB_SAMClk_Voltage_Limit_Table limits; |
}ATOM_PPLIB_SAMU_Table; |
typedef struct _ATOM_PPLIB_ACPClk_Voltage_Limit_Record |
{ |
USHORT usVoltage; |
USHORT usACPClockLow; |
UCHAR ucACPClockHigh; |
}ATOM_PPLIB_ACPClk_Voltage_Limit_Record; |
typedef struct _ATOM_PPLIB_ACPClk_Voltage_Limit_Table{ |
UCHAR numEntries; |
ATOM_PPLIB_ACPClk_Voltage_Limit_Record entries[1]; |
}ATOM_PPLIB_ACPClk_Voltage_Limit_Table; |
typedef struct _ATOM_PPLIB_ACP_Table |
{ |
UCHAR revid; |
ATOM_PPLIB_ACPClk_Voltage_Limit_Table limits; |
}ATOM_PPLIB_ACP_Table; |
typedef struct _ATOM_PowerTune_Table{ |
USHORT usTDP; |
USHORT usConfigurableTDP; |
USHORT usTDC; |
USHORT usBatteryPowerLimit; |
USHORT usSmallPowerLimit; |
USHORT usLowCACLeakage; |
USHORT usHighCACLeakage; |
}ATOM_PowerTune_Table; |
typedef struct _ATOM_PPLIB_POWERTUNE_Table |
{ |
UCHAR revid; |
ATOM_PowerTune_Table power_tune_table; |
}ATOM_PPLIB_POWERTUNE_Table; |
typedef struct _ATOM_PPLIB_POWERTUNE_Table_V1 |
{ |
UCHAR revid; |
ATOM_PowerTune_Table power_tune_table; |
USHORT usMaximumPowerDeliveryLimit; |
USHORT usReserve[7]; |
} ATOM_PPLIB_POWERTUNE_Table_V1; |
#define ATOM_PPM_A_A 1 |
#define ATOM_PPM_A_I 2 |
typedef struct _ATOM_PPLIB_PPM_Table |
{ |
UCHAR ucRevId; |
UCHAR ucPpmDesign; //A+I or A+A |
USHORT usCpuCoreNumber; |
ULONG ulPlatformTDP; |
ULONG ulSmallACPlatformTDP; |
ULONG ulPlatformTDC; |
ULONG ulSmallACPlatformTDC; |
ULONG ulApuTDP; |
ULONG ulDGpuTDP; |
ULONG ulDGpuUlvPower; |
ULONG ulTjmax; |
} ATOM_PPLIB_PPM_Table; |
#pragma pack() |
#endif |
/drivers/video/drm/radeon/r100.c |
---|
61,6 → 61,7 |
MODULE_FIRMWARE(FIRMWARE_RS600); |
MODULE_FIRMWARE(FIRMWARE_R520); |
#include "r100_track.h" |
/* This files gather functions specifics to: |
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 |
139,7 → 140,20 |
} |
} |
} |
u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) |
/** |
* r100_page_flip - pageflip callback. |
* |
* @rdev: radeon_device pointer |
* @crtc_id: crtc to cleanup pageflip on |
* @crtc_base: new address of the crtc (GPU MC address) |
* |
* Does the actual pageflip (r1xx-r4xx). |
* 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. |
*/ |
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; |
161,9 → 175,334 |
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); |
} |
/** |
* r100_pm_get_dynpm_state - look up dynpm power state callback. |
* |
* @rdev: radeon_device pointer |
* |
* Look up the optimal power state based on the |
* current state of the GPU (r1xx-r5xx). |
* Used for dynpm only. |
*/ |
void r100_pm_get_dynpm_state(struct radeon_device *rdev) |
{ |
int i; |
rdev->pm.dynpm_can_upclock = true; |
rdev->pm.dynpm_can_downclock = true; |
switch (rdev->pm.dynpm_planned_action) { |
case DYNPM_ACTION_MINIMUM: |
rdev->pm.requested_power_state_index = 0; |
rdev->pm.dynpm_can_downclock = false; |
break; |
case DYNPM_ACTION_DOWNCLOCK: |
if (rdev->pm.current_power_state_index == 0) { |
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; |
rdev->pm.dynpm_can_downclock = false; |
} else { |
if (rdev->pm.active_crtc_count > 1) { |
for (i = 0; i < rdev->pm.num_power_states; i++) { |
if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) |
continue; |
else if (i >= rdev->pm.current_power_state_index) { |
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; |
break; |
} else { |
rdev->pm.requested_power_state_index = i; |
break; |
} |
} |
} else |
rdev->pm.requested_power_state_index = |
rdev->pm.current_power_state_index - 1; |
} |
/* don't use the power state if crtcs are active and no display flag is set */ |
if ((rdev->pm.active_crtc_count > 0) && |
(rdev->pm.power_state[rdev->pm.requested_power_state_index].clock_info[0].flags & |
RADEON_PM_MODE_NO_DISPLAY)) { |
rdev->pm.requested_power_state_index++; |
} |
break; |
case DYNPM_ACTION_UPCLOCK: |
if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { |
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; |
rdev->pm.dynpm_can_upclock = false; |
} else { |
if (rdev->pm.active_crtc_count > 1) { |
for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { |
if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) |
continue; |
else if (i <= rdev->pm.current_power_state_index) { |
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; |
break; |
} else { |
rdev->pm.requested_power_state_index = i; |
break; |
} |
} |
} else |
rdev->pm.requested_power_state_index = |
rdev->pm.current_power_state_index + 1; |
} |
break; |
case DYNPM_ACTION_DEFAULT: |
rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; |
rdev->pm.dynpm_can_upclock = false; |
break; |
case DYNPM_ACTION_NONE: |
default: |
DRM_ERROR("Requested mode for not defined action\n"); |
return; |
} |
/* only one clock mode per power state */ |
rdev->pm.requested_clock_mode_index = 0; |
DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n", |
rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
clock_info[rdev->pm.requested_clock_mode_index].sclk, |
rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
clock_info[rdev->pm.requested_clock_mode_index].mclk, |
rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
pcie_lanes); |
} |
/** |
* r100_pm_init_profile - Initialize power profiles callback. |
* |
* @rdev: radeon_device pointer |
* |
* Initialize the power states used in profile mode |
* (r1xx-r3xx). |
* Used for profile mode only. |
*/ |
void r100_pm_init_profile(struct radeon_device *rdev) |
{ |
/* default */ |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; |
/* low sh */ |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; |
/* mid sh */ |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; |
/* high sh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; |
/* low mh */ |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; |
/* mid mh */ |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; |
/* high mh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; |
} |
/** |
* r100_pm_misc - set additional pm hw parameters callback. |
* |
* @rdev: radeon_device pointer |
* |
* Set non-clock parameters associated with a power state |
* (voltage, pcie lanes, etc.) (r1xx-r4xx). |
*/ |
void r100_pm_misc(struct radeon_device *rdev) |
{ |
int requested_index = rdev->pm.requested_power_state_index; |
struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; |
struct radeon_voltage *voltage = &ps->clock_info[0].voltage; |
u32 tmp, sclk_cntl, sclk_cntl2, sclk_more_cntl; |
if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { |
if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { |
tmp = RREG32(voltage->gpio.reg); |
if (voltage->active_high) |
tmp |= voltage->gpio.mask; |
else |
tmp &= ~(voltage->gpio.mask); |
WREG32(voltage->gpio.reg, tmp); |
if (voltage->delay) |
udelay(voltage->delay); |
} else { |
tmp = RREG32(voltage->gpio.reg); |
if (voltage->active_high) |
tmp &= ~voltage->gpio.mask; |
else |
tmp |= voltage->gpio.mask; |
WREG32(voltage->gpio.reg, tmp); |
if (voltage->delay) |
udelay(voltage->delay); |
} |
} |
sclk_cntl = RREG32_PLL(SCLK_CNTL); |
sclk_cntl2 = RREG32_PLL(SCLK_CNTL2); |
sclk_cntl2 &= ~REDUCED_SPEED_SCLK_SEL(3); |
sclk_more_cntl = RREG32_PLL(SCLK_MORE_CNTL); |
sclk_more_cntl &= ~VOLTAGE_DELAY_SEL(3); |
if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) { |
sclk_more_cntl |= REDUCED_SPEED_SCLK_EN; |
if (ps->misc & ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE) |
sclk_cntl2 |= REDUCED_SPEED_SCLK_MODE; |
else |
sclk_cntl2 &= ~REDUCED_SPEED_SCLK_MODE; |
if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) |
sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(0); |
else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) |
sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(2); |
} else |
sclk_more_cntl &= ~REDUCED_SPEED_SCLK_EN; |
if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) { |
sclk_more_cntl |= IO_CG_VOLTAGE_DROP; |
if (voltage->delay) { |
sclk_more_cntl |= VOLTAGE_DROP_SYNC; |
switch (voltage->delay) { |
case 33: |
sclk_more_cntl |= VOLTAGE_DELAY_SEL(0); |
break; |
case 66: |
sclk_more_cntl |= VOLTAGE_DELAY_SEL(1); |
break; |
case 99: |
sclk_more_cntl |= VOLTAGE_DELAY_SEL(2); |
break; |
case 132: |
sclk_more_cntl |= VOLTAGE_DELAY_SEL(3); |
break; |
} |
} else |
sclk_more_cntl &= ~VOLTAGE_DROP_SYNC; |
} else |
sclk_more_cntl &= ~IO_CG_VOLTAGE_DROP; |
if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN) |
sclk_cntl &= ~FORCE_HDP; |
else |
sclk_cntl |= FORCE_HDP; |
WREG32_PLL(SCLK_CNTL, sclk_cntl); |
WREG32_PLL(SCLK_CNTL2, sclk_cntl2); |
WREG32_PLL(SCLK_MORE_CNTL, sclk_more_cntl); |
/* set pcie lanes */ |
if ((rdev->flags & RADEON_IS_PCIE) && |
!(rdev->flags & RADEON_IS_IGP) && |
rdev->asic->pm.set_pcie_lanes && |
(ps->pcie_lanes != |
rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { |
radeon_set_pcie_lanes(rdev, |
ps->pcie_lanes); |
DRM_DEBUG_DRIVER("Setting: p: %d\n", ps->pcie_lanes); |
} |
} |
/** |
* r100_pm_prepare - pre-power state change callback. |
* |
* @rdev: radeon_device pointer |
* |
* Prepare for a power state change (r1xx-r4xx). |
*/ |
void r100_pm_prepare(struct radeon_device *rdev) |
{ |
struct drm_device *ddev = rdev->ddev; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
u32 tmp; |
/* disable any active CRTCs */ |
list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { |
radeon_crtc = to_radeon_crtc(crtc); |
if (radeon_crtc->enabled) { |
if (radeon_crtc->crtc_id) { |
tmp = RREG32(RADEON_CRTC2_GEN_CNTL); |
tmp |= RADEON_CRTC2_DISP_REQ_EN_B; |
WREG32(RADEON_CRTC2_GEN_CNTL, tmp); |
} else { |
tmp = RREG32(RADEON_CRTC_GEN_CNTL); |
tmp |= RADEON_CRTC_DISP_REQ_EN_B; |
WREG32(RADEON_CRTC_GEN_CNTL, tmp); |
} |
} |
} |
} |
/** |
* r100_pm_finish - post-power state change callback. |
* |
* @rdev: radeon_device pointer |
* |
* Clean up after a power state change (r1xx-r4xx). |
*/ |
void r100_pm_finish(struct radeon_device *rdev) |
{ |
struct drm_device *ddev = rdev->ddev; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
u32 tmp; |
/* enable any active CRTCs */ |
list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { |
radeon_crtc = to_radeon_crtc(crtc); |
if (radeon_crtc->enabled) { |
if (radeon_crtc->crtc_id) { |
tmp = RREG32(RADEON_CRTC2_GEN_CNTL); |
tmp &= ~RADEON_CRTC2_DISP_REQ_EN_B; |
WREG32(RADEON_CRTC2_GEN_CNTL, tmp); |
} else { |
tmp = RREG32(RADEON_CRTC_GEN_CNTL); |
tmp &= ~RADEON_CRTC_DISP_REQ_EN_B; |
WREG32(RADEON_CRTC_GEN_CNTL, tmp); |
} |
} |
} |
} |
/** |
* r100_gui_idle - gui idle callback. |
* |
* @rdev: radeon_device pointer |
* |
* Check of the GUI (2D/3D engines) are idle (r1xx-r5xx). |
* Returns true if idle, false if not. |
*/ |
bool r100_gui_idle(struct radeon_device *rdev) |
{ |
if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) |
313,7 → 652,6 |
{ |
uint32_t tmp; |
radeon_gart_restore(rdev); |
/* discard memory request outside of configured range */ |
tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; |
WREG32(RADEON_AIC_CNTL, tmp); |
343,15 → 681,11 |
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, uint32_t flags) |
{ |
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) |
503,11 → 837,7 |
/* Wait until IDLE & CLEAN */ |
radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); |
radeon_ring_write(ring, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN); |
radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); |
radeon_ring_write(ring, rdev->config.r100.hdp_cntl | |
RADEON_HDP_READ_BUFFER_INVALIDATE); |
radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); |
radeon_ring_write(ring, rdev->config.r100.hdp_cntl); |
r100_ring_hdp_flush(rdev, ring); |
/* Emit fence sequence & fire IRQ */ |
radeon_ring_write(ring, PACKET0(rdev->fence_drv[fence->ring].scratch_reg, 0)); |
radeon_ring_write(ring, fence->seq); |
515,7 → 845,7 |
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) |
522,6 → 852,7 |
{ |
/* Unused on older asics, since we don't have semaphores or multiple rings */ |
BUG(); |
return false; |
} |
int r100_copy_blit(struct radeon_device *rdev, |
594,7 → 925,7 |
if (fence) { |
r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); |
} |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
return r; |
} |
627,7 → 958,7 |
RADEON_ISYNC_ANY3D_IDLE2D | |
RADEON_ISYNC_WAIT_IDLEGUI | |
RADEON_ISYNC_CPSCRATCH_IDLEGUI); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
} |
634,18 → 965,11 |
/* Load the microcode for the CP */ |
static int r100_cp_init_microcode(struct radeon_device *rdev) |
{ |
struct platform_device *pdev; |
const char *fw_name = NULL; |
int err; |
DRM_DEBUG_KMS("\n"); |
pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); |
err = IS_ERR(pdev); |
if (err) { |
printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); |
return -EINVAL; |
} |
if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || |
(rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || |
(rdev->family == CHIP_RS200)) { |
687,8 → 1011,7 |
fw_name = FIRMWARE_R520; |
} |
err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); |
platform_device_unregister(pdev); |
err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); |
if (err) { |
printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n", |
fw_name); |
703,6 → 1026,50 |
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); |
} |
/** |
* r100_ring_hdp_flush - flush Host Data Path via the ring buffer |
* rdev: radeon device structure |
* ring: ring buffer struct for emitting packets |
*/ |
void r100_ring_hdp_flush(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); |
radeon_ring_write(ring, rdev->config.r100.hdp_cntl | |
RADEON_HDP_READ_BUFFER_INVALIDATE); |
radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); |
radeon_ring_write(ring, rdev->config.r100.hdp_cntl); |
} |
static void r100_cp_load_microcode(struct radeon_device *rdev) |
{ |
const __be32 *fw_data; |
751,12 → 1118,11 |
} |
/* Align ring size */ |
rb_bufsz = drm_order(ring_size / 8); |
rb_bufsz = order_base_2(ring_size / 8); |
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, |
0, 0x7fffff, RADEON_CP_PACKET2); |
RADEON_CP_PACKET2); |
if (r) { |
return r; |
} |
817,7 → 1183,6 |
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) | |
871,7 → 1236,6 |
} |
} |
#if 0 |
/* |
* CS functions |
*/ |
896,12 → 1260,12 |
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); |
947,7 → 1311,7 |
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; |
959,7 → 1323,7 |
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; |
973,7 → 1337,7 |
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; |
1026,68 → 1390,7 |
return 0; |
} |
void r100_cs_dump_packet(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt) |
{ |
volatile uint32_t *ib; |
unsigned i; |
unsigned idx; |
ib = p->ib.ptr; |
idx = pkt->idx; |
for (i = 0; i <= (pkt->count + 1); i++, idx++) { |
DRM_INFO("ib[%d]=0x%08X\n", idx, ib[idx]); |
} |
} |
/** |
* r100_cs_packet_parse() - parse cp packet and point ib index to next packet |
* @parser: parser structure holding parsing context. |
* @pkt: where to store packet informations |
* |
* Assume that chunk_ib_index is properly set. Will return -EINVAL |
* if packet is bigger than remaining ib size. or if packets is unknown. |
**/ |
int r100_cs_packet_parse(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
unsigned idx) |
{ |
struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; |
uint32_t header; |
if (idx >= ib_chunk->length_dw) { |
DRM_ERROR("Can not parse packet at %d after CS end %d !\n", |
idx, ib_chunk->length_dw); |
return -EINVAL; |
} |
header = radeon_get_ib_value(p, idx); |
pkt->idx = idx; |
pkt->type = CP_PACKET_GET_TYPE(header); |
pkt->count = CP_PACKET_GET_COUNT(header); |
switch (pkt->type) { |
case PACKET_TYPE0: |
pkt->reg = CP_PACKET0_GET_REG(header); |
pkt->one_reg_wr = CP_PACKET0_GET_ONE_REG_WR(header); |
break; |
case PACKET_TYPE3: |
pkt->opcode = CP_PACKET3_GET_OPCODE(header); |
break; |
case PACKET_TYPE2: |
pkt->count = -1; |
break; |
default: |
DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx); |
return -EINVAL; |
} |
if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) { |
DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n", |
pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); |
return -EINVAL; |
} |
return 0; |
} |
/** |
* r100_cs_packet_next_vline() - parse userspace VLINE packet |
* @parser: parser structure holding parsing context. |
* |
1103,7 → 1406,6 |
*/ |
int r100_cs_packet_parse_vline(struct radeon_cs_parser *p) |
{ |
struct drm_mode_object *obj; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
struct radeon_cs_packet p3reloc, waitreloc; |
1143,12 → 1445,11 |
header = radeon_get_ib_value(p, h_idx); |
crtc_id = radeon_get_ib_value(p, h_idx + 5); |
reg = R100_CP_PACKET0_GET_REG(header); |
obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); |
if (!obj) { |
crtc = drm_crtc_find(p->rdev->ddev, crtc_id); |
if (!crtc) { |
DRM_ERROR("cannot find crtc %d\n", crtc_id); |
return -EINVAL; |
return -ENOENT; |
} |
crtc = obj_to_crtc(obj); |
radeon_crtc = to_radeon_crtc(crtc); |
crtc_id = radeon_crtc->crtc_id; |
1277,7 → 1578,7 |
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); |
1290,7 → 1591,7 |
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: |
1304,16 → 1605,16 |
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; |
1331,7 → 1632,7 |
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; |
1349,7 → 1650,7 |
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; |
1367,7 → 1668,7 |
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; |
1385,9 → 1686,9 |
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); |
1455,7 → 1756,7 |
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: |
{ |
1615,7 → 1916,7 |
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; |
1629,7 → 1930,7 |
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)); |
2130,7 → 2431,6 |
} |
} |
} |
#endif |
/* |
* Global GPU functions |
2206,11 → 2506,9 |
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); |
} |
2566,21 → 2864,28 |
uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg) |
{ |
unsigned long flags; |
uint32_t data; |
spin_lock_irqsave(&rdev->pll_idx_lock, flags); |
WREG8(RADEON_CLOCK_CNTL_INDEX, reg & 0x3f); |
r100_pll_errata_after_index(rdev); |
data = RREG32(RADEON_CLOCK_CNTL_DATA); |
r100_pll_errata_after_data(rdev); |
spin_unlock_irqrestore(&rdev->pll_idx_lock, flags); |
return data; |
} |
void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->pll_idx_lock, flags); |
WREG8(RADEON_CLOCK_CNTL_INDEX, ((reg & 0x3f) | RADEON_PLL_WR_EN)); |
r100_pll_errata_after_index(rdev); |
WREG32(RADEON_CLOCK_CNTL_DATA, v); |
r100_pll_errata_after_data(rdev); |
spin_unlock_irqrestore(&rdev->pll_idx_lock, flags); |
} |
static void r100_set_safe_registers(struct radeon_device *rdev) |
2639,10 → 2944,12 |
seq_printf(m, "CP_RB_RPTR 0x%08x\n", rdp); |
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) { |
for (j = 0; j <= count; j++) { |
i = (rdp + j) & ring->ptr_mask; |
seq_printf(m, "r[%04d]=0x%08x\n", i, ring->ring[i]); |
} |
} |
return 0; |
} |
2781,6 → 3088,10 |
flags |= RADEON_SURF_TILE_COLOR_BOTH; |
if (tiling_flags & RADEON_TILING_MACRO) |
flags |= RADEON_SURF_TILE_COLOR_MACRO; |
/* setting pitch to 0 disables tiling */ |
if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) |
== 0) |
pitch = 0; |
} else if (rdev->family <= CHIP_RV280) { |
if (tiling_flags & (RADEON_TILING_MACRO)) |
flags |= R200_SURF_TILE_COLOR_MACRO; |
2798,13 → 3109,6 |
if (tiling_flags & RADEON_TILING_SWAP_32BIT) |
flags |= RADEON_SURF_AP0_SWP_32BPP | RADEON_SURF_AP1_SWP_32BPP; |
/* when we aren't tiling the pitch seems to needs to be furtherdivided down. - tested on power5 + rn50 server */ |
if (tiling_flags & (RADEON_TILING_SWAP_16BIT | RADEON_TILING_SWAP_32BIT)) { |
if (!(tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) |
if (ASIC_IS_RN50(rdev)) |
pitch /= 16; |
} |
/* r100/r200 divide by 16 */ |
if (rdev->family < CHIP_R300) |
flags |= pitch / 16; |
2900,12 → 3204,12 |
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; |
} |
} |
3330,7 → 3634,7 |
} |
radeon_ring_write(ring, PACKET0(scratch, 0)); |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(scratch); |
if (tmp == 0xDEADBEEF) { |
3392,7 → 3696,7 |
ib.ptr[6] = PACKET2(0); |
ib.ptr[7] = PACKET2(0); |
ib.length_dw = 8; |
r = radeon_ib_schedule(rdev, &ib, NULL); |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
if (r) { |
DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); |
goto free_ib; |
3688,6 → 3992,9 |
} |
r100_set_safe_registers(rdev); |
/* Initialize power management */ |
radeon_pm_init(rdev); |
rdev->accel_working = true; |
r = r100_startup(rdev); |
if (r) { |
3700,39 → 4007,6 |
return 0; |
} |
uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, |
bool always_indirect) |
{ |
if (reg < rdev->rmmio_size && !always_indirect) |
return readl(((void __iomem *)rdev->rmmio) + reg); |
else { |
unsigned long flags; |
uint32_t ret; |
spin_lock_irqsave(&rdev->mmio_idx_lock, flags); |
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); |
ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); |
spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); |
return ret; |
} |
} |
void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, |
bool always_indirect) |
{ |
if (reg < rdev->rmmio_size && !always_indirect) |
writel(v, ((void __iomem *)rdev->rmmio) + reg); |
else { |
unsigned long flags; |
spin_lock_irqsave(&rdev->mmio_idx_lock, flags); |
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); |
writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); |
spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); |
} |
} |
u32 r100_io_rreg(struct radeon_device *rdev, u32 reg) |
{ |
if (reg < rdev->rio_mem_size) |
/drivers/video/drm/radeon/r100_track.h |
---|
0,0 → 1,97 |
#define R100_TRACK_MAX_TEXTURE 3 |
#define R200_TRACK_MAX_TEXTURE 6 |
#define R300_TRACK_MAX_TEXTURE 16 |
#define R100_MAX_CB 1 |
#define R300_MAX_CB 4 |
/* |
* CS functions |
*/ |
struct r100_cs_track_cb { |
struct radeon_bo *robj; |
unsigned pitch; |
unsigned cpp; |
unsigned offset; |
}; |
struct r100_cs_track_array { |
struct radeon_bo *robj; |
unsigned esize; |
}; |
struct r100_cs_cube_info { |
struct radeon_bo *robj; |
unsigned offset; |
unsigned width; |
unsigned height; |
}; |
#define R100_TRACK_COMP_NONE 0 |
#define R100_TRACK_COMP_DXT1 1 |
#define R100_TRACK_COMP_DXT35 2 |
struct r100_cs_track_texture { |
struct radeon_bo *robj; |
struct r100_cs_cube_info cube_info[5]; /* info for 5 non-primary faces */ |
unsigned pitch; |
unsigned width; |
unsigned height; |
unsigned num_levels; |
unsigned cpp; |
unsigned tex_coord_type; |
unsigned txdepth; |
unsigned width_11; |
unsigned height_11; |
bool use_pitch; |
bool enabled; |
bool lookup_disable; |
bool roundup_w; |
bool roundup_h; |
unsigned compress_format; |
}; |
struct r100_cs_track { |
unsigned num_cb; |
unsigned num_texture; |
unsigned maxy; |
unsigned vtx_size; |
unsigned vap_vf_cntl; |
unsigned vap_alt_nverts; |
unsigned immd_dwords; |
unsigned num_arrays; |
unsigned max_indx; |
unsigned color_channel_mask; |
struct r100_cs_track_array arrays[16]; |
struct r100_cs_track_cb cb[R300_MAX_CB]; |
struct r100_cs_track_cb zb; |
struct r100_cs_track_cb aa; |
struct r100_cs_track_texture textures[R300_TRACK_MAX_TEXTURE]; |
bool z_enabled; |
bool separate_cube; |
bool zb_cb_clear; |
bool blend_read_enable; |
bool cb_dirty; |
bool zb_dirty; |
bool tex_dirty; |
bool aa_dirty; |
bool aaresolve; |
}; |
int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track); |
void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track); |
int r100_cs_packet_parse_vline(struct radeon_cs_parser *p); |
int r200_packet0_check(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
unsigned idx, unsigned reg); |
int r100_reloc_pitch_offset(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
unsigned idx, |
unsigned reg); |
int r100_packet3_load_vbpntr(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
int idx); |
/drivers/video/drm/radeon/r200.c |
---|
34,8 → 34,6 |
#include "r100d.h" |
#include "r200_reg_safe.h" |
#if 0 |
#include "r100_track.h" |
static int r200_get_vtx_size_0(uint32_t vtx_fmt_0) |
81,7 → 79,6 |
vtx_size += 3; |
return vtx_size; |
} |
#endif |
int r200_copy_dma(struct radeon_device *rdev, |
uint64_t src_offset, |
124,11 → 121,11 |
if (fence) { |
r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); |
} |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
return r; |
} |
#if 0 |
static int r200_get_vtx_size_1(uint32_t vtx_fmt_1) |
{ |
int vtx_size, i, tex_size; |
188,7 → 185,7 |
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); |
201,7 → 198,7 |
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: |
218,16 → 215,16 |
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; |
271,7 → 268,7 |
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; |
290,9 → 287,9 |
} |
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); |
365,7 → 362,7 |
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: |
{ |
543,7 → 540,6 |
} |
return 0; |
} |
#endif |
void r200_set_safe_registers(struct radeon_device *rdev) |
{ |
/drivers/video/drm/radeon/r200_reg_safe.h |
---|
16,7 → 16,7 |
0xFFE7FE1F, 0xF003FFFF, 0x7EFFFFFF, 0xFFFF803C, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFEFCE, 0xFFFEFFFF, 0xFFFFFFFE, |
0x020E0FF0, 0xFFFC83FD, 0xFFFFFFFF, 0xFFFFFFFF, |
0x020E0FF0, 0xFFCC83FD, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFBFFFF, 0xEFFCFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
/drivers/video/drm/radeon/r300.c |
---|
34,7 → 34,7 |
#include "radeon.h" |
#include "radeon_asic.h" |
#include <drm/radeon_drm.h> |
#include "r100_track.h" |
#include "r300d.h" |
#include "rv350d.h" |
#include "r300_reg_safe.h" |
69,24 → 69,27 |
mb(); |
} |
#define R300_PTE_UNSNOOPED (1 << 0) |
#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, uint32_t flags) |
{ |
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; |
((upper_32_bits(addr) & 0xff) << 24); |
if (flags & RADEON_GART_PAGE_READ) |
addr |= R300_PTE_READABLE; |
if (flags & RADEON_GART_PAGE_WRITE) |
addr |= R300_PTE_WRITEABLE; |
if (!(flags & RADEON_GART_PAGE_SNOOP)) |
addr |= R300_PTE_UNSNOOPED; |
/* on x86 we want this to be CPU endian, on powerpc |
* on powerpc without HW swappers, it'll get swapped on way |
* into VRAM - so no need for cpu_to_le32 on VRAM tables */ |
writel(addr, ((void __iomem *)ptr) + (i * 4)); |
return 0; |
} |
int rv370_pcie_gart_init(struct radeon_device *rdev) |
123,7 → 126,6 |
r = radeon_gart_table_vram_pin(rdev); |
if (r) |
return r; |
radeon_gart_restore(rdev); |
/* discard memory request outside of configured range */ |
tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; |
WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); |
293,7 → 295,7 |
radeon_ring_write(ring, |
R300_GEOMETRY_ROUND_NEAREST | |
R300_COLOR_ROUND_NEAREST); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
} |
static void r300_errata(struct radeon_device *rdev) |
592,9 → 594,6 |
#endif |
} |
#if 0 |
static int r300_packet0_check(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
unsigned idx, unsigned reg) |
643,7 → 642,7 |
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); |
656,7 → 655,7 |
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: |
685,16 → 684,16 |
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; |
} |
756,11 → 755,11 |
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); |
841,11 → 840,11 |
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); |
1055,7 → 1054,7 |
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 */ |
1100,7 → 1099,7 |
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; |
1165,7 → 1164,7 |
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; |
1287,9 → 1286,7 |
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); |
return 0; |
} |
#endif |
void r300_set_reg_safe(struct radeon_device *rdev) |
{ |
rdev->config.r300.reg_safe_bm = r300_reg_safe_bm; |
1484,10 → 1481,13 |
} |
r300_set_reg_safe(rdev); |
/* Initialize power management */ |
radeon_pm_init(rdev); |
rdev->accel_working = true; |
r = r300_startup(rdev); |
if (r) { |
/* Somethings want wront with the accel init stop accel */ |
/* Something went wrong with the accel init, so stop accel */ |
dev_err(rdev->dev, "Disabling GPU acceleration\n"); |
if (rdev->flags & RADEON_IS_PCIE) |
rv370_pcie_gart_fini(rdev); |
/drivers/video/drm/radeon/r300_reg_safe.h |
---|
31,12 → 31,12 |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, |
0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE009FF, |
0xFFFFFC48, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, |
0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE00BFF, |
0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, |
0x00000000, 0x0000C100, 0x00000000, 0x00000000, |
0x00000000, 0x00000000, 0x00000000, 0x00000000, |
0x00000000, 0xFFFF0000, 0xFFFFFFFF, 0xFF80FFFF, |
0x00000000, 0x00000000, 0x00000000, 0x00000000, |
0x0003FC01, 0xFFFFFCF8, 0xFF800B19, |
0x0003FC0B, 0xFFFFFCFF, 0xFFBFFB99, |
}; |
/drivers/video/drm/radeon/r420.c |
---|
160,18 → 160,25 |
u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(R_0001F8_MC_IND_INDEX, S_0001F8_MC_IND_ADDR(reg)); |
r = RREG32(R_0001FC_MC_IND_DATA); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
return r; |
} |
void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(R_0001F8_MC_IND_INDEX, S_0001F8_MC_IND_ADDR(reg) | |
S_0001F8_MC_IND_WR_EN(1)); |
WREG32(R_0001FC_MC_IND_DATA, v); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
} |
static void r420_debugfs(struct radeon_device *rdev) |
212,7 → 219,7 |
radeon_ring_write(ring, PACKET0(R300_CP_RESYNC_ADDR, 1)); |
radeon_ring_write(ring, rdev->config.r300.resync_scratch); |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
} |
static void r420_cp_errata_fini(struct radeon_device *rdev) |
225,7 → 232,7 |
radeon_ring_lock(rdev, ring, 8); |
radeon_ring_write(ring, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); |
radeon_ring_write(ring, R300_RB3D_DC_FINISH); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
radeon_scratch_free(rdev, rdev->config.r300.resync_scratch); |
} |
370,6 → 377,9 |
} |
r420_set_reg_safe(rdev); |
/* Initialize power management */ |
radeon_pm_init(rdev); |
rdev->accel_working = true; |
r = r420_startup(rdev); |
if (r) { |
/drivers/video/drm/radeon/r420_reg_safe.h |
---|
31,12 → 31,12 |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, |
0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE009FF, |
0xFFFFFC48, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, |
0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE00BFF, |
0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, |
0x00000000, 0x00000100, 0x00000000, 0x00000000, |
0x00000000, 0x00000000, 0x00000000, 0x00000000, |
0x00000000, 0x00000000, 0x00000000, 0xFF800000, |
0x00000000, 0x00000000, 0x00000000, 0x00000000, |
0x0003FC01, 0xFFFFFCF8, 0xFF800B19, |
0x0003FC0B, 0xFFFFFCFF, 0xFFBFFB99, |
}; |
/drivers/video/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 |
/drivers/video/drm/radeon/r520.c |
---|
284,6 → 284,9 |
return r; |
rv515_set_safe_registers(rdev); |
/* Initialize power management */ |
radeon_pm_init(rdev); |
rdev->accel_working = true; |
r = r520_startup(rdev); |
if (r) { |
/drivers/video/drm/radeon/r600.c |
---|
37,19 → 37,8 |
#include "r600d.h" |
#include "atom.h" |
#include "avivod.h" |
#include "radeon_ucode.h" |
#define PFP_UCODE_SIZE 576 |
#define PM4_UCODE_SIZE 1792 |
#define RLC_UCODE_SIZE 768 |
#define R700_PFP_UCODE_SIZE 848 |
#define R700_PM4_UCODE_SIZE 1360 |
#define R700_RLC_UCODE_SIZE 1024 |
#define EVERGREEN_PFP_UCODE_SIZE 1120 |
#define EVERGREEN_PM4_UCODE_SIZE 1376 |
#define EVERGREEN_RLC_UCODE_SIZE 768 |
#define CAYMAN_RLC_UCODE_SIZE 1024 |
#define ARUBA_RLC_UCODE_SIZE 1536 |
/* Firmware Names */ |
MODULE_FIRMWARE("radeon/R600_pfp.bin"); |
MODULE_FIRMWARE("radeon/R600_me.bin"); |
67,24 → 56,32 |
MODULE_FIRMWARE("radeon/RS780_me.bin"); |
MODULE_FIRMWARE("radeon/RV770_pfp.bin"); |
MODULE_FIRMWARE("radeon/RV770_me.bin"); |
MODULE_FIRMWARE("radeon/RV770_smc.bin"); |
MODULE_FIRMWARE("radeon/RV730_pfp.bin"); |
MODULE_FIRMWARE("radeon/RV730_me.bin"); |
MODULE_FIRMWARE("radeon/RV730_smc.bin"); |
MODULE_FIRMWARE("radeon/RV740_smc.bin"); |
MODULE_FIRMWARE("radeon/RV710_pfp.bin"); |
MODULE_FIRMWARE("radeon/RV710_me.bin"); |
MODULE_FIRMWARE("radeon/RV710_smc.bin"); |
MODULE_FIRMWARE("radeon/R600_rlc.bin"); |
MODULE_FIRMWARE("radeon/R700_rlc.bin"); |
MODULE_FIRMWARE("radeon/CEDAR_pfp.bin"); |
MODULE_FIRMWARE("radeon/CEDAR_me.bin"); |
MODULE_FIRMWARE("radeon/CEDAR_rlc.bin"); |
MODULE_FIRMWARE("radeon/CEDAR_smc.bin"); |
MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin"); |
MODULE_FIRMWARE("radeon/REDWOOD_me.bin"); |
MODULE_FIRMWARE("radeon/REDWOOD_rlc.bin"); |
MODULE_FIRMWARE("radeon/REDWOOD_smc.bin"); |
MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin"); |
MODULE_FIRMWARE("radeon/JUNIPER_me.bin"); |
MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin"); |
MODULE_FIRMWARE("radeon/JUNIPER_smc.bin"); |
MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin"); |
MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); |
MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin"); |
MODULE_FIRMWARE("radeon/CYPRESS_smc.bin"); |
MODULE_FIRMWARE("radeon/PALM_pfp.bin"); |
MODULE_FIRMWARE("radeon/PALM_me.bin"); |
MODULE_FIRMWARE("radeon/SUMO_rlc.bin"); |
107,6 → 104,8 |
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 |
121,6 → 120,64 |
return rdev->clock.spll.reference_freq; |
} |
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) |
{ |
134,11 → 191,439 |
return actual_temp * 1000; |
} |
void r600_pm_get_dynpm_state(struct radeon_device *rdev) |
{ |
int i; |
rdev->pm.dynpm_can_upclock = true; |
rdev->pm.dynpm_can_downclock = true; |
/* power state array is low to high, default is first */ |
if ((rdev->flags & RADEON_IS_IGP) || (rdev->family == CHIP_R600)) { |
int min_power_state_index = 0; |
if (rdev->pm.num_power_states > 2) |
min_power_state_index = 1; |
switch (rdev->pm.dynpm_planned_action) { |
case DYNPM_ACTION_MINIMUM: |
rdev->pm.requested_power_state_index = min_power_state_index; |
rdev->pm.requested_clock_mode_index = 0; |
rdev->pm.dynpm_can_downclock = false; |
break; |
case DYNPM_ACTION_DOWNCLOCK: |
if (rdev->pm.current_power_state_index == min_power_state_index) { |
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; |
rdev->pm.dynpm_can_downclock = false; |
} else { |
if (rdev->pm.active_crtc_count > 1) { |
for (i = 0; i < rdev->pm.num_power_states; i++) { |
if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) |
continue; |
else if (i >= rdev->pm.current_power_state_index) { |
rdev->pm.requested_power_state_index = |
rdev->pm.current_power_state_index; |
break; |
} else { |
rdev->pm.requested_power_state_index = i; |
break; |
} |
} |
} else { |
if (rdev->pm.current_power_state_index == 0) |
rdev->pm.requested_power_state_index = |
rdev->pm.num_power_states - 1; |
else |
rdev->pm.requested_power_state_index = |
rdev->pm.current_power_state_index - 1; |
} |
} |
rdev->pm.requested_clock_mode_index = 0; |
/* don't use the power state if crtcs are active and no display flag is set */ |
if ((rdev->pm.active_crtc_count > 0) && |
(rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
clock_info[rdev->pm.requested_clock_mode_index].flags & |
RADEON_PM_MODE_NO_DISPLAY)) { |
rdev->pm.requested_power_state_index++; |
} |
break; |
case DYNPM_ACTION_UPCLOCK: |
if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { |
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; |
rdev->pm.dynpm_can_upclock = false; |
} else { |
if (rdev->pm.active_crtc_count > 1) { |
for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { |
if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) |
continue; |
else if (i <= rdev->pm.current_power_state_index) { |
rdev->pm.requested_power_state_index = |
rdev->pm.current_power_state_index; |
break; |
} else { |
rdev->pm.requested_power_state_index = i; |
break; |
} |
} |
} else |
rdev->pm.requested_power_state_index = |
rdev->pm.current_power_state_index + 1; |
} |
rdev->pm.requested_clock_mode_index = 0; |
break; |
case DYNPM_ACTION_DEFAULT: |
rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; |
rdev->pm.requested_clock_mode_index = 0; |
rdev->pm.dynpm_can_upclock = false; |
break; |
case DYNPM_ACTION_NONE: |
default: |
DRM_ERROR("Requested mode for not defined action\n"); |
return; |
} |
} else { |
/* XXX select a power state based on AC/DC, single/dualhead, etc. */ |
/* for now just select the first power state and switch between clock modes */ |
/* power state array is low to high, default is first (0) */ |
if (rdev->pm.active_crtc_count > 1) { |
rdev->pm.requested_power_state_index = -1; |
/* start at 1 as we don't want the default mode */ |
for (i = 1; i < rdev->pm.num_power_states; i++) { |
if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) |
continue; |
else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) || |
(rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) { |
rdev->pm.requested_power_state_index = i; |
break; |
} |
} |
/* if nothing selected, grab the default state. */ |
if (rdev->pm.requested_power_state_index == -1) |
rdev->pm.requested_power_state_index = 0; |
} else |
rdev->pm.requested_power_state_index = 1; |
switch (rdev->pm.dynpm_planned_action) { |
case DYNPM_ACTION_MINIMUM: |
rdev->pm.requested_clock_mode_index = 0; |
rdev->pm.dynpm_can_downclock = false; |
break; |
case DYNPM_ACTION_DOWNCLOCK: |
if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { |
if (rdev->pm.current_clock_mode_index == 0) { |
rdev->pm.requested_clock_mode_index = 0; |
rdev->pm.dynpm_can_downclock = false; |
} else |
rdev->pm.requested_clock_mode_index = |
rdev->pm.current_clock_mode_index - 1; |
} else { |
rdev->pm.requested_clock_mode_index = 0; |
rdev->pm.dynpm_can_downclock = false; |
} |
/* don't use the power state if crtcs are active and no display flag is set */ |
if ((rdev->pm.active_crtc_count > 0) && |
(rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
clock_info[rdev->pm.requested_clock_mode_index].flags & |
RADEON_PM_MODE_NO_DISPLAY)) { |
rdev->pm.requested_clock_mode_index++; |
} |
break; |
case DYNPM_ACTION_UPCLOCK: |
if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { |
if (rdev->pm.current_clock_mode_index == |
(rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1)) { |
rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index; |
rdev->pm.dynpm_can_upclock = false; |
} else |
rdev->pm.requested_clock_mode_index = |
rdev->pm.current_clock_mode_index + 1; |
} else { |
rdev->pm.requested_clock_mode_index = |
rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1; |
rdev->pm.dynpm_can_upclock = false; |
} |
break; |
case DYNPM_ACTION_DEFAULT: |
rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; |
rdev->pm.requested_clock_mode_index = 0; |
rdev->pm.dynpm_can_upclock = false; |
break; |
case DYNPM_ACTION_NONE: |
default: |
DRM_ERROR("Requested mode for not defined action\n"); |
return; |
} |
} |
DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n", |
rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
clock_info[rdev->pm.requested_clock_mode_index].sclk, |
rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
clock_info[rdev->pm.requested_clock_mode_index].mclk, |
rdev->pm.power_state[rdev->pm.requested_power_state_index]. |
pcie_lanes); |
} |
void rs780_pm_init_profile(struct radeon_device *rdev) |
{ |
if (rdev->pm.num_power_states == 2) { |
/* default */ |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; |
/* low sh */ |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; |
/* mid sh */ |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; |
/* high sh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; |
/* low mh */ |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; |
/* mid mh */ |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; |
/* high mh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; |
} else if (rdev->pm.num_power_states == 3) { |
/* default */ |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; |
/* low sh */ |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; |
/* mid sh */ |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; |
/* high sh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; |
/* low mh */ |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; |
/* mid mh */ |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; |
/* high mh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; |
} else { |
/* default */ |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; |
/* low sh */ |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; |
/* mid sh */ |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; |
/* high sh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 3; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; |
/* low mh */ |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; |
/* mid mh */ |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; |
/* high mh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; |
} |
} |
void r600_pm_init_profile(struct radeon_device *rdev) |
{ |
int idx; |
if (rdev->family == CHIP_R600) { |
/* XXX */ |
/* default */ |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; |
/* low sh */ |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; |
/* mid sh */ |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; |
/* high sh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; |
/* low mh */ |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; |
/* mid mh */ |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; |
/* high mh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; |
} else { |
if (rdev->pm.num_power_states < 4) { |
/* default */ |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; |
/* low sh */ |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; |
/* mid sh */ |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; |
/* high sh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; |
/* low mh */ |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; |
/* low mh */ |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; |
/* high mh */ |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; |
} else { |
/* default */ |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; |
/* low sh */ |
if (rdev->flags & RADEON_IS_MOBILITY) |
idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); |
else |
idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; |
/* mid sh */ |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; |
/* high sh */ |
idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; |
/* low mh */ |
if (rdev->flags & RADEON_IS_MOBILITY) |
idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); |
else |
idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; |
/* mid mh */ |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; |
/* high mh */ |
idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = idx; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; |
rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; |
} |
} |
} |
void r600_pm_misc(struct radeon_device *rdev) |
{ |
int req_ps_idx = rdev->pm.requested_power_state_index; |
int req_cm_idx = rdev->pm.requested_clock_mode_index; |
struct radeon_power_state *ps = &rdev->pm.power_state[req_ps_idx]; |
struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; |
if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { |
/* 0xff01 is a flag rather then an actual voltage */ |
if (voltage->voltage == 0xff01) |
return; |
if (voltage->voltage != rdev->pm.current_vddc) { |
radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); |
rdev->pm.current_vddc = voltage->voltage; |
DRM_DEBUG_DRIVER("Setting: v: %d\n", voltage->voltage); |
} |
} |
} |
bool r600_gui_idle(struct radeon_device *rdev) |
{ |
if (RREG32(GRBM_STATUS) & GUI_ACTIVE) |
483,7 → 968,6 |
r = radeon_gart_table_vram_pin(rdev); |
if (r) |
return r; |
radeon_gart_restore(rdev); |
/* Setup L2 cache */ |
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | |
619,20 → 1103,27 |
uint32_t rs780_mc_rreg(struct radeon_device *rdev, uint32_t reg) |
{ |
unsigned long flags; |
uint32_t r; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg)); |
r = RREG32(R_0028FC_MC_DATA); |
WREG32(R_0028F8_MC_INDEX, ~C_0028F8_MC_IND_ADDR); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
return r; |
} |
void rs780_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg) | |
S_0028F8_MC_IND_WR_EN(1)); |
WREG32(R_0028FC_MC_DATA, v); |
WREG32(R_0028F8_MC_INDEX, 0x7F); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
} |
static void r600_mc_program(struct radeon_device *rdev) |
847,7 → 1338,7 |
if (rdev->vram_scratch.robj == NULL) { |
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, |
PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, |
NULL, &rdev->vram_scratch.robj); |
0, NULL, &rdev->vram_scratch.robj); |
if (r) { |
return r; |
} |
948,7 → 1439,7 |
return true; |
} |
static u32 r600_gpu_check_soft_reset(struct radeon_device *rdev) |
u32 r600_gpu_check_soft_reset(struct radeon_device *rdev) |
{ |
u32 reset_mask = 0; |
u32 tmp; |
1153,6 → 1644,67 |
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; |
1162,10 → 1714,17 |
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); |
1188,36 → 1747,12 |
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); |
} |
/** |
* r600_dma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up. |
* Returns true if the engine appears to be locked up, false if not. |
*/ |
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); |
return false; |
} |
/* force ring activities */ |
radeon_ring_force_activity(rdev, ring); |
return radeon_ring_test_lockup(rdev, ring); |
} |
u32 r6xx_remap_render_backend(struct radeon_device *rdev, |
u32 tiling_pipe_num, |
u32 max_rb_num, |
1277,7 → 1812,6 |
{ |
u32 tiling_config; |
u32 ramcfg; |
u32 cc_rb_backend_disable; |
u32 cc_gc_shader_pipe_config; |
u32 tmp; |
int i, j; |
1404,26 → 1938,20 |
} |
tiling_config |= BANK_SWAPS(1); |
cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; |
tmp = R6XX_MAX_BACKENDS - |
r600_count_pipe_bits((cc_rb_backend_disable >> 16) & R6XX_MAX_BACKENDS_MASK); |
if (tmp < rdev->config.r600.max_backends) { |
rdev->config.r600.max_backends = tmp; |
} |
cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0x00ffff00; |
tmp = R6XX_MAX_PIPES - |
r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R6XX_MAX_PIPES_MASK); |
if (tmp < rdev->config.r600.max_pipes) { |
rdev->config.r600.max_pipes = tmp; |
} |
tmp = R6XX_MAX_SIMDS - |
tmp = rdev->config.r600.max_simds - |
r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R6XX_MAX_SIMDS_MASK); |
if (tmp < rdev->config.r600.max_simds) { |
rdev->config.r600.max_simds = tmp; |
} |
rdev->config.r600.active_simds = tmp; |
disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R6XX_MAX_BACKENDS_MASK; |
tmp = 0; |
for (i = 0; i < rdev->config.r600.max_backends; i++) |
tmp |= (1 << i); |
/* if all the backends are disabled, fix it up here */ |
if ((disabled_rb_mask & tmp) == tmp) { |
for (i = 0; i < rdev->config.r600.max_backends; i++) |
disabled_rb_mask &= ~(1 << i); |
} |
tmp = (tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; |
tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.r600.max_backends, |
R6XX_MAX_BACKENDS, disabled_rb_mask); |
1688,20 → 2216,27 |
*/ |
u32 r600_pciep_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->pciep_idx_lock, flags); |
WREG32(PCIE_PORT_INDEX, ((reg) & 0xff)); |
(void)RREG32(PCIE_PORT_INDEX); |
r = RREG32(PCIE_PORT_DATA); |
spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags); |
return r; |
} |
void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->pciep_idx_lock, flags); |
WREG32(PCIE_PORT_INDEX, ((reg) & 0xff)); |
(void)RREG32(PCIE_PORT_INDEX); |
WREG32(PCIE_PORT_DATA, (v)); |
(void)RREG32(PCIE_PORT_DATA); |
spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags); |
} |
/* |
1709,6 → 2244,7 |
*/ |
void r600_cp_stop(struct radeon_device *rdev) |
{ |
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); |
1717,22 → 2253,15 |
int r600_init_microcode(struct radeon_device *rdev) |
{ |
struct platform_device *pdev; |
const char *chip_name; |
const char *rlc_chip_name; |
size_t pfp_req_size, me_req_size, rlc_req_size; |
const char *smc_chip_name = "RV770"; |
size_t pfp_req_size, me_req_size, rlc_req_size, smc_req_size = 0; |
char fw_name[30]; |
int err; |
DRM_DEBUG("\n"); |
pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); |
err = IS_ERR(pdev); |
if (err) { |
printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); |
return -EINVAL; |
} |
switch (rdev->family) { |
case CHIP_R600: |
chip_name = "R600"; |
1766,32 → 2295,51 |
case CHIP_RV770: |
chip_name = "RV770"; |
rlc_chip_name = "R700"; |
smc_chip_name = "RV770"; |
smc_req_size = ALIGN(RV770_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_RV730: |
case CHIP_RV740: |
chip_name = "RV730"; |
rlc_chip_name = "R700"; |
smc_chip_name = "RV730"; |
smc_req_size = ALIGN(RV730_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_RV710: |
chip_name = "RV710"; |
rlc_chip_name = "R700"; |
smc_chip_name = "RV710"; |
smc_req_size = ALIGN(RV710_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_RV740: |
chip_name = "RV730"; |
rlc_chip_name = "R700"; |
smc_chip_name = "RV740"; |
smc_req_size = ALIGN(RV740_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_CEDAR: |
chip_name = "CEDAR"; |
rlc_chip_name = "CEDAR"; |
smc_chip_name = "CEDAR"; |
smc_req_size = ALIGN(CEDAR_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_REDWOOD: |
chip_name = "REDWOOD"; |
rlc_chip_name = "REDWOOD"; |
smc_chip_name = "REDWOOD"; |
smc_req_size = ALIGN(REDWOOD_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_JUNIPER: |
chip_name = "JUNIPER"; |
rlc_chip_name = "JUNIPER"; |
smc_chip_name = "JUNIPER"; |
smc_req_size = ALIGN(JUNIPER_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_CYPRESS: |
case CHIP_HEMLOCK: |
chip_name = "CYPRESS"; |
rlc_chip_name = "CYPRESS"; |
smc_chip_name = "CYPRESS"; |
smc_req_size = ALIGN(CYPRESS_SMC_UCODE_SIZE, 4); |
break; |
case CHIP_PALM: |
chip_name = "PALM"; |
1817,15 → 2365,15 |
me_req_size = R700_PM4_UCODE_SIZE * 4; |
rlc_req_size = R700_RLC_UCODE_SIZE * 4; |
} else { |
pfp_req_size = PFP_UCODE_SIZE * 4; |
me_req_size = PM4_UCODE_SIZE * 12; |
rlc_req_size = RLC_UCODE_SIZE * 4; |
pfp_req_size = R600_PFP_UCODE_SIZE * 4; |
me_req_size = R600_PM4_UCODE_SIZE * 12; |
rlc_req_size = R600_RLC_UCODE_SIZE * 4; |
} |
DRM_INFO("Loading %s Microcode\n", chip_name); |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); |
err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->pfp_fw->size != pfp_req_size) { |
1837,7 → 2385,7 |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); |
err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->me_fw->size != me_req_size) { |
1848,7 → 2396,7 |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); |
err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->rlc_fw->size != rlc_req_size) { |
1858,9 → 2406,25 |
err = -EINVAL; |
} |
if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name); |
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); |
if (err) { |
printk(KERN_ERR |
"smc: error loading firmware \"%s\"\n", |
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", |
rdev->smc_fw->size, fw_name); |
err = -EINVAL; |
} |
} |
out: |
platform_device_unregister(pdev); |
if (err) { |
if (err != -EINVAL) |
printk(KERN_ERR |
1872,10 → 2436,42 |
rdev->me_fw = NULL; |
release_firmware(rdev->rlc_fw); |
rdev->rlc_fw = NULL; |
release_firmware(rdev->smc_fw); |
rdev->smc_fw = NULL; |
} |
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; |
1902,13 → 2498,13 |
fw_data = (const __be32 *)rdev->me_fw->data; |
WREG32(CP_ME_RAM_WADDR, 0); |
for (i = 0; i < PM4_UCODE_SIZE * 3; i++) |
for (i = 0; i < R600_PM4_UCODE_SIZE * 3; i++) |
WREG32(CP_ME_RAM_DATA, |
be32_to_cpup(fw_data++)); |
fw_data = (const __be32 *)rdev->pfp_fw->data; |
WREG32(CP_PFP_UCODE_ADDR, 0); |
for (i = 0; i < PFP_UCODE_SIZE; i++) |
for (i = 0; i < R600_PFP_UCODE_SIZE; i++) |
WREG32(CP_PFP_UCODE_DATA, |
be32_to_cpup(fw_data++)); |
1941,7 → 2537,7 |
radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, 0); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
cp_me = 0xff; |
WREG32(R_0086D8_CP_ME_CNTL, cp_me); |
1962,8 → 2558,8 |
WREG32(GRBM_SOFT_RESET, 0); |
/* Set ring buffer size */ |
rb_bufsz = drm_order(ring->ring_size / 8); |
tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
rb_bufsz = order_base_2(ring->ring_size / 8); |
tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
#ifdef __BIG_ENDIAN |
tmp |= BUF_SWAP_32BIT; |
#endif |
1998,8 → 2594,6 |
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); |
2007,6 → 2601,10 |
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; |
} |
2016,7 → 2614,7 |
int r; |
/* Align ring size */ |
rb_bufsz = drm_order(ring_size / 8); |
rb_bufsz = order_base_2(ring_size / 8); |
ring_size = (1 << (rb_bufsz + 1)) * 4; |
ring->ring_size = ring_size; |
ring->align_mask = 16 - 1; |
2039,327 → 2637,6 |
} |
/* |
* DMA |
* Starting with R600, the GPU has an asynchronous |
* DMA engine. The programming model is very similar |
* to the 3D engine (ring buffer, IBs, etc.), but the |
* DMA controller has it's own packet format that is |
* different form the PM4 format used by the 3D engine. |
* It supports copying data, writing embedded data, |
* solid fills, and a number of other things. It also |
* has support for tiling/detiling of buffers. |
*/ |
/** |
* r600_dma_stop - stop the async dma engine |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engine (r6xx-evergreen). |
*/ |
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); |
rb_cntl &= ~DMA_RB_ENABLE; |
WREG32(DMA_RB_CNTL, rb_cntl); |
rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; |
} |
/** |
* r600_dma_resume - setup and start the async dma engine |
* |
* @rdev: radeon_device pointer |
* |
* Set up the DMA ring buffer and enable it. (r6xx-evergreen). |
* Returns 0 for success, error for failure. |
*/ |
int r600_dma_resume(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; |
u32 rb_cntl, dma_cntl, ib_cntl; |
u32 rb_bufsz; |
int r; |
/* Reset dma */ |
if (rdev->family >= CHIP_RV770) |
WREG32(SRBM_SOFT_RESET, RV770_SOFT_RESET_DMA); |
else |
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); |
RREG32(SRBM_SOFT_RESET); |
udelay(50); |
WREG32(SRBM_SOFT_RESET, 0); |
WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL, 0); |
WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL, 0); |
/* Set ring buffer size in dwords */ |
rb_bufsz = drm_order(ring->ring_size / 4); |
rb_cntl = rb_bufsz << 1; |
#ifdef __BIG_ENDIAN |
rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE; |
#endif |
WREG32(DMA_RB_CNTL, rb_cntl); |
/* Initialize the ring buffer's read and write pointers */ |
WREG32(DMA_RB_RPTR, 0); |
WREG32(DMA_RB_WPTR, 0); |
/* set the wb address whether it's enabled or not */ |
WREG32(DMA_RB_RPTR_ADDR_HI, |
upper_32_bits(rdev->wb.gpu_addr + R600_WB_DMA_RPTR_OFFSET) & 0xFF); |
WREG32(DMA_RB_RPTR_ADDR_LO, |
((rdev->wb.gpu_addr + R600_WB_DMA_RPTR_OFFSET) & 0xFFFFFFFC)); |
if (rdev->wb.enabled) |
rb_cntl |= DMA_RPTR_WRITEBACK_ENABLE; |
WREG32(DMA_RB_BASE, ring->gpu_addr >> 8); |
/* enable DMA IBs */ |
ib_cntl = DMA_IB_ENABLE; |
#ifdef __BIG_ENDIAN |
ib_cntl |= DMA_IB_SWAP_ENABLE; |
#endif |
WREG32(DMA_IB_CNTL, ib_cntl); |
dma_cntl = RREG32(DMA_CNTL); |
dma_cntl &= ~CTXEMPTY_INT_ENABLE; |
WREG32(DMA_CNTL, dma_cntl); |
if (rdev->family >= CHIP_RV770) |
WREG32(DMA_MODE, 1); |
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; |
r = radeon_ring_test(rdev, R600_RING_TYPE_DMA_INDEX, ring); |
if (r) { |
ring->ready = false; |
return r; |
} |
radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); |
return 0; |
} |
/** |
* r600_dma_fini - tear down the async dma engine |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engine and free the ring (r6xx-evergreen). |
*/ |
void r600_dma_fini(struct radeon_device *rdev) |
{ |
r600_dma_stop(rdev); |
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]); |
} |
/* |
* UVD |
*/ |
int r600_uvd_rbc_start(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
uint64_t rptr_addr; |
uint32_t rb_bufsz, tmp; |
int r; |
rptr_addr = rdev->wb.gpu_addr + R600_WB_UVD_RPTR_OFFSET; |
if (upper_32_bits(rptr_addr) != upper_32_bits(ring->gpu_addr)) { |
DRM_ERROR("UVD ring and rptr not in the same 4GB segment!\n"); |
return -EINVAL; |
} |
/* force RBC into idle state */ |
WREG32(UVD_RBC_RB_CNTL, 0x11010101); |
/* Set the write pointer delay */ |
WREG32(UVD_RBC_RB_WPTR_CNTL, 0); |
/* set the wb address */ |
WREG32(UVD_RBC_RB_RPTR_ADDR, rptr_addr >> 2); |
/* programm the 4GB memory segment for rptr and ring buffer */ |
WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(rptr_addr) | |
(0x7 << 16) | (0x1 << 31)); |
/* Initialize the ring buffer's read and write pointers */ |
WREG32(UVD_RBC_RB_RPTR, 0x0); |
ring->wptr = ring->rptr = RREG32(UVD_RBC_RB_RPTR); |
WREG32(UVD_RBC_RB_WPTR, ring->wptr); |
/* set the ring address */ |
WREG32(UVD_RBC_RB_BASE, ring->gpu_addr); |
/* Set ring buffer size */ |
rb_bufsz = drm_order(ring->ring_size); |
rb_bufsz = (0x1 << 8) | rb_bufsz; |
WREG32(UVD_RBC_RB_CNTL, rb_bufsz); |
ring->ready = true; |
r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring); |
if (r) { |
ring->ready = false; |
return r; |
} |
r = radeon_ring_lock(rdev, ring, 10); |
if (r) { |
DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r); |
return r; |
} |
tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0); |
radeon_ring_write(ring, tmp); |
radeon_ring_write(ring, 0xFFFFF); |
tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0); |
radeon_ring_write(ring, tmp); |
radeon_ring_write(ring, 0xFFFFF); |
tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0); |
radeon_ring_write(ring, tmp); |
radeon_ring_write(ring, 0xFFFFF); |
/* Clear timeout status bits */ |
radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0)); |
radeon_ring_write(ring, 0x8); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0)); |
radeon_ring_write(ring, 3); |
radeon_ring_unlock_commit(rdev, ring); |
return 0; |
} |
void r600_uvd_rbc_stop(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
/* force RBC into idle state */ |
WREG32(UVD_RBC_RB_CNTL, 0x11010101); |
ring->ready = false; |
} |
int r600_uvd_init(struct radeon_device *rdev) |
{ |
int i, j, r; |
/* disable byte swapping */ |
u32 lmi_swap_cntl = 0; |
u32 mp_swap_cntl = 0; |
/* raise clocks while booting up the VCPU */ |
radeon_set_uvd_clocks(rdev, 53300, 40000); |
/* disable clock gating */ |
WREG32(UVD_CGC_GATE, 0); |
/* disable interupt */ |
WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1)); |
/* put LMI, VCPU, RBC etc... into reset */ |
WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET | |
LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET | |
CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET); |
mdelay(5); |
/* take UVD block out of reset */ |
WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD); |
mdelay(5); |
/* initialize UVD memory controller */ |
WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) | |
(1 << 21) | (1 << 9) | (1 << 20)); |
#ifdef __BIG_ENDIAN |
/* swap (8 in 32) RB and IB */ |
lmi_swap_cntl = 0xa; |
mp_swap_cntl = 0; |
#endif |
WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl); |
WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl); |
WREG32(UVD_MPC_SET_MUXA0, 0x40c2040); |
WREG32(UVD_MPC_SET_MUXA1, 0x0); |
WREG32(UVD_MPC_SET_MUXB0, 0x40c2040); |
WREG32(UVD_MPC_SET_MUXB1, 0x0); |
WREG32(UVD_MPC_SET_ALU, 0); |
WREG32(UVD_MPC_SET_MUX, 0x88); |
/* Stall UMC */ |
WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); |
WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); |
/* take all subblocks out of reset, except VCPU */ |
WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); |
mdelay(5); |
/* enable VCPU clock */ |
WREG32(UVD_VCPU_CNTL, 1 << 9); |
/* enable UMC */ |
WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); |
/* boot up the VCPU */ |
WREG32(UVD_SOFT_RESET, 0); |
mdelay(10); |
WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); |
for (i = 0; i < 10; ++i) { |
uint32_t status; |
for (j = 0; j < 100; ++j) { |
status = RREG32(UVD_STATUS); |
if (status & 2) |
break; |
mdelay(10); |
} |
r = 0; |
if (status & 2) |
break; |
DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n"); |
WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET); |
mdelay(10); |
WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET); |
mdelay(10); |
r = -1; |
} |
if (r) { |
DRM_ERROR("UVD not responding, giving up!!!\n"); |
radeon_set_uvd_clocks(rdev, 0, 0); |
return r; |
} |
/* enable interupt */ |
WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1)); |
r = r600_uvd_rbc_start(rdev); |
if (!r) |
DRM_INFO("UVD initialized successfully.\n"); |
/* lower clocks again */ |
radeon_set_uvd_clocks(rdev, 0, 0); |
return r; |
} |
/* |
* GPU scratch registers helpers function. |
*/ |
void r600_scratch_init(struct radeon_device *rdev) |
2396,7 → 2673,7 |
radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); |
radeon_ring_write(ring, ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(scratch); |
if (tmp == 0xDEADBEEF) |
2414,94 → 2691,6 |
return r; |
} |
/** |
* r600_dma_ring_test - simple async dma engine test |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Test the DMA engine by writing using it to write an |
* value to memory. (r6xx-SI). |
* Returns 0 for success, error for failure. |
*/ |
int r600_dma_ring_test(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
unsigned i; |
int r; |
void __iomem *ptr = (void *)rdev->vram_scratch.ptr; |
u32 tmp; |
if (!ptr) { |
DRM_ERROR("invalid vram scratch pointer\n"); |
return -EINVAL; |
} |
tmp = 0xCAFEDEAD; |
writel(tmp, ptr); |
r = radeon_ring_lock(rdev, ring, 4); |
if (r) { |
DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r); |
return r; |
} |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); |
radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff); |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = readl(ptr); |
if (tmp == 0xDEADBEEF) |
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 (0x%08X)\n", |
ring->idx, tmp); |
r = -EINVAL; |
} |
return r; |
} |
int r600_uvd_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
uint32_t tmp = 0; |
unsigned i; |
int r; |
WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD); |
r = radeon_ring_lock(rdev, ring, 3); |
if (r) { |
DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", |
ring->idx, r); |
return r; |
} |
radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(UVD_CONTEXT_ID); |
if (tmp == 0xDEADBEEF) |
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 (0x%08X)\n", |
ring->idx, tmp); |
r = -EINVAL; |
} |
return r; |
} |
/* |
* CP fences/semaphores |
*/ |
2510,14 → 2699,17 |
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 */ |
2524,7 → 2716,7 |
/* 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); |
2531,9 → 2723,7 |
} 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 */ |
2553,137 → 2743,44 |
} |
} |
void r600_uvd_fence_emit(struct radeon_device *rdev, |
struct radeon_fence *fence) |
{ |
struct radeon_ring *ring = &rdev->ring[fence->ring]; |
uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr; |
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, 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)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); |
radeon_ring_write(ring, 2); |
return; |
} |
void r600_semaphore_ring_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait) |
{ |
uint64_t addr = semaphore->gpu_addr; |
unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL; |
if (rdev->family < CHIP_CAYMAN) |
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, (upper_32_bits(addr) & 0xff) | sel); |
} |
/* |
* DMA fences/semaphores |
*/ |
/** |
* r600_dma_fence_ring_emit - emit a fence on the DMA ring |
* r600_semaphore_ring_emit - emit a semaphore on the CP ring |
* |
* @rdev: radeon_device pointer |
* @fence: radeon fence object |
* |
* Add a DMA fence packet to the ring to write |
* the fence seq number and DMA trap packet to generate |
* an interrupt if needed (r6xx-r7xx). |
*/ |
void r600_dma_fence_ring_emit(struct radeon_device *rdev, |
struct radeon_fence *fence) |
{ |
struct radeon_ring *ring = &rdev->ring[fence->ring]; |
u64 addr = rdev->fence_drv[fence->ring].gpu_addr; |
/* write the fence */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0)); |
radeon_ring_write(ring, addr & 0xfffffffc); |
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff)); |
radeon_ring_write(ring, lower_32_bits(fence->seq)); |
/* generate an interrupt */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0)); |
} |
/** |
* r600_dma_semaphore_ring_emit - emit a semaphore on the dma ring |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* @ring: radeon ring buffer object |
* @semaphore: radeon semaphore object |
* @emit_wait: wait or signal semaphore |
* @emit_wait: Is this a sempahore wait? |
* |
* Add a DMA semaphore packet to the ring wait on or signal |
* other rings (r6xx-SI). |
* Emits a semaphore signal/wait packet to the CP ring and prevents the PFP |
* from running ahead of semaphore waits. |
*/ |
void r600_dma_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) |
{ |
u64 addr = semaphore->gpu_addr; |
u32 s = emit_wait ? 0 : 1; |
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); |
} |
void r600_uvd_semaphore_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait) |
{ |
uint64_t addr = semaphore->gpu_addr; |
unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL; |
radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); |
radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); |
if (rdev->family < CHIP_CAYMAN) |
sel |= PACKET3_SEM_WAIT_ON_SIGNAL; |
radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); |
radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); |
radeon_ring_write(ring, PACKET3(PACKET3_MEM_SEMAPHORE, 1)); |
radeon_ring_write(ring, lower_32_bits(addr)); |
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); |
radeon_ring_write(ring, emit_wait ? 1 : 0); |
/* PFP_SYNC_ME packet only exists on 7xx+ */ |
if (emit_wait && (rdev->family >= CHIP_RV770)) { |
/* Prevent the PFP from running ahead of the semaphore wait */ |
radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); |
radeon_ring_write(ring, 0x0); |
} |
int r600_copy_blit(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; |
struct radeon_sa_bo *vb = NULL; |
int r; |
r = r600_blit_prepare_copy(rdev, num_gpu_pages, fence, &vb, &sem); |
if (r) { |
return r; |
return true; |
} |
r600_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages, vb); |
r600_blit_done_copy(rdev, fence, vb, sem); |
return 0; |
} |
/** |
* r600_copy_dma - copy pages using the DMA engine |
* r600_copy_cpdma - copy pages using the CP DMA engine |
* |
* @rdev: radeon_device pointer |
* @src_offset: src GPU address |
2691,19 → 2788,19 |
* @num_gpu_pages: number of GPU pages to xfer |
* @fence: radeon fence object |
* |
* Copy GPU paging using the DMA engine (r6xx). |
* Copy GPU paging using the CP DMA engine (r6xx+). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int r600_copy_dma(struct radeon_device *rdev, |
int r600_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.dma_ring_index; |
int ring_index = rdev->asic->copy.blit_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_dw, cur_size_in_dw; |
u32 size_in_bytes, cur_size_in_bytes, tmp; |
int i, num_loops; |
int r = 0; |
2713,9 → 2810,9 |
return r; |
} |
size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; |
num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFE); |
r = radeon_ring_lock(rdev, ring, num_loops * 4 + 8); |
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 * 6 + 24); |
if (r) { |
DRM_ERROR("radeon: moving bo (%d).\n", r); |
radeon_semaphore_free(rdev, &sem, NULL); |
2722,35 → 2819,41 |
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); |
radeon_ring_write(ring, WAIT_3D_IDLE_bit); |
for (i = 0; i < num_loops; i++) { |
cur_size_in_dw = size_in_dw; |
if (cur_size_in_dw > 0xFFFE) |
cur_size_in_dw = 0xFFFE; |
size_in_dw -= cur_size_in_dw; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw)); |
radeon_ring_write(ring, dst_offset & 0xfffffffc); |
radeon_ring_write(ring, src_offset & 0xfffffffc); |
radeon_ring_write(ring, (((upper_32_bits(dst_offset) & 0xff) << 16) | |
(upper_32_bits(src_offset) & 0xff))); |
src_offset += cur_size_in_dw * 4; |
dst_offset += cur_size_in_dw * 4; |
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; |
tmp = upper_32_bits(src_offset) & 0xff; |
if (size_in_bytes == 0) |
tmp |= PACKET3_CP_DMA_CP_SYNC; |
radeon_ring_write(ring, PACKET3(PACKET3_CP_DMA, 4)); |
radeon_ring_write(ring, lower_32_bits(src_offset)); |
radeon_ring_write(ring, tmp); |
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; |
dst_offset += cur_size_in_bytes; |
} |
radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); |
radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); |
radeon_ring_write(ring, WAIT_CP_DMA_IDLE_bit); |
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_ring_unlock_commit(rdev, ring, false); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
2777,19 → 2880,13 |
/* enable pcie gen2 link */ |
r600_pcie_gen2_enable(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; |
} |
} |
/* scratch needs to be initialized before MC */ |
r = r600_vram_scratch_init(rdev); |
if (r) |
return r; |
r600_mc_program(rdev); |
if (rdev->flags & RADEON_IS_AGP) { |
r600_agp_enable(rdev); |
} else { |
2798,12 → 2895,6 |
return r; |
} |
r600_gpu_init(rdev); |
r = r600_blit_init(rdev); |
if (r) { |
// r600_blit_fini(rdev); |
rdev->asic->copy.copy = NULL; |
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); |
} |
/* allocate wb buffer */ |
r = radeon_wb_init(rdev); |
2816,12 → 2907,6 |
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); |
2839,18 → 2924,10 |
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, |
0, 0xfffff, RADEON_CP_PACKET2); |
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, |
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
if (r) |
return r; |
r = r600_cp_load_microcode(rdev); |
if (r) |
return r; |
2858,15 → 2935,13 |
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); |
return r; |
} |
return 0; |
} |
2946,12 → 3021,20 |
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); |
3003,16 → 3086,6 |
radeon_ring_write(ring, ib->length_dw); |
} |
void r600_uvd_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0)); |
radeon_ring_write(ring, ib->gpu_addr); |
radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0)); |
radeon_ring_write(ring, ib->length_dw); |
} |
int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
struct radeon_ib ib; |
3036,7 → 3109,7 |
ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); |
ib.ptr[2] = 0xDEADBEEF; |
ib.length_dw = 3; |
r = radeon_ib_schedule(rdev, &ib, NULL); |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
if (r) { |
DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); |
goto free_ib; |
3066,139 → 3139,6 |
return r; |
} |
/** |
* r600_dma_ib_test - test an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Test a simple IB in the DMA ring (r6xx-SI). |
* Returns 0 on success, error on failure. |
*/ |
int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
struct radeon_ib ib; |
unsigned i; |
int r; |
void __iomem *ptr = (void *)rdev->vram_scratch.ptr; |
u32 tmp = 0; |
if (!ptr) { |
DRM_ERROR("invalid vram scratch pointer\n"); |
return -EINVAL; |
} |
tmp = 0xCAFEDEAD; |
writel(tmp, ptr); |
r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); |
if (r) { |
DRM_ERROR("radeon: failed to get ib (%d).\n", r); |
return r; |
} |
ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1); |
ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc; |
ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff; |
ib.ptr[3] = 0xDEADBEEF; |
ib.length_dw = 4; |
r = radeon_ib_schedule(rdev, &ib, NULL); |
if (r) { |
radeon_ib_free(rdev, &ib); |
DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); |
return r; |
} |
r = radeon_fence_wait(ib.fence, false); |
if (r) { |
DRM_ERROR("radeon: fence wait failed (%d).\n", r); |
return r; |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = readl(ptr); |
if (tmp == 0xDEADBEEF) |
break; |
DRM_UDELAY(1); |
} |
if (i < rdev->usec_timeout) { |
DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i); |
} else { |
DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp); |
r = -EINVAL; |
} |
radeon_ib_free(rdev, &ib); |
return r; |
} |
int r600_uvd_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 (r) { |
DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r); |
return r; |
} |
// r = radeon_uvd_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_uvd_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); |
goto error; |
} |
DRM_INFO("ib test on ring %d succeeded\n", ring->idx); |
error: |
radeon_fence_unref(&fence); |
radeon_set_uvd_clocks(rdev, 0, 0); |
return r; |
} |
/** |
* r600_dma_ring_ib_execute - Schedule an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to schedule |
* |
* Schedule an IB in the DMA ring (r6xx-r7xx). |
*/ |
void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
if (rdev->wb.enabled) { |
u32 next_rptr = ring->wptr + 4; |
while ((next_rptr & 7) != 5) |
next_rptr++; |
next_rptr += 3; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); |
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff); |
radeon_ring_write(ring, next_rptr); |
} |
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring. |
* Pad as necessary with NOPs. |
*/ |
while ((ring->wptr & 7) != 5) |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_INDIRECT_BUFFER, 0, 0, 0)); |
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0)); |
radeon_ring_write(ring, (ib->length_dw << 16) | (upper_32_bits(ib->gpu_addr) & 0xFF)); |
} |
/* |
* Interrupts |
* |
3215,7 → 3155,7 |
u32 rb_bufsz; |
/* Align ring size */ |
rb_bufsz = drm_order(ring_size / 4); |
rb_bufsz = order_base_2(ring_size / 4); |
ring_size = (1 << rb_bufsz) * 4; |
rdev->ih.ring_size = ring_size; |
rdev->ih.ptr_mask = rdev->ih.ring_size - 1; |
3230,7 → 3170,7 |
if (rdev->ih.ring_obj == NULL) { |
r = radeon_bo_create(rdev, rdev->ih.ring_size, |
PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_GTT, |
RADEON_GEM_DOMAIN_GTT, 0, |
NULL, &rdev->ih.ring_obj); |
if (r) { |
DRM_ERROR("radeon: failed to create ih ring buffer (%d).\n", r); |
3295,7 → 3235,7 |
WREG32(RLC_CNTL, RLC_ENABLE); |
} |
static int r600_rlc_init(struct radeon_device *rdev) |
static int r600_rlc_resume(struct radeon_device *rdev) |
{ |
u32 i; |
const __be32 *fw_data; |
3307,45 → 3247,22 |
WREG32(RLC_HB_CNTL, 0); |
if (rdev->family == CHIP_ARUBA) { |
WREG32(TN_RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8); |
WREG32(TN_RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8); |
} |
if (rdev->family <= CHIP_CAYMAN) { |
WREG32(RLC_HB_BASE, 0); |
WREG32(RLC_HB_RPTR, 0); |
WREG32(RLC_HB_WPTR, 0); |
} |
if (rdev->family <= CHIP_CAICOS) { |
WREG32(RLC_HB_WPTR_LSB_ADDR, 0); |
WREG32(RLC_HB_WPTR_MSB_ADDR, 0); |
} |
WREG32(RLC_MC_CNTL, 0); |
WREG32(RLC_UCODE_CNTL, 0); |
fw_data = (const __be32 *)rdev->rlc_fw->data; |
if (rdev->family >= CHIP_ARUBA) { |
for (i = 0; i < ARUBA_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
} else if (rdev->family >= CHIP_CAYMAN) { |
for (i = 0; i < CAYMAN_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
} else if (rdev->family >= CHIP_CEDAR) { |
for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
} else if (rdev->family >= CHIP_RV770) { |
if (rdev->family >= CHIP_RV770) { |
for (i = 0; i < R700_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
} else { |
for (i = 0; i < RLC_UCODE_SIZE; i++) { |
for (i = 0; i < R600_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
3453,7 → 3370,10 |
r600_disable_interrupts(rdev); |
/* init rlc */ |
ret = r600_rlc_init(rdev); |
if (rdev->family >= CHIP_CEDAR) |
ret = evergreen_rlc_resume(rdev); |
else |
ret = r600_rlc_resume(rdev); |
if (ret) { |
r600_ih_ring_fini(rdev); |
return ret; |
3472,7 → 3392,7 |
WREG32(INTERRUPT_CNTL, interrupt_cntl); |
WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8); |
rb_bufsz = drm_order(rdev->ih.ring_size / 4); |
rb_bufsz = order_base_2(rdev->ih.ring_size / 4); |
ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE | |
IH_WPTR_OVERFLOW_CLEAR | |
3519,8 → 3439,8 |
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; |
if (!rdev->irq.installed) { |
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
3555,8 → 3475,21 |
hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK; |
hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK; |
} |
dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE; |
if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) { |
thermal_int = RREG32(CG_THERMAL_INT) & |
~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); |
} else if (rdev->family >= CHIP_RV770) { |
thermal_int = RREG32(RV770_CG_THERMAL_INT) & |
~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); |
} |
if (rdev->irq.dpm_thermal) { |
DRM_DEBUG("dpm thermal\n"); |
thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; |
} |
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { |
DRM_DEBUG("r600_irq_set: sw int\n"); |
cp_int_cntl |= RB_INT_ENABLE; |
3614,8 → 3547,8 |
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); |
3638,6 → 3571,11 |
WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0); |
WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1); |
} |
if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) { |
WREG32(CG_THERMAL_INT, thermal_int); |
} else if (rdev->family >= CHIP_RV770) { |
WREG32(RV770_CG_THERMAL_INT, thermal_int); |
} |
return 0; |
} |
3787,6 → 3725,7 |
tmp = RREG32(IH_RB_CNTL); |
tmp |= IH_WPTR_OVERFLOW_CLEAR; |
WREG32(IH_RB_CNTL, tmp); |
wptr &= ~RB_OVERFLOW; |
} |
return (wptr & rdev->ih.ptr_mask); |
} |
3831,6 → 3770,7 |
u32 ring_index; |
bool queue_hotplug = false; |
bool queue_hdmi = false; |
bool queue_thermal = false; |
if (!rdev->ih.enabled || rdev->shutdown) |
return IRQ_NONE; |
3984,6 → 3924,10 |
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 */ |
3998,6 → 3942,16 |
DRM_DEBUG("IH: DMA trap\n"); |
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX); |
break; |
case 230: /* thermal low to high */ |
DRM_DEBUG("IH: thermal low to high\n"); |
rdev->pm.dpm.thermal.high_to_low = false; |
queue_thermal = true; |
break; |
case 231: /* thermal high to low */ |
DRM_DEBUG("IH: thermal high to low\n"); |
rdev->pm.dpm.thermal.high_to_low = true; |
queue_thermal = true; |
break; |
case 233: /* GUI IDLE */ |
DRM_DEBUG("IH: GUI idle\n"); |
break; |
4053,16 → 4007,15 |
} |
/** |
* r600_ioctl_wait_idle - flush host path cache on wait idle ioctl |
* r600_mmio_hdp_flush - flush Host Data Path cache via MMIO |
* rdev: radeon device structure |
* bo: buffer object struct which userspace is waiting for idle |
* |
* Some R6XX/R7XX doesn't seems to take into account HDP flush performed |
* through ring buffer, this leads to corruption in rendering, see |
* http://bugzilla.kernel.org/show_bug.cgi?id=15186 to avoid this we |
* directly perform HDP flush by writing register through MMIO. |
* Some R6XX/R7XX don't seem to take into account HDP flushes performed |
* through the ring buffer. This leads to corruption in rendering, see |
* http://bugzilla.kernel.org/show_bug.cgi?id=15186 . To avoid this, we |
* directly perform the HDP flush by writing the register through MMIO. |
*/ |
void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) |
void r600_mmio_hdp_flush(struct radeon_device *rdev) |
{ |
/* r7xx hw bug. write to HDP_DEBUG1 followed by fb read |
* rather than write to HDP_REG_COHERENCY_FLUSH_CNTL. |
/drivers/video/drm/radeon/r600_audio.c |
---|
57,12 → 57,12 |
*/ |
static int r600_audio_chipset_supported(struct radeon_device *rdev) |
{ |
return ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE6(rdev); |
return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); |
} |
struct r600_audio r600_audio_status(struct radeon_device *rdev) |
struct r600_audio_pin r600_audio_status(struct radeon_device *rdev) |
{ |
struct r600_audio status; |
struct r600_audio_pin status; |
uint32_t value; |
value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL); |
120,16 → 120,16 |
struct radeon_device *rdev = container_of(work, struct radeon_device, |
audio_work); |
struct drm_device *dev = rdev->ddev; |
struct r600_audio audio_status = r600_audio_status(rdev); |
struct r600_audio_pin audio_status = r600_audio_status(rdev); |
struct drm_encoder *encoder; |
bool changed = false; |
if (rdev->audio_status.channels != audio_status.channels || |
rdev->audio_status.rate != audio_status.rate || |
rdev->audio_status.bits_per_sample != audio_status.bits_per_sample || |
rdev->audio_status.status_bits != audio_status.status_bits || |
rdev->audio_status.category_code != audio_status.category_code) { |
rdev->audio_status = audio_status; |
if (rdev->audio.pin[0].channels != audio_status.channels || |
rdev->audio.pin[0].rate != audio_status.rate || |
rdev->audio.pin[0].bits_per_sample != audio_status.bits_per_sample || |
rdev->audio.pin[0].status_bits != audio_status.status_bits || |
rdev->audio.pin[0].category_code != audio_status.category_code) { |
rdev->audio.pin[0] = audio_status; |
changed = true; |
} |
141,13 → 141,16 |
} |
} |
/* |
* turn on/off audio engine |
*/ |
static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable) |
/* enable the audio stream */ |
void r600_audio_enable(struct radeon_device *rdev, |
struct r600_audio_pin *pin, |
bool enable) |
{ |
u32 value = 0; |
DRM_INFO("%s audio support\n", enable ? "Enabling" : "Disabling"); |
if (!pin) |
return; |
if (ASIC_IS_DCE4(rdev)) { |
if (enable) { |
value |= 0x81000000; /* Required to enable audio */ |
158,7 → 161,6 |
WREG32_P(R600_AUDIO_ENABLE, |
enable ? 0x81000000 : 0x0, ~0x81000000); |
} |
rdev->audio_enabled = enable; |
} |
/* |
169,13 → 171,17 |
if (!radeon_audio || !r600_audio_chipset_supported(rdev)) |
return 0; |
r600_audio_engine_enable(rdev, true); |
rdev->audio.enabled = true; |
rdev->audio_status.channels = -1; |
rdev->audio_status.rate = -1; |
rdev->audio_status.bits_per_sample = -1; |
rdev->audio_status.status_bits = 0; |
rdev->audio_status.category_code = 0; |
rdev->audio.num_pins = 1; |
rdev->audio.pin[0].channels = -1; |
rdev->audio.pin[0].rate = -1; |
rdev->audio.pin[0].bits_per_sample = -1; |
rdev->audio.pin[0].status_bits = 0; |
rdev->audio.pin[0].category_code = 0; |
rdev->audio.pin[0].id = 0; |
/* disable audio. it will be set up later */ |
r600_audio_enable(rdev, &rdev->audio.pin[0], false); |
return 0; |
} |
186,8 → 192,16 |
*/ |
void r600_audio_fini(struct radeon_device *rdev) |
{ |
if (!rdev->audio_enabled) |
if (!rdev->audio.enabled) |
return; |
r600_audio_engine_enable(rdev, false); |
r600_audio_enable(rdev, &rdev->audio.pin[0], false); |
rdev->audio.enabled = false; |
} |
struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev) |
{ |
/* only one pin on 6xx-NI */ |
return &rdev->audio.pin[0]; |
} |
/drivers/video/drm/radeon/r600_blit_shaders.h |
---|
35,5 → 35,4 |
extern const u32 r6xx_ps_size, r6xx_vs_size; |
extern const u32 r6xx_default_size, r7xx_default_size; |
__pure uint32_t int2float(uint32_t x); |
#endif |
/drivers/video/drm/radeon/r600_cs.c |
---|
0,0 → 1,2630 |
/* |
* 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 <linux/kernel.h> |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "r600d.h" |
#include "r600_reg_safe.h" |
static int r600_nomm; |
extern void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size); |
struct r600_cs_track { |
/* configuration we miror so that we use same code btw kms/ums */ |
u32 group_size; |
u32 nbanks; |
u32 npipes; |
/* value we track */ |
u32 sq_config; |
u32 log_nsamples; |
u32 nsamples; |
u32 cb_color_base_last[8]; |
struct radeon_bo *cb_color_bo[8]; |
u64 cb_color_bo_mc[8]; |
u64 cb_color_bo_offset[8]; |
struct radeon_bo *cb_color_frag_bo[8]; |
u64 cb_color_frag_offset[8]; |
struct radeon_bo *cb_color_tile_bo[8]; |
u64 cb_color_tile_offset[8]; |
u32 cb_color_mask[8]; |
u32 cb_color_info[8]; |
u32 cb_color_view[8]; |
u32 cb_color_size_idx[8]; /* unused */ |
u32 cb_target_mask; |
u32 cb_shader_mask; /* unused */ |
bool is_resolve; |
u32 cb_color_size[8]; |
u32 vgt_strmout_en; |
u32 vgt_strmout_buffer_en; |
struct radeon_bo *vgt_strmout_bo[4]; |
u64 vgt_strmout_bo_mc[4]; /* unused */ |
u32 vgt_strmout_bo_offset[4]; |
u32 vgt_strmout_size[4]; |
u32 db_depth_control; |
u32 db_depth_info; |
u32 db_depth_size_idx; |
u32 db_depth_view; |
u32 db_depth_size; |
u32 db_offset; |
struct radeon_bo *db_bo; |
u64 db_bo_mc; |
bool sx_misc_kill_all_prims; |
bool cb_dirty; |
bool db_dirty; |
bool streamout_dirty; |
struct radeon_bo *htile_bo; |
u64 htile_offset; |
u32 htile_surface; |
}; |
#define FMT_8_BIT(fmt, vc) [fmt] = { 1, 1, 1, vc, CHIP_R600 } |
#define FMT_16_BIT(fmt, vc) [fmt] = { 1, 1, 2, vc, CHIP_R600 } |
#define FMT_24_BIT(fmt) [fmt] = { 1, 1, 4, 0, CHIP_R600 } |
#define FMT_32_BIT(fmt, vc) [fmt] = { 1, 1, 4, vc, CHIP_R600 } |
#define FMT_48_BIT(fmt) [fmt] = { 1, 1, 8, 0, CHIP_R600 } |
#define FMT_64_BIT(fmt, vc) [fmt] = { 1, 1, 8, vc, CHIP_R600 } |
#define FMT_96_BIT(fmt) [fmt] = { 1, 1, 12, 0, CHIP_R600 } |
#define FMT_128_BIT(fmt, vc) [fmt] = { 1, 1, 16,vc, CHIP_R600 } |
struct gpu_formats { |
unsigned blockwidth; |
unsigned blockheight; |
unsigned blocksize; |
unsigned valid_color; |
enum radeon_family min_family; |
}; |
static const struct gpu_formats color_formats_table[] = { |
/* 8 bit */ |
FMT_8_BIT(V_038004_COLOR_8, 1), |
FMT_8_BIT(V_038004_COLOR_4_4, 1), |
FMT_8_BIT(V_038004_COLOR_3_3_2, 1), |
FMT_8_BIT(V_038004_FMT_1, 0), |
/* 16-bit */ |
FMT_16_BIT(V_038004_COLOR_16, 1), |
FMT_16_BIT(V_038004_COLOR_16_FLOAT, 1), |
FMT_16_BIT(V_038004_COLOR_8_8, 1), |
FMT_16_BIT(V_038004_COLOR_5_6_5, 1), |
FMT_16_BIT(V_038004_COLOR_6_5_5, 1), |
FMT_16_BIT(V_038004_COLOR_1_5_5_5, 1), |
FMT_16_BIT(V_038004_COLOR_4_4_4_4, 1), |
FMT_16_BIT(V_038004_COLOR_5_5_5_1, 1), |
/* 24-bit */ |
FMT_24_BIT(V_038004_FMT_8_8_8), |
/* 32-bit */ |
FMT_32_BIT(V_038004_COLOR_32, 1), |
FMT_32_BIT(V_038004_COLOR_32_FLOAT, 1), |
FMT_32_BIT(V_038004_COLOR_16_16, 1), |
FMT_32_BIT(V_038004_COLOR_16_16_FLOAT, 1), |
FMT_32_BIT(V_038004_COLOR_8_24, 1), |
FMT_32_BIT(V_038004_COLOR_8_24_FLOAT, 1), |
FMT_32_BIT(V_038004_COLOR_24_8, 1), |
FMT_32_BIT(V_038004_COLOR_24_8_FLOAT, 1), |
FMT_32_BIT(V_038004_COLOR_10_11_11, 1), |
FMT_32_BIT(V_038004_COLOR_10_11_11_FLOAT, 1), |
FMT_32_BIT(V_038004_COLOR_11_11_10, 1), |
FMT_32_BIT(V_038004_COLOR_11_11_10_FLOAT, 1), |
FMT_32_BIT(V_038004_COLOR_2_10_10_10, 1), |
FMT_32_BIT(V_038004_COLOR_8_8_8_8, 1), |
FMT_32_BIT(V_038004_COLOR_10_10_10_2, 1), |
FMT_32_BIT(V_038004_FMT_5_9_9_9_SHAREDEXP, 0), |
FMT_32_BIT(V_038004_FMT_32_AS_8, 0), |
FMT_32_BIT(V_038004_FMT_32_AS_8_8, 0), |
/* 48-bit */ |
FMT_48_BIT(V_038004_FMT_16_16_16), |
FMT_48_BIT(V_038004_FMT_16_16_16_FLOAT), |
/* 64-bit */ |
FMT_64_BIT(V_038004_COLOR_X24_8_32_FLOAT, 1), |
FMT_64_BIT(V_038004_COLOR_32_32, 1), |
FMT_64_BIT(V_038004_COLOR_32_32_FLOAT, 1), |
FMT_64_BIT(V_038004_COLOR_16_16_16_16, 1), |
FMT_64_BIT(V_038004_COLOR_16_16_16_16_FLOAT, 1), |
FMT_96_BIT(V_038004_FMT_32_32_32), |
FMT_96_BIT(V_038004_FMT_32_32_32_FLOAT), |
/* 128-bit */ |
FMT_128_BIT(V_038004_COLOR_32_32_32_32, 1), |
FMT_128_BIT(V_038004_COLOR_32_32_32_32_FLOAT, 1), |
[V_038004_FMT_GB_GR] = { 2, 1, 4, 0 }, |
[V_038004_FMT_BG_RG] = { 2, 1, 4, 0 }, |
/* block compressed formats */ |
[V_038004_FMT_BC1] = { 4, 4, 8, 0 }, |
[V_038004_FMT_BC2] = { 4, 4, 16, 0 }, |
[V_038004_FMT_BC3] = { 4, 4, 16, 0 }, |
[V_038004_FMT_BC4] = { 4, 4, 8, 0 }, |
[V_038004_FMT_BC5] = { 4, 4, 16, 0}, |
[V_038004_FMT_BC6] = { 4, 4, 16, 0, CHIP_CEDAR}, /* Evergreen-only */ |
[V_038004_FMT_BC7] = { 4, 4, 16, 0, CHIP_CEDAR}, /* Evergreen-only */ |
/* The other Evergreen formats */ |
[V_038004_FMT_32_AS_32_32_32_32] = { 1, 1, 4, 0, CHIP_CEDAR}, |
}; |
bool r600_fmt_is_valid_color(u32 format) |
{ |
if (format >= ARRAY_SIZE(color_formats_table)) |
return false; |
if (color_formats_table[format].valid_color) |
return true; |
return false; |
} |
bool r600_fmt_is_valid_texture(u32 format, enum radeon_family family) |
{ |
if (format >= ARRAY_SIZE(color_formats_table)) |
return false; |
if (family < color_formats_table[format].min_family) |
return false; |
if (color_formats_table[format].blockwidth > 0) |
return true; |
return false; |
} |
int r600_fmt_get_blocksize(u32 format) |
{ |
if (format >= ARRAY_SIZE(color_formats_table)) |
return 0; |
return color_formats_table[format].blocksize; |
} |
int r600_fmt_get_nblocksx(u32 format, u32 w) |
{ |
unsigned bw; |
if (format >= ARRAY_SIZE(color_formats_table)) |
return 0; |
bw = color_formats_table[format].blockwidth; |
if (bw == 0) |
return 0; |
return (w + bw - 1) / bw; |
} |
int r600_fmt_get_nblocksy(u32 format, u32 h) |
{ |
unsigned bh; |
if (format >= ARRAY_SIZE(color_formats_table)) |
return 0; |
bh = color_formats_table[format].blockheight; |
if (bh == 0) |
return 0; |
return (h + bh - 1) / bh; |
} |
struct array_mode_checker { |
int array_mode; |
u32 group_size; |
u32 nbanks; |
u32 npipes; |
u32 nsamples; |
u32 blocksize; |
}; |
/* returns alignment in pixels for pitch/height/depth and bytes for base */ |
static int r600_get_array_mode_alignment(struct array_mode_checker *values, |
u32 *pitch_align, |
u32 *height_align, |
u32 *depth_align, |
u64 *base_align) |
{ |
u32 tile_width = 8; |
u32 tile_height = 8; |
u32 macro_tile_width = values->nbanks; |
u32 macro_tile_height = values->npipes; |
u32 tile_bytes = tile_width * tile_height * values->blocksize * values->nsamples; |
u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes; |
switch (values->array_mode) { |
case ARRAY_LINEAR_GENERAL: |
/* technically tile_width/_height for pitch/height */ |
*pitch_align = 1; /* tile_width */ |
*height_align = 1; /* tile_height */ |
*depth_align = 1; |
*base_align = 1; |
break; |
case ARRAY_LINEAR_ALIGNED: |
*pitch_align = max((u32)64, (u32)(values->group_size / values->blocksize)); |
*height_align = 1; |
*depth_align = 1; |
*base_align = values->group_size; |
break; |
case ARRAY_1D_TILED_THIN1: |
*pitch_align = max((u32)tile_width, |
(u32)(values->group_size / |
(tile_height * values->blocksize * values->nsamples))); |
*height_align = tile_height; |
*depth_align = 1; |
*base_align = values->group_size; |
break; |
case ARRAY_2D_TILED_THIN1: |
*pitch_align = max((u32)macro_tile_width * tile_width, |
(u32)((values->group_size * values->nbanks) / |
(values->blocksize * values->nsamples * tile_width))); |
*height_align = macro_tile_height * tile_height; |
*depth_align = 1; |
*base_align = max(macro_tile_bytes, |
(*pitch_align) * values->blocksize * (*height_align) * values->nsamples); |
break; |
default: |
return -EINVAL; |
} |
return 0; |
} |
static void r600_cs_track_init(struct r600_cs_track *track) |
{ |
int i; |
/* assume DX9 mode */ |
track->sq_config = DX9_CONSTS; |
for (i = 0; i < 8; i++) { |
track->cb_color_base_last[i] = 0; |
track->cb_color_size[i] = 0; |
track->cb_color_size_idx[i] = 0; |
track->cb_color_info[i] = 0; |
track->cb_color_view[i] = 0xFFFFFFFF; |
track->cb_color_bo[i] = NULL; |
track->cb_color_bo_offset[i] = 0xFFFFFFFF; |
track->cb_color_bo_mc[i] = 0xFFFFFFFF; |
track->cb_color_frag_bo[i] = NULL; |
track->cb_color_frag_offset[i] = 0xFFFFFFFF; |
track->cb_color_tile_bo[i] = NULL; |
track->cb_color_tile_offset[i] = 0xFFFFFFFF; |
track->cb_color_mask[i] = 0xFFFFFFFF; |
} |
track->is_resolve = false; |
track->nsamples = 16; |
track->log_nsamples = 4; |
track->cb_target_mask = 0xFFFFFFFF; |
track->cb_shader_mask = 0xFFFFFFFF; |
track->cb_dirty = true; |
track->db_bo = NULL; |
track->db_bo_mc = 0xFFFFFFFF; |
/* assume the biggest format and that htile is enabled */ |
track->db_depth_info = 7 | (1 << 25); |
track->db_depth_view = 0xFFFFC000; |
track->db_depth_size = 0xFFFFFFFF; |
track->db_depth_size_idx = 0; |
track->db_depth_control = 0xFFFFFFFF; |
track->db_dirty = true; |
track->htile_bo = NULL; |
track->htile_offset = 0xFFFFFFFF; |
track->htile_surface = 0; |
for (i = 0; i < 4; i++) { |
track->vgt_strmout_size[i] = 0; |
track->vgt_strmout_bo[i] = NULL; |
track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF; |
track->vgt_strmout_bo_mc[i] = 0xFFFFFFFF; |
} |
track->streamout_dirty = true; |
track->sx_misc_kill_all_prims = false; |
} |
static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) |
{ |
struct r600_cs_track *track = p->track; |
u32 slice_tile_max, size, tmp; |
u32 height, height_align, pitch, pitch_align, depth_align; |
u64 base_offset, base_align; |
struct array_mode_checker array_check; |
volatile u32 *ib = p->ib.ptr; |
unsigned array_mode; |
u32 format; |
/* When resolve is used, the second colorbuffer has always 1 sample. */ |
unsigned nsamples = track->is_resolve && i == 1 ? 1 : track->nsamples; |
size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i]; |
format = G_0280A0_FORMAT(track->cb_color_info[i]); |
if (!r600_fmt_is_valid_color(format)) { |
dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n", |
__func__, __LINE__, format, |
i, track->cb_color_info[i]); |
return -EINVAL; |
} |
/* pitch in pixels */ |
pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8; |
slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1; |
slice_tile_max *= 64; |
height = slice_tile_max / pitch; |
if (height > 8192) |
height = 8192; |
array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]); |
base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i]; |
array_check.array_mode = array_mode; |
array_check.group_size = track->group_size; |
array_check.nbanks = track->nbanks; |
array_check.npipes = track->npipes; |
array_check.nsamples = nsamples; |
array_check.blocksize = r600_fmt_get_blocksize(format); |
if (r600_get_array_mode_alignment(&array_check, |
&pitch_align, &height_align, &depth_align, &base_align)) { |
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, |
G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i, |
track->cb_color_info[i]); |
return -EINVAL; |
} |
switch (array_mode) { |
case V_0280A0_ARRAY_LINEAR_GENERAL: |
break; |
case V_0280A0_ARRAY_LINEAR_ALIGNED: |
break; |
case V_0280A0_ARRAY_1D_TILED_THIN1: |
/* avoid breaking userspace */ |
if (height > 7) |
height &= ~0x7; |
break; |
case V_0280A0_ARRAY_2D_TILED_THIN1: |
break; |
default: |
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, |
G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i, |
track->cb_color_info[i]); |
return -EINVAL; |
} |
if (!IS_ALIGNED(pitch, pitch_align)) { |
dev_warn(p->dev, "%s:%d cb pitch (%d, 0x%x, %d) invalid\n", |
__func__, __LINE__, pitch, pitch_align, array_mode); |
return -EINVAL; |
} |
if (!IS_ALIGNED(height, height_align)) { |
dev_warn(p->dev, "%s:%d cb height (%d, 0x%x, %d) invalid\n", |
__func__, __LINE__, height, height_align, array_mode); |
return -EINVAL; |
} |
if (!IS_ALIGNED(base_offset, base_align)) { |
dev_warn(p->dev, "%s offset[%d] 0x%llx 0x%llx, %d not aligned\n", __func__, i, |
base_offset, base_align, array_mode); |
return -EINVAL; |
} |
/* check offset */ |
tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) * |
r600_fmt_get_blocksize(format) * nsamples; |
switch (array_mode) { |
default: |
case V_0280A0_ARRAY_LINEAR_GENERAL: |
case V_0280A0_ARRAY_LINEAR_ALIGNED: |
tmp += track->cb_color_view[i] & 0xFF; |
break; |
case V_0280A0_ARRAY_1D_TILED_THIN1: |
case V_0280A0_ARRAY_2D_TILED_THIN1: |
tmp += G_028080_SLICE_MAX(track->cb_color_view[i]) * tmp; |
break; |
} |
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { |
if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) { |
/* the initial DDX does bad things with the CB size occasionally */ |
/* it rounds up height too far for slice tile max but the BO is smaller */ |
/* r600c,g also seem to flush at bad times in some apps resulting in |
* bogus values here. So for linear just allow anything to avoid breaking |
* broken userspace. |
*/ |
} else { |
dev_warn(p->dev, "%s offset[%d] %d %llu %d %lu too big (%d %d) (%d %d %d)\n", |
__func__, i, array_mode, |
track->cb_color_bo_offset[i], tmp, |
radeon_bo_size(track->cb_color_bo[i]), |
pitch, height, r600_fmt_get_nblocksx(format, pitch), |
r600_fmt_get_nblocksy(format, height), |
r600_fmt_get_blocksize(format)); |
return -EINVAL; |
} |
} |
/* limit max tile */ |
tmp = (height * pitch) >> 6; |
if (tmp < slice_tile_max) |
slice_tile_max = tmp; |
tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) | |
S_028060_SLICE_TILE_MAX(slice_tile_max - 1); |
ib[track->cb_color_size_idx[i]] = tmp; |
/* FMASK/CMASK */ |
switch (G_0280A0_TILE_MODE(track->cb_color_info[i])) { |
case V_0280A0_TILE_DISABLE: |
break; |
case V_0280A0_FRAG_ENABLE: |
if (track->nsamples > 1) { |
uint32_t tile_max = G_028100_FMASK_TILE_MAX(track->cb_color_mask[i]); |
/* the tile size is 8x8, but the size is in units of bits. |
* for bytes, do just * 8. */ |
uint32_t bytes = track->nsamples * track->log_nsamples * 8 * (tile_max + 1); |
if (bytes + track->cb_color_frag_offset[i] > |
radeon_bo_size(track->cb_color_frag_bo[i])) { |
dev_warn(p->dev, "%s FMASK_TILE_MAX too large " |
"(tile_max=%u, bytes=%u, offset=%llu, bo_size=%lu)\n", |
__func__, tile_max, bytes, |
track->cb_color_frag_offset[i], |
radeon_bo_size(track->cb_color_frag_bo[i])); |
return -EINVAL; |
} |
} |
/* fall through */ |
case V_0280A0_CLEAR_ENABLE: |
{ |
uint32_t block_max = G_028100_CMASK_BLOCK_MAX(track->cb_color_mask[i]); |
/* One block = 128x128 pixels, one 8x8 tile has 4 bits.. |
* (128*128) / (8*8) / 2 = 128 bytes per block. */ |
uint32_t bytes = (block_max + 1) * 128; |
if (bytes + track->cb_color_tile_offset[i] > |
radeon_bo_size(track->cb_color_tile_bo[i])) { |
dev_warn(p->dev, "%s CMASK_BLOCK_MAX too large " |
"(block_max=%u, bytes=%u, offset=%llu, bo_size=%lu)\n", |
__func__, block_max, bytes, |
track->cb_color_tile_offset[i], |
radeon_bo_size(track->cb_color_tile_bo[i])); |
return -EINVAL; |
} |
break; |
} |
default: |
dev_warn(p->dev, "%s invalid tile mode\n", __func__); |
return -EINVAL; |
} |
return 0; |
} |
static int r600_cs_track_validate_db(struct radeon_cs_parser *p) |
{ |
struct r600_cs_track *track = p->track; |
u32 nviews, bpe, ntiles, size, slice_tile_max, tmp; |
u32 height_align, pitch_align, depth_align; |
u32 pitch = 8192; |
u32 height = 8192; |
u64 base_offset, base_align; |
struct array_mode_checker array_check; |
int array_mode; |
volatile u32 *ib = p->ib.ptr; |
if (track->db_bo == NULL) { |
dev_warn(p->dev, "z/stencil with no depth buffer\n"); |
return -EINVAL; |
} |
switch (G_028010_FORMAT(track->db_depth_info)) { |
case V_028010_DEPTH_16: |
bpe = 2; |
break; |
case V_028010_DEPTH_X8_24: |
case V_028010_DEPTH_8_24: |
case V_028010_DEPTH_X8_24_FLOAT: |
case V_028010_DEPTH_8_24_FLOAT: |
case V_028010_DEPTH_32_FLOAT: |
bpe = 4; |
break; |
case V_028010_DEPTH_X24_8_32_FLOAT: |
bpe = 8; |
break; |
default: |
dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info)); |
return -EINVAL; |
} |
if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) { |
if (!track->db_depth_size_idx) { |
dev_warn(p->dev, "z/stencil buffer size not set\n"); |
return -EINVAL; |
} |
tmp = radeon_bo_size(track->db_bo) - track->db_offset; |
tmp = (tmp / bpe) >> 6; |
if (!tmp) { |
dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n", |
track->db_depth_size, bpe, track->db_offset, |
radeon_bo_size(track->db_bo)); |
return -EINVAL; |
} |
ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF); |
} else { |
size = radeon_bo_size(track->db_bo); |
/* pitch in pixels */ |
pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8; |
slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; |
slice_tile_max *= 64; |
height = slice_tile_max / pitch; |
if (height > 8192) |
height = 8192; |
base_offset = track->db_bo_mc + track->db_offset; |
array_mode = G_028010_ARRAY_MODE(track->db_depth_info); |
array_check.array_mode = array_mode; |
array_check.group_size = track->group_size; |
array_check.nbanks = track->nbanks; |
array_check.npipes = track->npipes; |
array_check.nsamples = track->nsamples; |
array_check.blocksize = bpe; |
if (r600_get_array_mode_alignment(&array_check, |
&pitch_align, &height_align, &depth_align, &base_align)) { |
dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, |
G_028010_ARRAY_MODE(track->db_depth_info), |
track->db_depth_info); |
return -EINVAL; |
} |
switch (array_mode) { |
case V_028010_ARRAY_1D_TILED_THIN1: |
/* don't break userspace */ |
height &= ~0x7; |
break; |
case V_028010_ARRAY_2D_TILED_THIN1: |
break; |
default: |
dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, |
G_028010_ARRAY_MODE(track->db_depth_info), |
track->db_depth_info); |
return -EINVAL; |
} |
if (!IS_ALIGNED(pitch, pitch_align)) { |
dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n", |
__func__, __LINE__, pitch, pitch_align, array_mode); |
return -EINVAL; |
} |
if (!IS_ALIGNED(height, height_align)) { |
dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n", |
__func__, __LINE__, height, height_align, array_mode); |
return -EINVAL; |
} |
if (!IS_ALIGNED(base_offset, base_align)) { |
dev_warn(p->dev, "%s offset 0x%llx, 0x%llx, %d not aligned\n", __func__, |
base_offset, base_align, array_mode); |
return -EINVAL; |
} |
ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; |
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1; |
tmp = ntiles * bpe * 64 * nviews * track->nsamples; |
if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) { |
dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n", |
array_mode, |
track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset, |
radeon_bo_size(track->db_bo)); |
return -EINVAL; |
} |
} |
/* hyperz */ |
if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) { |
unsigned long size; |
unsigned nbx, nby; |
if (track->htile_bo == NULL) { |
dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n", |
__func__, __LINE__, track->db_depth_info); |
return -EINVAL; |
} |
if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) { |
dev_warn(p->dev, "%s:%d htile can't be enabled with bogus db_depth_size 0x%08x\n", |
__func__, __LINE__, track->db_depth_size); |
return -EINVAL; |
} |
nbx = pitch; |
nby = height; |
if (G_028D24_LINEAR(track->htile_surface)) { |
/* nbx must be 16 htiles aligned == 16 * 8 pixel aligned */ |
nbx = round_up(nbx, 16 * 8); |
/* nby is npipes htiles aligned == npipes * 8 pixel aligned */ |
nby = round_up(nby, track->npipes * 8); |
} else { |
/* always assume 8x8 htile */ |
/* align is htile align * 8, htile align vary according to |
* number of pipe and tile width and nby |
*/ |
switch (track->npipes) { |
case 8: |
/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/ |
nbx = round_up(nbx, 64 * 8); |
nby = round_up(nby, 64 * 8); |
break; |
case 4: |
/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/ |
nbx = round_up(nbx, 64 * 8); |
nby = round_up(nby, 32 * 8); |
break; |
case 2: |
/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/ |
nbx = round_up(nbx, 32 * 8); |
nby = round_up(nby, 32 * 8); |
break; |
case 1: |
/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/ |
nbx = round_up(nbx, 32 * 8); |
nby = round_up(nby, 16 * 8); |
break; |
default: |
dev_warn(p->dev, "%s:%d invalid num pipes %d\n", |
__func__, __LINE__, track->npipes); |
return -EINVAL; |
} |
} |
/* compute number of htile */ |
nbx = nbx >> 3; |
nby = nby >> 3; |
/* size must be aligned on npipes * 2K boundary */ |
size = roundup(nbx * nby * 4, track->npipes * (2 << 10)); |
size += track->htile_offset; |
if (size > radeon_bo_size(track->htile_bo)) { |
dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n", |
__func__, __LINE__, radeon_bo_size(track->htile_bo), |
size, nbx, nby); |
return -EINVAL; |
} |
} |
track->db_dirty = false; |
return 0; |
} |
static int r600_cs_track_check(struct radeon_cs_parser *p) |
{ |
struct r600_cs_track *track = p->track; |
u32 tmp; |
int r, i; |
/* on legacy kernel we don't perform advanced check */ |
if (p->rdev == NULL) |
return 0; |
/* check streamout */ |
if (track->streamout_dirty && track->vgt_strmout_en) { |
for (i = 0; i < 4; i++) { |
if (track->vgt_strmout_buffer_en & (1 << i)) { |
if (track->vgt_strmout_bo[i]) { |
u64 offset = (u64)track->vgt_strmout_bo_offset[i] + |
(u64)track->vgt_strmout_size[i]; |
if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) { |
DRM_ERROR("streamout %d bo too small: 0x%llx, 0x%lx\n", |
i, offset, |
radeon_bo_size(track->vgt_strmout_bo[i])); |
return -EINVAL; |
} |
} else { |
dev_warn(p->dev, "No buffer for streamout %d\n", i); |
return -EINVAL; |
} |
} |
} |
track->streamout_dirty = false; |
} |
if (track->sx_misc_kill_all_prims) |
return 0; |
/* check that we have a cb for each enabled target, we don't check |
* shader_mask because it seems mesa isn't always setting it :( |
*/ |
if (track->cb_dirty) { |
tmp = track->cb_target_mask; |
/* We must check both colorbuffers for RESOLVE. */ |
if (track->is_resolve) { |
tmp |= 0xff; |
} |
for (i = 0; i < 8; i++) { |
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", |
__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i); |
return -EINVAL; |
} |
/* perform rewrite of CB_COLOR[0-7]_SIZE */ |
r = r600_cs_track_validate_cb(p, i); |
if (r) |
return r; |
} |
} |
track->cb_dirty = false; |
} |
/* Check depth buffer */ |
if (track->db_dirty && |
G_028010_FORMAT(track->db_depth_info) != V_028010_DEPTH_INVALID && |
(G_028800_STENCIL_ENABLE(track->db_depth_control) || |
G_028800_Z_ENABLE(track->db_depth_control))) { |
r = r600_cs_track_validate_db(p); |
if (r) |
return r; |
} |
return 0; |
} |
/** |
* r600_cs_packet_parse_vline() - parse userspace VLINE packet |
* @parser: parser structure holding parsing context. |
* |
* This is an R600-specific function for parsing VLINE packets. |
* Real work is done by r600_cs_common_vline_parse function. |
* Here we just set up ASIC-specific register table and call |
* the common implementation function. |
*/ |
static int r600_cs_packet_parse_vline(struct radeon_cs_parser *p) |
{ |
static uint32_t vline_start_end[2] = {AVIVO_D1MODE_VLINE_START_END, |
AVIVO_D2MODE_VLINE_START_END}; |
static uint32_t vline_status[2] = {AVIVO_D1MODE_VLINE_STATUS, |
AVIVO_D2MODE_VLINE_STATUS}; |
return r600_cs_common_vline_parse(p, vline_start_end, vline_status); |
} |
/** |
* r600_cs_common_vline_parse() - common vline parser |
* @parser: parser structure holding parsing context. |
* @vline_start_end: table of vline_start_end registers |
* @vline_status: table of vline_status registers |
* |
* Userspace sends a special sequence for VLINE waits. |
* PACKET0 - VLINE_START_END + value |
* PACKET3 - WAIT_REG_MEM poll vline status reg |
* RELOC (P3) - crtc_id in reloc. |
* |
* This function parses this and relocates the VLINE START END |
* and WAIT_REG_MEM packets to the correct crtc. |
* It also detects a switched off crtc and nulls out the |
* wait in that case. This function is common for all ASICs that |
* are R600 and newer. The parsing algorithm is the same, and only |
* differs in which registers are used. |
* |
* Caller is the ASIC-specific function which passes the parser |
* context and ASIC-specific register table |
*/ |
int r600_cs_common_vline_parse(struct radeon_cs_parser *p, |
uint32_t *vline_start_end, |
uint32_t *vline_status) |
{ |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
struct radeon_cs_packet p3reloc, wait_reg_mem; |
int crtc_id; |
int r; |
uint32_t header, h_idx, reg, wait_reg_mem_info; |
volatile uint32_t *ib; |
ib = p->ib.ptr; |
/* parse the WAIT_REG_MEM */ |
r = radeon_cs_packet_parse(p, &wait_reg_mem, p->idx); |
if (r) |
return r; |
/* check its a WAIT_REG_MEM */ |
if (wait_reg_mem.type != RADEON_PACKET_TYPE3 || |
wait_reg_mem.opcode != PACKET3_WAIT_REG_MEM) { |
DRM_ERROR("vline wait missing WAIT_REG_MEM segment\n"); |
return -EINVAL; |
} |
wait_reg_mem_info = radeon_get_ib_value(p, wait_reg_mem.idx + 1); |
/* bit 4 is reg (0) or mem (1) */ |
if (wait_reg_mem_info & 0x10) { |
DRM_ERROR("vline WAIT_REG_MEM waiting on MEM instead of REG\n"); |
return -EINVAL; |
} |
/* bit 8 is me (0) or pfp (1) */ |
if (wait_reg_mem_info & 0x100) { |
DRM_ERROR("vline WAIT_REG_MEM waiting on PFP instead of ME\n"); |
return -EINVAL; |
} |
/* waiting for value to be equal */ |
if ((wait_reg_mem_info & 0x7) != 0x3) { |
DRM_ERROR("vline WAIT_REG_MEM function not equal\n"); |
return -EINVAL; |
} |
if ((radeon_get_ib_value(p, wait_reg_mem.idx + 2) << 2) != vline_status[0]) { |
DRM_ERROR("vline WAIT_REG_MEM bad reg\n"); |
return -EINVAL; |
} |
if (radeon_get_ib_value(p, wait_reg_mem.idx + 5) != RADEON_VLINE_STAT) { |
DRM_ERROR("vline WAIT_REG_MEM bad bit mask\n"); |
return -EINVAL; |
} |
/* jump over the NOP */ |
r = radeon_cs_packet_parse(p, &p3reloc, p->idx + wait_reg_mem.count + 2); |
if (r) |
return r; |
h_idx = p->idx - 2; |
p->idx += wait_reg_mem.count + 2; |
p->idx += p3reloc.count + 2; |
header = radeon_get_ib_value(p, h_idx); |
crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1); |
reg = R600_CP_PACKET0_GET_REG(header); |
crtc = drm_crtc_find(p->rdev->ddev, crtc_id); |
if (!crtc) { |
DRM_ERROR("cannot find crtc %d\n", crtc_id); |
return -ENOENT; |
} |
radeon_crtc = to_radeon_crtc(crtc); |
crtc_id = radeon_crtc->crtc_id; |
if (!crtc->enabled) { |
/* CRTC isn't enabled - we need to nop out the WAIT_REG_MEM */ |
ib[h_idx + 2] = PACKET2(0); |
ib[h_idx + 3] = PACKET2(0); |
ib[h_idx + 4] = PACKET2(0); |
ib[h_idx + 5] = PACKET2(0); |
ib[h_idx + 6] = PACKET2(0); |
ib[h_idx + 7] = PACKET2(0); |
ib[h_idx + 8] = PACKET2(0); |
} else if (reg == vline_start_end[0]) { |
header &= ~R600_CP_PACKET0_REG_MASK; |
header |= vline_start_end[crtc_id] >> 2; |
ib[h_idx] = header; |
ib[h_idx + 4] = vline_status[crtc_id] >> 2; |
} else { |
DRM_ERROR("unknown crtc reloc\n"); |
return -EINVAL; |
} |
return 0; |
} |
static int r600_packet0_check(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
unsigned idx, unsigned reg) |
{ |
int r; |
switch (reg) { |
case AVIVO_D1MODE_VLINE_START_END: |
r = r600_cs_packet_parse_vline(p); |
if (r) { |
DRM_ERROR("No reloc for ib[%d]=0x%04X\n", |
idx, reg); |
return r; |
} |
break; |
default: |
printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", |
reg, idx); |
return -EINVAL; |
} |
return 0; |
} |
static int r600_cs_parse_packet0(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt) |
{ |
unsigned reg, i; |
unsigned idx; |
int r; |
idx = pkt->idx + 1; |
reg = pkt->reg; |
for (i = 0; i <= pkt->count; i++, idx++, reg += 4) { |
r = r600_packet0_check(p, pkt, idx, reg); |
if (r) { |
return r; |
} |
} |
return 0; |
} |
/** |
* r600_cs_check_reg() - check if register is authorized or not |
* @parser: parser structure holding parsing context |
* @reg: register we are testing |
* @idx: index into the cs buffer |
* |
* This function will test against r600_reg_safe_bm and return 0 |
* if register is safe. If register is not flag as safe this function |
* will test it against a list of register needind special handling. |
*/ |
static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) |
{ |
struct r600_cs_track *track = (struct r600_cs_track *)p->track; |
struct radeon_cs_reloc *reloc; |
u32 m, i, tmp, *ib; |
int r; |
i = (reg >> 7); |
if (i >= ARRAY_SIZE(r600_reg_safe_bm)) { |
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); |
return -EINVAL; |
} |
m = 1 << ((reg >> 2) & 31); |
if (!(r600_reg_safe_bm[i] & m)) |
return 0; |
ib = p->ib.ptr; |
switch (reg) { |
/* force following reg to 0 in an attempt to disable out buffer |
* which will need us to better understand how it works to perform |
* security check on it (Jerome) |
*/ |
case R_0288A8_SQ_ESGS_RING_ITEMSIZE: |
case R_008C44_SQ_ESGS_RING_SIZE: |
case R_0288B0_SQ_ESTMP_RING_ITEMSIZE: |
case R_008C54_SQ_ESTMP_RING_SIZE: |
case R_0288C0_SQ_FBUF_RING_ITEMSIZE: |
case R_008C74_SQ_FBUF_RING_SIZE: |
case R_0288B4_SQ_GSTMP_RING_ITEMSIZE: |
case R_008C5C_SQ_GSTMP_RING_SIZE: |
case R_0288AC_SQ_GSVS_RING_ITEMSIZE: |
case R_008C4C_SQ_GSVS_RING_SIZE: |
case R_0288BC_SQ_PSTMP_RING_ITEMSIZE: |
case R_008C6C_SQ_PSTMP_RING_SIZE: |
case R_0288C4_SQ_REDUC_RING_ITEMSIZE: |
case R_008C7C_SQ_REDUC_RING_SIZE: |
case R_0288B8_SQ_VSTMP_RING_ITEMSIZE: |
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;*/ |
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); |
break; |
case R_028800_DB_DEPTH_CONTROL: |
track->db_depth_control = radeon_get_ib_value(p, idx); |
track->db_dirty = true; |
break; |
case R_028010_DB_DEPTH_INFO: |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS) && |
radeon_cs_packet_next_is_pkt3_nop(p)) { |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
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->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 { |
ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1); |
track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1); |
} |
} else { |
track->db_depth_info = radeon_get_ib_value(p, idx); |
} |
track->db_dirty = true; |
break; |
case R_028004_DB_DEPTH_VIEW: |
track->db_depth_view = radeon_get_ib_value(p, idx); |
track->db_dirty = true; |
break; |
case R_028000_DB_DEPTH_SIZE: |
track->db_depth_size = radeon_get_ib_value(p, idx); |
track->db_depth_size_idx = idx; |
track->db_dirty = true; |
break; |
case R_028AB0_VGT_STRMOUT_EN: |
track->vgt_strmout_en = radeon_get_ib_value(p, idx); |
track->streamout_dirty = true; |
break; |
case R_028B20_VGT_STRMOUT_BUFFER_EN: |
track->vgt_strmout_buffer_en = radeon_get_ib_value(p, idx); |
track->streamout_dirty = true; |
break; |
case VGT_STRMOUT_BUFFER_BASE_0: |
case VGT_STRMOUT_BUFFER_BASE_1: |
case VGT_STRMOUT_BUFFER_BASE_2: |
case VGT_STRMOUT_BUFFER_BASE_3: |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
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->gpu_offset >> 8) & 0xffffffff); |
track->vgt_strmout_bo[tmp] = reloc->robj; |
track->vgt_strmout_bo_mc[tmp] = reloc->gpu_offset; |
track->streamout_dirty = true; |
break; |
case VGT_STRMOUT_BUFFER_SIZE_0: |
case VGT_STRMOUT_BUFFER_SIZE_1: |
case VGT_STRMOUT_BUFFER_SIZE_2: |
case VGT_STRMOUT_BUFFER_SIZE_3: |
tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16; |
/* size in register is DWs, convert to bytes */ |
track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4; |
track->streamout_dirty = true; |
break; |
case CP_COHER_BASE: |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_warn(p->dev, "missing reloc for CP_COHER_BASE " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
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); |
track->cb_dirty = true; |
break; |
case R_02823C_CB_SHADER_MASK: |
track->cb_shader_mask = radeon_get_ib_value(p, idx); |
break; |
case R_028C04_PA_SC_AA_CONFIG: |
tmp = G_028C04_MSAA_NUM_SAMPLES(radeon_get_ib_value(p, idx)); |
track->log_nsamples = tmp; |
track->nsamples = 1 << tmp; |
track->cb_dirty = true; |
break; |
case R_028808_CB_COLOR_CONTROL: |
tmp = G_028808_SPECIAL_OP(radeon_get_ib_value(p, idx)); |
track->is_resolve = tmp == V_028808_SPECIAL_RESOLVE_BOX; |
track->cb_dirty = true; |
break; |
case R_0280A0_CB_COLOR0_INFO: |
case R_0280A4_CB_COLOR1_INFO: |
case R_0280A8_CB_COLOR2_INFO: |
case R_0280AC_CB_COLOR3_INFO: |
case R_0280B0_CB_COLOR4_INFO: |
case R_0280B4_CB_COLOR5_INFO: |
case R_0280B8_CB_COLOR6_INFO: |
case R_0280BC_CB_COLOR7_INFO: |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS) && |
radeon_cs_packet_next_is_pkt3_nop(p)) { |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); |
return -EINVAL; |
} |
tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4; |
track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); |
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->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); |
} |
} else { |
tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4; |
track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); |
} |
track->cb_dirty = true; |
break; |
case R_028080_CB_COLOR0_VIEW: |
case R_028084_CB_COLOR1_VIEW: |
case R_028088_CB_COLOR2_VIEW: |
case R_02808C_CB_COLOR3_VIEW: |
case R_028090_CB_COLOR4_VIEW: |
case R_028094_CB_COLOR5_VIEW: |
case R_028098_CB_COLOR6_VIEW: |
case R_02809C_CB_COLOR7_VIEW: |
tmp = (reg - R_028080_CB_COLOR0_VIEW) / 4; |
track->cb_color_view[tmp] = radeon_get_ib_value(p, idx); |
track->cb_dirty = true; |
break; |
case R_028060_CB_COLOR0_SIZE: |
case R_028064_CB_COLOR1_SIZE: |
case R_028068_CB_COLOR2_SIZE: |
case R_02806C_CB_COLOR3_SIZE: |
case R_028070_CB_COLOR4_SIZE: |
case R_028074_CB_COLOR5_SIZE: |
case R_028078_CB_COLOR6_SIZE: |
case R_02807C_CB_COLOR7_SIZE: |
tmp = (reg - R_028060_CB_COLOR0_SIZE) / 4; |
track->cb_color_size[tmp] = radeon_get_ib_value(p, idx); |
track->cb_color_size_idx[tmp] = idx; |
track->cb_dirty = true; |
break; |
/* This register were added late, there is userspace |
* which does provide relocation for those but set |
* 0 offset. In order to avoid breaking old userspace |
* we detect this and set address to point to last |
* CB_COLOR0_BASE, note that if userspace doesn't set |
* CB_COLOR0_BASE before this register we will report |
* error. Old userspace always set CB_COLOR0_BASE |
* before any of this. |
*/ |
case R_0280E0_CB_COLOR0_FRAG: |
case R_0280E4_CB_COLOR1_FRAG: |
case R_0280E8_CB_COLOR2_FRAG: |
case R_0280EC_CB_COLOR3_FRAG: |
case R_0280F0_CB_COLOR4_FRAG: |
case R_0280F4_CB_COLOR5_FRAG: |
case R_0280F8_CB_COLOR6_FRAG: |
case R_0280FC_CB_COLOR7_FRAG: |
tmp = (reg - R_0280E0_CB_COLOR0_FRAG) / 4; |
if (!radeon_cs_packet_next_is_pkt3_nop(p)) { |
if (!track->cb_color_base_last[tmp]) { |
dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg); |
return -EINVAL; |
} |
track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp]; |
track->cb_color_frag_offset[tmp] = track->cb_color_bo_offset[tmp]; |
ib[idx] = track->cb_color_base_last[tmp]; |
} else { |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); |
return -EINVAL; |
} |
track->cb_color_frag_bo[tmp] = reloc->robj; |
track->cb_color_frag_offset[tmp] = (u64)ib[idx] << 8; |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
} |
if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) { |
track->cb_dirty = true; |
} |
break; |
case R_0280C0_CB_COLOR0_TILE: |
case R_0280C4_CB_COLOR1_TILE: |
case R_0280C8_CB_COLOR2_TILE: |
case R_0280CC_CB_COLOR3_TILE: |
case R_0280D0_CB_COLOR4_TILE: |
case R_0280D4_CB_COLOR5_TILE: |
case R_0280D8_CB_COLOR6_TILE: |
case R_0280DC_CB_COLOR7_TILE: |
tmp = (reg - R_0280C0_CB_COLOR0_TILE) / 4; |
if (!radeon_cs_packet_next_is_pkt3_nop(p)) { |
if (!track->cb_color_base_last[tmp]) { |
dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg); |
return -EINVAL; |
} |
track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp]; |
track->cb_color_tile_offset[tmp] = track->cb_color_bo_offset[tmp]; |
ib[idx] = track->cb_color_base_last[tmp]; |
} else { |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); |
return -EINVAL; |
} |
track->cb_color_tile_bo[tmp] = reloc->robj; |
track->cb_color_tile_offset[tmp] = (u64)ib[idx] << 8; |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
} |
if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) { |
track->cb_dirty = true; |
} |
break; |
case R_028100_CB_COLOR0_MASK: |
case R_028104_CB_COLOR1_MASK: |
case R_028108_CB_COLOR2_MASK: |
case R_02810C_CB_COLOR3_MASK: |
case R_028110_CB_COLOR4_MASK: |
case R_028114_CB_COLOR5_MASK: |
case R_028118_CB_COLOR6_MASK: |
case R_02811C_CB_COLOR7_MASK: |
tmp = (reg - R_028100_CB_COLOR0_MASK) / 4; |
track->cb_color_mask[tmp] = radeon_get_ib_value(p, idx); |
if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) { |
track->cb_dirty = true; |
} |
break; |
case CB_COLOR0_BASE: |
case CB_COLOR1_BASE: |
case CB_COLOR2_BASE: |
case CB_COLOR3_BASE: |
case CB_COLOR4_BASE: |
case CB_COLOR5_BASE: |
case CB_COLOR6_BASE: |
case CB_COLOR7_BASE: |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
tmp = (reg - CB_COLOR0_BASE) / 4; |
track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8; |
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->gpu_offset; |
track->cb_dirty = true; |
break; |
case DB_DEPTH_BASE: |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
track->db_offset = radeon_get_ib_value(p, idx) << 8; |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->db_bo = reloc->robj; |
track->db_bo_mc = reloc->gpu_offset; |
track->db_dirty = true; |
break; |
case DB_HTILE_DATA_BASE: |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_warn(p->dev, "bad SET_CONTEXT_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
track->htile_offset = radeon_get_ib_value(p, idx) << 8; |
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
track->htile_bo = reloc->robj; |
track->db_dirty = true; |
break; |
case DB_HTILE_SURFACE: |
track->htile_surface = radeon_get_ib_value(p, idx); |
/* force 8x8 htile width and height */ |
ib[idx] |= 3; |
track->db_dirty = true; |
break; |
case SQ_PGM_START_FS: |
case SQ_PGM_START_ES: |
case SQ_PGM_START_VS: |
case SQ_PGM_START_GS: |
case SQ_PGM_START_PS: |
case SQ_ALU_CONST_CACHE_GS_0: |
case SQ_ALU_CONST_CACHE_GS_1: |
case SQ_ALU_CONST_CACHE_GS_2: |
case SQ_ALU_CONST_CACHE_GS_3: |
case SQ_ALU_CONST_CACHE_GS_4: |
case SQ_ALU_CONST_CACHE_GS_5: |
case SQ_ALU_CONST_CACHE_GS_6: |
case SQ_ALU_CONST_CACHE_GS_7: |
case SQ_ALU_CONST_CACHE_GS_8: |
case SQ_ALU_CONST_CACHE_GS_9: |
case SQ_ALU_CONST_CACHE_GS_10: |
case SQ_ALU_CONST_CACHE_GS_11: |
case SQ_ALU_CONST_CACHE_GS_12: |
case SQ_ALU_CONST_CACHE_GS_13: |
case SQ_ALU_CONST_CACHE_GS_14: |
case SQ_ALU_CONST_CACHE_GS_15: |
case SQ_ALU_CONST_CACHE_PS_0: |
case SQ_ALU_CONST_CACHE_PS_1: |
case SQ_ALU_CONST_CACHE_PS_2: |
case SQ_ALU_CONST_CACHE_PS_3: |
case SQ_ALU_CONST_CACHE_PS_4: |
case SQ_ALU_CONST_CACHE_PS_5: |
case SQ_ALU_CONST_CACHE_PS_6: |
case SQ_ALU_CONST_CACHE_PS_7: |
case SQ_ALU_CONST_CACHE_PS_8: |
case SQ_ALU_CONST_CACHE_PS_9: |
case SQ_ALU_CONST_CACHE_PS_10: |
case SQ_ALU_CONST_CACHE_PS_11: |
case SQ_ALU_CONST_CACHE_PS_12: |
case SQ_ALU_CONST_CACHE_PS_13: |
case SQ_ALU_CONST_CACHE_PS_14: |
case SQ_ALU_CONST_CACHE_PS_15: |
case SQ_ALU_CONST_CACHE_VS_0: |
case SQ_ALU_CONST_CACHE_VS_1: |
case SQ_ALU_CONST_CACHE_VS_2: |
case SQ_ALU_CONST_CACHE_VS_3: |
case SQ_ALU_CONST_CACHE_VS_4: |
case SQ_ALU_CONST_CACHE_VS_5: |
case SQ_ALU_CONST_CACHE_VS_6: |
case SQ_ALU_CONST_CACHE_VS_7: |
case SQ_ALU_CONST_CACHE_VS_8: |
case SQ_ALU_CONST_CACHE_VS_9: |
case SQ_ALU_CONST_CACHE_VS_10: |
case SQ_ALU_CONST_CACHE_VS_11: |
case SQ_ALU_CONST_CACHE_VS_12: |
case SQ_ALU_CONST_CACHE_VS_13: |
case SQ_ALU_CONST_CACHE_VS_14: |
case SQ_ALU_CONST_CACHE_VS_15: |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
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 SX_MEMORY_EXPORT_BASE: |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
dev_warn(p->dev, "bad SET_CONFIG_REG " |
"0x%04X\n", reg); |
return -EINVAL; |
} |
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; |
break; |
default: |
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); |
return -EINVAL; |
} |
return 0; |
} |
unsigned r600_mip_minify(unsigned size, unsigned level) |
{ |
unsigned val; |
val = max(1U, size >> level); |
if (level > 0) |
val = roundup_pow_of_two(val); |
return val; |
} |
static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned llevel, |
unsigned w0, unsigned h0, unsigned d0, unsigned nsamples, unsigned format, |
unsigned block_align, unsigned height_align, unsigned base_align, |
unsigned *l0_size, unsigned *mipmap_size) |
{ |
unsigned offset, i, level; |
unsigned width, height, depth, size; |
unsigned blocksize; |
unsigned nbx, nby; |
unsigned nlevels = llevel - blevel + 1; |
*l0_size = -1; |
blocksize = r600_fmt_get_blocksize(format); |
w0 = r600_mip_minify(w0, 0); |
h0 = r600_mip_minify(h0, 0); |
d0 = r600_mip_minify(d0, 0); |
for(i = 0, offset = 0, level = blevel; i < nlevels; i++, level++) { |
width = r600_mip_minify(w0, i); |
nbx = r600_fmt_get_nblocksx(format, width); |
nbx = round_up(nbx, block_align); |
height = r600_mip_minify(h0, i); |
nby = r600_fmt_get_nblocksy(format, height); |
nby = round_up(nby, height_align); |
depth = r600_mip_minify(d0, i); |
size = nbx * nby * blocksize * nsamples; |
if (nfaces) |
size *= nfaces; |
else |
size *= depth; |
if (i == 0) |
*l0_size = size; |
if (i == 0 || i == 1) |
offset = round_up(offset, base_align); |
offset += size; |
} |
*mipmap_size = offset; |
if (llevel == 0) |
*mipmap_size = *l0_size; |
if (!blevel) |
*mipmap_size -= *l0_size; |
} |
/** |
* r600_check_texture_resource() - check if register is authorized or not |
* @p: parser structure holding parsing context |
* @idx: index into the cs buffer |
* @texture: texture's bo structure |
* @mipmap: mipmap's bo structure |
* |
* This function will check that the resource has valid field and that |
* the texture and mipmap bo object are big enough to cover this resource. |
*/ |
static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx, |
struct radeon_bo *texture, |
struct radeon_bo *mipmap, |
u64 base_offset, |
u64 mip_offset, |
u32 tiling_flags) |
{ |
struct r600_cs_track *track = p->track; |
u32 dim, nfaces, llevel, blevel, w0, h0, d0; |
u32 word0, word1, l0_size, mipmap_size, word2, word3, word4, word5; |
u32 height_align, pitch, pitch_align, depth_align; |
u32 barray, larray; |
u64 base_align; |
struct array_mode_checker array_check; |
u32 format; |
bool is_array; |
/* on legacy kernel we don't perform advanced check */ |
if (p->rdev == NULL) |
return 0; |
/* convert to bytes */ |
base_offset <<= 8; |
mip_offset <<= 8; |
word0 = radeon_get_ib_value(p, idx + 0); |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { |
if (tiling_flags & RADEON_TILING_MACRO) |
word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); |
else if (tiling_flags & RADEON_TILING_MICRO) |
word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1); |
} |
word1 = radeon_get_ib_value(p, idx + 1); |
word2 = radeon_get_ib_value(p, idx + 2) << 8; |
word3 = radeon_get_ib_value(p, idx + 3) << 8; |
word4 = radeon_get_ib_value(p, idx + 4); |
word5 = radeon_get_ib_value(p, idx + 5); |
dim = G_038000_DIM(word0); |
w0 = G_038000_TEX_WIDTH(word0) + 1; |
pitch = (G_038000_PITCH(word0) + 1) * 8; |
h0 = G_038004_TEX_HEIGHT(word1) + 1; |
d0 = G_038004_TEX_DEPTH(word1); |
format = G_038004_DATA_FORMAT(word1); |
blevel = G_038010_BASE_LEVEL(word4); |
llevel = G_038014_LAST_LEVEL(word5); |
/* pitch in texels */ |
array_check.array_mode = G_038000_TILE_MODE(word0); |
array_check.group_size = track->group_size; |
array_check.nbanks = track->nbanks; |
array_check.npipes = track->npipes; |
array_check.nsamples = 1; |
array_check.blocksize = r600_fmt_get_blocksize(format); |
nfaces = 1; |
is_array = false; |
switch (dim) { |
case V_038000_SQ_TEX_DIM_1D: |
case V_038000_SQ_TEX_DIM_2D: |
case V_038000_SQ_TEX_DIM_3D: |
break; |
case V_038000_SQ_TEX_DIM_CUBEMAP: |
if (p->family >= CHIP_RV770) |
nfaces = 8; |
else |
nfaces = 6; |
break; |
case V_038000_SQ_TEX_DIM_1D_ARRAY: |
case V_038000_SQ_TEX_DIM_2D_ARRAY: |
is_array = true; |
break; |
case V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA: |
is_array = true; |
/* fall through */ |
case V_038000_SQ_TEX_DIM_2D_MSAA: |
array_check.nsamples = 1 << llevel; |
llevel = 0; |
break; |
default: |
dev_warn(p->dev, "this kernel doesn't support %d texture dim\n", G_038000_DIM(word0)); |
return -EINVAL; |
} |
if (!r600_fmt_is_valid_texture(format, p->family)) { |
dev_warn(p->dev, "%s:%d texture invalid format %d\n", |
__func__, __LINE__, format); |
return -EINVAL; |
} |
if (r600_get_array_mode_alignment(&array_check, |
&pitch_align, &height_align, &depth_align, &base_align)) { |
dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n", |
__func__, __LINE__, G_038000_TILE_MODE(word0)); |
return -EINVAL; |
} |
/* XXX check height as well... */ |
if (!IS_ALIGNED(pitch, pitch_align)) { |
dev_warn(p->dev, "%s:%d tex pitch (%d, 0x%x, %d) invalid\n", |
__func__, __LINE__, pitch, pitch_align, G_038000_TILE_MODE(word0)); |
return -EINVAL; |
} |
if (!IS_ALIGNED(base_offset, base_align)) { |
dev_warn(p->dev, "%s:%d tex base offset (0x%llx, 0x%llx, %d) invalid\n", |
__func__, __LINE__, base_offset, base_align, G_038000_TILE_MODE(word0)); |
return -EINVAL; |
} |
if (!IS_ALIGNED(mip_offset, base_align)) { |
dev_warn(p->dev, "%s:%d tex mip offset (0x%llx, 0x%llx, %d) invalid\n", |
__func__, __LINE__, mip_offset, base_align, G_038000_TILE_MODE(word0)); |
return -EINVAL; |
} |
if (blevel > llevel) { |
dev_warn(p->dev, "texture blevel %d > llevel %d\n", |
blevel, llevel); |
} |
if (is_array) { |
barray = G_038014_BASE_ARRAY(word5); |
larray = G_038014_LAST_ARRAY(word5); |
nfaces = larray - barray + 1; |
} |
r600_texture_size(nfaces, blevel, llevel, w0, h0, d0, array_check.nsamples, format, |
pitch_align, height_align, base_align, |
&l0_size, &mipmap_size); |
/* using get ib will give us the offset into the texture bo */ |
if ((l0_size + word2) > radeon_bo_size(texture)) { |
dev_warn(p->dev, "texture bo too small ((%d %d) (%d %d) %d %d %d -> %d have %ld)\n", |
w0, h0, pitch_align, height_align, |
array_check.array_mode, format, word2, |
l0_size, radeon_bo_size(texture)); |
dev_warn(p->dev, "alignments %d %d %d %lld\n", pitch, pitch_align, height_align, base_align); |
return -EINVAL; |
} |
/* using get ib will give us the offset into the mipmap bo */ |
if ((mipmap_size + word3) > radeon_bo_size(mipmap)) { |
/*dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n", |
w0, h0, format, blevel, nlevels, word3, mipmap_size, radeon_bo_size(texture));*/ |
} |
return 0; |
} |
static bool r600_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) |
{ |
u32 m, i; |
i = (reg >> 7); |
if (i >= ARRAY_SIZE(r600_reg_safe_bm)) { |
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); |
return false; |
} |
m = 1 << ((reg >> 2) & 31); |
if (!(r600_reg_safe_bm[i] & m)) |
return true; |
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); |
return false; |
} |
static int r600_packet3_check(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt) |
{ |
struct radeon_cs_reloc *reloc; |
struct r600_cs_track *track; |
volatile u32 *ib; |
unsigned idx; |
unsigned i; |
unsigned start_reg, end_reg, reg; |
int r; |
u32 idx_value; |
track = (struct r600_cs_track *)p->track; |
ib = p->ib.ptr; |
idx = pkt->idx + 1; |
idx_value = radeon_get_ib_value(p, idx); |
switch (pkt->opcode) { |
case PACKET3_SET_PREDICATION: |
{ |
int pred_op; |
int tmp; |
uint64_t offset; |
if (pkt->count != 1) { |
DRM_ERROR("bad SET PREDICATION\n"); |
return -EINVAL; |
} |
tmp = radeon_get_ib_value(p, idx + 1); |
pred_op = (tmp >> 16) & 0x7; |
/* for the clear predicate operation */ |
if (pred_op == 0) |
return 0; |
if (pred_op > 2) { |
DRM_ERROR("bad SET PREDICATION operation %d\n", pred_op); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad SET PREDICATION\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(idx_value & 0xfffffff0) + |
((u64)(tmp & 0xff) << 32); |
ib[idx + 0] = offset; |
ib[idx + 1] = (tmp & 0xffffff00) | (upper_32_bits(offset) & 0xff); |
} |
break; |
case PACKET3_START_3D_CMDBUF: |
if (p->family >= CHIP_RV770 || pkt->count) { |
DRM_ERROR("bad START_3D\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_CONTEXT_CONTROL: |
if (pkt->count != 1) { |
DRM_ERROR("bad CONTEXT_CONTROL\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_INDEX_TYPE: |
case PACKET3_NUM_INSTANCES: |
if (pkt->count) { |
DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_DRAW_INDEX: |
{ |
uint64_t offset; |
if (pkt->count != 3) { |
DRM_ERROR("bad DRAW_INDEX\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad DRAW_INDEX\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
idx_value + |
((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); |
ib[idx+0] = offset; |
ib[idx+1] = upper_32_bits(offset) & 0xff; |
r = r600_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); |
return r; |
} |
break; |
} |
case PACKET3_DRAW_INDEX_AUTO: |
if (pkt->count != 1) { |
DRM_ERROR("bad DRAW_INDEX_AUTO\n"); |
return -EINVAL; |
} |
r = r600_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx); |
return r; |
} |
break; |
case PACKET3_DRAW_INDEX_IMMD_BE: |
case PACKET3_DRAW_INDEX_IMMD: |
if (pkt->count < 2) { |
DRM_ERROR("bad DRAW_INDEX_IMMD\n"); |
return -EINVAL; |
} |
r = r600_cs_track_check(p); |
if (r) { |
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); |
return r; |
} |
break; |
case PACKET3_WAIT_REG_MEM: |
if (pkt->count != 5) { |
DRM_ERROR("bad WAIT_REG_MEM\n"); |
return -EINVAL; |
} |
/* bit 4 is reg (0) or mem (1) */ |
if (idx_value & 0x10) { |
uint64_t offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad WAIT_REG_MEM\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(radeon_get_ib_value(p, idx+1) & 0xfffffff0) + |
((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); |
ib[idx+1] = (ib[idx+1] & 0x3) | (offset & 0xfffffff0); |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
} else if (idx_value & 0x100) { |
DRM_ERROR("cannot use PFP on REG wait\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_CP_DMA: |
{ |
u32 command, size; |
u64 offset, tmp; |
if (pkt->count != 4) { |
DRM_ERROR("bad CP DMA\n"); |
return -EINVAL; |
} |
command = radeon_get_ib_value(p, idx+4); |
size = command & 0x1fffff; |
if (command & PACKET3_CP_DMA_CMD_SAS) { |
/* src address space is register */ |
DRM_ERROR("CP DMA SAS not supported\n"); |
return -EINVAL; |
} else { |
if (command & PACKET3_CP_DMA_CMD_SAIC) { |
DRM_ERROR("CP DMA SAIC only supported for registers\n"); |
return -EINVAL; |
} |
/* src address space is memory */ |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad CP DMA SRC\n"); |
return -EINVAL; |
} |
tmp = radeon_get_ib_value(p, idx) + |
((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); |
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", |
tmp + size, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
ib[idx] = offset; |
ib[idx+1] = (ib[idx+1] & 0xffffff00) | (upper_32_bits(offset) & 0xff); |
} |
if (command & PACKET3_CP_DMA_CMD_DAS) { |
/* dst address space is register */ |
DRM_ERROR("CP DMA DAS not supported\n"); |
return -EINVAL; |
} else { |
/* dst address space is memory */ |
if (command & PACKET3_CP_DMA_CMD_DAIC) { |
DRM_ERROR("CP DMA DAIC only supported for registers\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad CP DMA DST\n"); |
return -EINVAL; |
} |
tmp = radeon_get_ib_value(p, idx+2) + |
((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32); |
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", |
tmp + size, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
ib[idx+2] = offset; |
ib[idx+3] = upper_32_bits(offset) & 0xff; |
} |
break; |
} |
case PACKET3_SURFACE_SYNC: |
if (pkt->count != 3) { |
DRM_ERROR("bad SURFACE_SYNC\n"); |
return -EINVAL; |
} |
/* 0xffffffff/0x0 is flush all cache flag */ |
if (radeon_get_ib_value(p, idx + 1) != 0xffffffff || |
radeon_get_ib_value(p, idx + 2) != 0) { |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad SURFACE_SYNC\n"); |
return -EINVAL; |
} |
ib[idx+2] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
} |
break; |
case PACKET3_EVENT_WRITE: |
if (pkt->count != 2 && pkt->count != 0) { |
DRM_ERROR("bad EVENT_WRITE\n"); |
return -EINVAL; |
} |
if (pkt->count) { |
uint64_t offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad EVENT_WRITE\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(radeon_get_ib_value(p, idx+1) & 0xfffffff8) + |
((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); |
ib[idx+1] = offset & 0xfffffff8; |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
} |
break; |
case PACKET3_EVENT_WRITE_EOP: |
{ |
uint64_t offset; |
if (pkt->count != 4) { |
DRM_ERROR("bad EVENT_WRITE_EOP\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad EVENT_WRITE\n"); |
return -EINVAL; |
} |
offset = reloc->gpu_offset + |
(radeon_get_ib_value(p, idx+1) & 0xfffffffc) + |
((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32); |
ib[idx+1] = offset & 0xfffffffc; |
ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff); |
break; |
} |
case PACKET3_SET_CONFIG_REG: |
start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_OFFSET; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_CONFIG_REG_OFFSET) || |
(start_reg >= PACKET3_SET_CONFIG_REG_END) || |
(end_reg >= PACKET3_SET_CONFIG_REG_END)) { |
DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n"); |
return -EINVAL; |
} |
for (i = 0; i < pkt->count; i++) { |
reg = start_reg + (4 * i); |
r = r600_cs_check_reg(p, reg, idx+1+i); |
if (r) |
return r; |
} |
break; |
case PACKET3_SET_CONTEXT_REG: |
start_reg = (idx_value << 2) + PACKET3_SET_CONTEXT_REG_OFFSET; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_CONTEXT_REG_OFFSET) || |
(start_reg >= PACKET3_SET_CONTEXT_REG_END) || |
(end_reg >= PACKET3_SET_CONTEXT_REG_END)) { |
DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n"); |
return -EINVAL; |
} |
for (i = 0; i < pkt->count; i++) { |
reg = start_reg + (4 * i); |
r = r600_cs_check_reg(p, reg, idx+1+i); |
if (r) |
return r; |
} |
break; |
case PACKET3_SET_RESOURCE: |
if (pkt->count % 7) { |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
start_reg = (idx_value << 2) + PACKET3_SET_RESOURCE_OFFSET; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_RESOURCE_OFFSET) || |
(start_reg >= PACKET3_SET_RESOURCE_END) || |
(end_reg >= PACKET3_SET_RESOURCE_END)) { |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
for (i = 0; i < (pkt->count / 7); i++) { |
struct radeon_bo *texture, *mipmap; |
u32 size, offset, base_offset, mip_offset; |
switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) { |
case SQ_TEX_VTX_VALID_TEXTURE: |
/* tex base */ |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
base_offset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { |
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->tiling_flags & RADEON_TILING_MICRO) |
ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1); |
} |
texture = reloc->robj; |
/* tex mip base */ |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
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->tiling_flags); |
if (r) |
return r; |
ib[idx+1+(i*7)+2] += base_offset; |
ib[idx+1+(i*7)+3] += mip_offset; |
break; |
case SQ_TEX_VTX_VALID_BUFFER: |
{ |
uint64_t offset64; |
/* vtx base */ |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+1+(i*7)+0); |
size = radeon_get_ib_value(p, idx+1+(i*7)+1) + 1; |
if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) { |
/* force size to size of the buffer */ |
dev_warn(p->dev, "vbo resource seems too big (%d) for the bo (%ld)\n", |
size + offset, radeon_bo_size(reloc->robj)); |
ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj) - 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); |
break; |
} |
case SQ_TEX_VTX_INVALID_TEXTURE: |
case SQ_TEX_VTX_INVALID_BUFFER: |
default: |
DRM_ERROR("bad SET_RESOURCE\n"); |
return -EINVAL; |
} |
} |
break; |
case PACKET3_SET_ALU_CONST: |
if (track->sq_config & DX9_CONSTS) { |
start_reg = (idx_value << 2) + PACKET3_SET_ALU_CONST_OFFSET; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_ALU_CONST_OFFSET) || |
(start_reg >= PACKET3_SET_ALU_CONST_END) || |
(end_reg >= PACKET3_SET_ALU_CONST_END)) { |
DRM_ERROR("bad SET_ALU_CONST\n"); |
return -EINVAL; |
} |
} |
break; |
case PACKET3_SET_BOOL_CONST: |
start_reg = (idx_value << 2) + PACKET3_SET_BOOL_CONST_OFFSET; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_BOOL_CONST_OFFSET) || |
(start_reg >= PACKET3_SET_BOOL_CONST_END) || |
(end_reg >= PACKET3_SET_BOOL_CONST_END)) { |
DRM_ERROR("bad SET_BOOL_CONST\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_SET_LOOP_CONST: |
start_reg = (idx_value << 2) + PACKET3_SET_LOOP_CONST_OFFSET; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_LOOP_CONST_OFFSET) || |
(start_reg >= PACKET3_SET_LOOP_CONST_END) || |
(end_reg >= PACKET3_SET_LOOP_CONST_END)) { |
DRM_ERROR("bad SET_LOOP_CONST\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_SET_CTL_CONST: |
start_reg = (idx_value << 2) + PACKET3_SET_CTL_CONST_OFFSET; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_CTL_CONST_OFFSET) || |
(start_reg >= PACKET3_SET_CTL_CONST_END) || |
(end_reg >= PACKET3_SET_CTL_CONST_END)) { |
DRM_ERROR("bad SET_CTL_CONST\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_SET_SAMPLER: |
if (pkt->count % 3) { |
DRM_ERROR("bad SET_SAMPLER\n"); |
return -EINVAL; |
} |
start_reg = (idx_value << 2) + PACKET3_SET_SAMPLER_OFFSET; |
end_reg = 4 * pkt->count + start_reg - 4; |
if ((start_reg < PACKET3_SET_SAMPLER_OFFSET) || |
(start_reg >= PACKET3_SET_SAMPLER_END) || |
(end_reg >= PACKET3_SET_SAMPLER_END)) { |
DRM_ERROR("bad SET_SAMPLER\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_STRMOUT_BASE_UPDATE: |
/* RS780 and RS880 also need this */ |
if (p->family < CHIP_RS780) { |
DRM_ERROR("STRMOUT_BASE_UPDATE only supported on 7xx\n"); |
return -EINVAL; |
} |
if (pkt->count != 1) { |
DRM_ERROR("bad STRMOUT_BASE_UPDATE packet count\n"); |
return -EINVAL; |
} |
if (idx_value > 3) { |
DRM_ERROR("bad STRMOUT_BASE_UPDATE index\n"); |
return -EINVAL; |
} |
{ |
u64 offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad STRMOUT_BASE_UPDATE reloc\n"); |
return -EINVAL; |
} |
if (reloc->robj != track->vgt_strmout_bo[idx_value]) { |
DRM_ERROR("bad STRMOUT_BASE_UPDATE, bo does not match\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+1) << 8; |
if (offset != track->vgt_strmout_bo_offset[idx_value]) { |
DRM_ERROR("bad STRMOUT_BASE_UPDATE, bo offset does not match: 0x%llx, 0x%x\n", |
offset, track->vgt_strmout_bo_offset[idx_value]); |
return -EINVAL; |
} |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad STRMOUT_BASE_UPDATE bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
ib[idx+1] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); |
} |
break; |
case PACKET3_SURFACE_BASE_UPDATE: |
if (p->family >= CHIP_RV770 || p->family == CHIP_R600) { |
DRM_ERROR("bad SURFACE_BASE_UPDATE\n"); |
return -EINVAL; |
} |
if (pkt->count) { |
DRM_ERROR("bad SURFACE_BASE_UPDATE\n"); |
return -EINVAL; |
} |
break; |
case PACKET3_STRMOUT_BUFFER_UPDATE: |
if (pkt->count != 4) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (invalid count)\n"); |
return -EINVAL; |
} |
/* Updating memory at DST_ADDRESS. */ |
if (idx_value & 0x1) { |
u64 offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing dst reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+1); |
offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE dst bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+1] = offset; |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
} |
/* Reading data from SRC_ADDRESS. */ |
if (((idx_value >> 1) & 0x3) == 2) { |
u64 offset; |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing src reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+3); |
offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad STRMOUT_BUFFER_UPDATE src bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+3] = offset; |
ib[idx+4] = upper_32_bits(offset) & 0xff; |
} |
break; |
case PACKET3_MEM_WRITE: |
{ |
u64 offset; |
if (pkt->count != 3) { |
DRM_ERROR("bad MEM_WRITE (invalid count)\n"); |
return -EINVAL; |
} |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad MEM_WRITE (missing reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+0); |
offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL; |
if (offset & 0x7) { |
DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n"); |
return -EINVAL; |
} |
if ((offset + 8) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n", |
offset + 8, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+0] = offset; |
ib[idx+1] = upper_32_bits(offset) & 0xff; |
break; |
} |
case PACKET3_COPY_DW: |
if (pkt->count != 4) { |
DRM_ERROR("bad COPY_DW (invalid count)\n"); |
return -EINVAL; |
} |
if (idx_value & 0x1) { |
u64 offset; |
/* SRC is memory. */ |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad COPY_DW (missing src reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+1); |
offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad COPY_DW src bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+1] = offset; |
ib[idx+2] = upper_32_bits(offset) & 0xff; |
} else { |
/* SRC is a reg. */ |
reg = radeon_get_ib_value(p, idx+1) << 2; |
if (!r600_is_safe_reg(p, reg, idx+1)) |
return -EINVAL; |
} |
if (idx_value & 0x2) { |
u64 offset; |
/* DST is memory. */ |
r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm); |
if (r) { |
DRM_ERROR("bad COPY_DW (missing dst reloc)\n"); |
return -EINVAL; |
} |
offset = radeon_get_ib_value(p, idx+3); |
offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
if ((offset + 4) > radeon_bo_size(reloc->robj)) { |
DRM_ERROR("bad COPY_DW dst bo too small: 0x%llx, 0x%lx\n", |
offset + 4, radeon_bo_size(reloc->robj)); |
return -EINVAL; |
} |
offset += reloc->gpu_offset; |
ib[idx+3] = offset; |
ib[idx+4] = upper_32_bits(offset) & 0xff; |
} else { |
/* DST is a reg. */ |
reg = radeon_get_ib_value(p, idx+3) << 2; |
if (!r600_is_safe_reg(p, reg, idx+3)) |
return -EINVAL; |
} |
break; |
case PACKET3_NOP: |
break; |
default: |
DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); |
return -EINVAL; |
} |
return 0; |
} |
int r600_cs_parse(struct radeon_cs_parser *p) |
{ |
struct radeon_cs_packet pkt; |
struct r600_cs_track *track; |
int r; |
if (p->track == NULL) { |
/* initialize tracker, we are in kms */ |
track = kzalloc(sizeof(*track), GFP_KERNEL); |
if (track == NULL) |
return -ENOMEM; |
r600_cs_track_init(track); |
if (p->rdev->family < CHIP_RV770) { |
track->npipes = p->rdev->config.r600.tiling_npipes; |
track->nbanks = p->rdev->config.r600.tiling_nbanks; |
track->group_size = p->rdev->config.r600.tiling_group_size; |
} else if (p->rdev->family <= CHIP_RV740) { |
track->npipes = p->rdev->config.rv770.tiling_npipes; |
track->nbanks = p->rdev->config.rv770.tiling_nbanks; |
track->group_size = p->rdev->config.rv770.tiling_group_size; |
} |
p->track = track; |
} |
do { |
r = radeon_cs_packet_parse(p, &pkt, p->idx); |
if (r) { |
kfree(p->track); |
p->track = NULL; |
return r; |
} |
p->idx += pkt.count + 2; |
switch (pkt.type) { |
case RADEON_PACKET_TYPE0: |
r = r600_cs_parse_packet0(p, &pkt); |
break; |
case RADEON_PACKET_TYPE2: |
break; |
case RADEON_PACKET_TYPE3: |
r = r600_packet3_check(p, &pkt); |
break; |
default: |
DRM_ERROR("Unknown packet type %d !\n", pkt.type); |
kfree(p->track); |
p->track = NULL; |
return -EINVAL; |
} |
if (r) { |
kfree(p->track); |
p->track = NULL; |
return r; |
} |
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); |
#if 0 |
for (r = 0; r < p->ib.length_dw; r++) { |
printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]); |
mdelay(1); |
} |
#endif |
kfree(p->track); |
p->track = NULL; |
return 0; |
} |
#ifdef CONFIG_DRM_RADEON_UMS |
/** |
* cs_parser_fini() - clean parser states |
* @parser: parser structure holding parsing context. |
* @error: error number |
* |
* If error is set than unvalidate buffer, otherwise just free memory |
* used by parsing context. |
**/ |
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++) |
drm_free_large(parser->chunks[i].kdata); |
kfree(parser->chunks); |
kfree(parser->chunks_array); |
} |
static int r600_cs_parser_relocs_legacy(struct radeon_cs_parser *p) |
{ |
if (p->chunk_relocs_idx == -1) { |
return 0; |
} |
p->relocs = kzalloc(sizeof(struct radeon_cs_reloc), GFP_KERNEL); |
if (p->relocs == NULL) { |
return -ENOMEM; |
} |
return 0; |
} |
int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp, |
unsigned family, u32 *ib, int *l) |
{ |
struct radeon_cs_parser parser; |
struct radeon_cs_chunk *ib_chunk; |
struct r600_cs_track *track; |
int r; |
/* initialize tracker */ |
track = kzalloc(sizeof(*track), GFP_KERNEL); |
if (track == NULL) |
return -ENOMEM; |
r600_cs_track_init(track); |
r600_cs_legacy_get_tiling_conf(dev, &track->npipes, &track->nbanks, &track->group_size); |
/* initialize parser */ |
memset(&parser, 0, sizeof(struct radeon_cs_parser)); |
parser.filp = filp; |
parser.dev = &dev->pdev->dev; |
parser.rdev = NULL; |
parser.family = family; |
parser.track = track; |
parser.ib.ptr = ib; |
r = radeon_cs_parser_init(&parser, data); |
if (r) { |
DRM_ERROR("Failed to initialize parser !\n"); |
r600_cs_parser_fini(&parser, r); |
return r; |
} |
r = r600_cs_parser_relocs_legacy(&parser); |
if (r) { |
DRM_ERROR("Failed to parse relocation !\n"); |
r600_cs_parser_fini(&parser, r); |
return r; |
} |
/* Copy the packet into the IB, the parser will read from the |
* input memory (cached) and write to the IB (which can be |
* uncached). */ |
ib_chunk = &parser.chunks[parser.chunk_ib_idx]; |
parser.ib.length_dw = ib_chunk->length_dw; |
*l = parser.ib.length_dw; |
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 = r600_cs_parse(&parser); |
if (r) { |
DRM_ERROR("Invalid command stream !\n"); |
r600_cs_parser_fini(&parser, r); |
return r; |
} |
r600_cs_parser_fini(&parser, r); |
return r; |
} |
void r600_cs_legacy_init(void) |
{ |
r600_nomm = 1; |
} |
#endif |
/* |
* DMA |
*/ |
/** |
* r600_dma_cs_next_reloc() - parse next reloc |
* @p: parser structure holding parsing context. |
* @cs_reloc: reloc informations |
* |
* Return the next reloc, do bo validation and compute |
* GPU offset using the provided start. |
**/ |
int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, |
struct radeon_cs_reloc **cs_reloc) |
{ |
struct radeon_cs_chunk *relocs_chunk; |
unsigned idx; |
*cs_reloc = NULL; |
if (p->chunk_relocs_idx == -1) { |
DRM_ERROR("No relocation chunk !\n"); |
return -EINVAL; |
} |
relocs_chunk = &p->chunks[p->chunk_relocs_idx]; |
idx = p->dma_reloc_idx; |
if (idx >= p->nrelocs) { |
DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", |
idx, p->nrelocs); |
return -EINVAL; |
} |
*cs_reloc = p->relocs_ptr[idx]; |
p->dma_reloc_idx++; |
return 0; |
} |
#define GET_DMA_CMD(h) (((h) & 0xf0000000) >> 28) |
#define GET_DMA_COUNT(h) ((h) & 0x0000ffff) |
#define GET_DMA_T(h) (((h) & 0x00800000) >> 23) |
/** |
* r600_dma_cs_parse() - parse the DMA IB |
* @p: parser structure holding parsing context. |
* |
* Parses the DMA IB from the CS ioctl and updates |
* the GPU addresses based on the reloc information and |
* checks for errors. (R6xx-R7xx) |
* Returns 0 for success and an error on failure. |
**/ |
int r600_dma_cs_parse(struct radeon_cs_parser *p) |
{ |
struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; |
struct radeon_cs_reloc *src_reloc, *dst_reloc; |
u32 header, cmd, count, tiled; |
volatile u32 *ib = p->ib.ptr; |
u32 idx, idx_value; |
u64 src_offset, dst_offset; |
int r; |
do { |
if (p->idx >= ib_chunk->length_dw) { |
DRM_ERROR("Can not parse packet at %d after CS end %d !\n", |
p->idx, ib_chunk->length_dw); |
return -EINVAL; |
} |
idx = p->idx; |
header = radeon_get_ib_value(p, idx); |
cmd = GET_DMA_CMD(header); |
count = GET_DMA_COUNT(header); |
tiled = GET_DMA_T(header); |
switch (cmd) { |
case DMA_PACKET_WRITE: |
r = r600_dma_cs_next_reloc(p, &dst_reloc); |
if (r) { |
DRM_ERROR("bad DMA_PACKET_WRITE\n"); |
return -EINVAL; |
} |
if (tiled) { |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_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->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)) { |
dev_warn(p->dev, "DMA write buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
break; |
case DMA_PACKET_COPY: |
r = r600_dma_cs_next_reloc(p, &src_reloc); |
if (r) { |
DRM_ERROR("bad DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
r = r600_dma_cs_next_reloc(p, &dst_reloc); |
if (r) { |
DRM_ERROR("bad DMA_PACKET_COPY\n"); |
return -EINVAL; |
} |
if (tiled) { |
idx_value = radeon_get_ib_value(p, idx + 2); |
/* detile bit */ |
if (idx_value & (1 << 31)) { |
/* tiled src, linear dst */ |
src_offset = radeon_get_ib_value(p, idx+1); |
src_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->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->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->gpu_offset >> 8); |
} |
p->idx += 7; |
} else { |
if (p->family >= CHIP_RV770) { |
src_offset = radeon_get_ib_value(p, idx+2); |
src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
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->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); |
src_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32; |
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->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; |
} |
} |
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
dev_warn(p->dev, "DMA copy src buffer too small (%llu %lu)\n", |
src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
return -EINVAL; |
} |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA write dst buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
break; |
case DMA_PACKET_CONSTANT_FILL: |
if (p->family < CHIP_RV770) { |
DRM_ERROR("Constant Fill is 7xx only !\n"); |
return -EINVAL; |
} |
r = r600_dma_cs_next_reloc(p, &dst_reloc); |
if (r) { |
DRM_ERROR("bad DMA_PACKET_WRITE\n"); |
return -EINVAL; |
} |
dst_offset = radeon_get_ib_value(p, idx+1); |
dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16; |
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n", |
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
return -EINVAL; |
} |
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: |
p->idx += 1; |
break; |
default: |
DRM_ERROR("Unknown packet type %d at %d !\n", cmd, idx); |
return -EINVAL; |
} |
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); |
#if 0 |
for (r = 0; r < p->ib->length_dw; r++) { |
printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]); |
mdelay(1); |
} |
#endif |
return 0; |
} |
/drivers/video/drm/radeon/r600_dma.c |
---|
0,0 → 1,500 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "radeon_asic.h" |
#include "r600d.h" |
u32 r600_gpu_check_soft_reset(struct radeon_device *rdev); |
/* |
* DMA |
* Starting with R600, the GPU has an asynchronous |
* DMA engine. The programming model is very similar |
* to the 3D engine (ring buffer, IBs, etc.), but the |
* DMA controller has it's own packet format that is |
* different form the PM4 format used by the 3D engine. |
* It supports copying data, writing embedded data, |
* solid fills, and a number of other things. It also |
* has support for tiling/detiling of buffers. |
*/ |
/** |
* r600_dma_get_rptr - get the current read pointer |
* |
* @rdev: radeon_device pointer |
* @ring: radeon ring pointer |
* |
* Get the current rptr from the hardware (r6xx+). |
*/ |
uint32_t r600_dma_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(DMA_RB_RPTR); |
return (rptr & 0x3fffc) >> 2; |
} |
/** |
* r600_dma_get_wptr - get the current write pointer |
* |
* @rdev: radeon_device pointer |
* @ring: radeon ring pointer |
* |
* Get the current wptr from the hardware (r6xx+). |
*/ |
uint32_t r600_dma_get_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
return (RREG32(DMA_RB_WPTR) & 0x3fffc) >> 2; |
} |
/** |
* r600_dma_set_wptr - commit the write pointer |
* |
* @rdev: radeon_device pointer |
* @ring: radeon ring pointer |
* |
* Write the wptr back to the hardware (r6xx+). |
*/ |
void r600_dma_set_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
WREG32(DMA_RB_WPTR, (ring->wptr << 2) & 0x3fffc); |
} |
/** |
* r600_dma_stop - stop the async dma engine |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engine (r6xx-evergreen). |
*/ |
void r600_dma_stop(struct radeon_device *rdev) |
{ |
u32 rb_cntl = RREG32(DMA_RB_CNTL); |
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); |
rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; |
} |
/** |
* r600_dma_resume - setup and start the async dma engine |
* |
* @rdev: radeon_device pointer |
* |
* Set up the DMA ring buffer and enable it. (r6xx-evergreen). |
* Returns 0 for success, error for failure. |
*/ |
int r600_dma_resume(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; |
u32 rb_cntl, dma_cntl, ib_cntl; |
u32 rb_bufsz; |
int r; |
/* Reset dma */ |
if (rdev->family >= CHIP_RV770) |
WREG32(SRBM_SOFT_RESET, RV770_SOFT_RESET_DMA); |
else |
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); |
RREG32(SRBM_SOFT_RESET); |
udelay(50); |
WREG32(SRBM_SOFT_RESET, 0); |
WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL, 0); |
WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL, 0); |
/* Set ring buffer size in dwords */ |
rb_bufsz = order_base_2(ring->ring_size / 4); |
rb_cntl = rb_bufsz << 1; |
#ifdef __BIG_ENDIAN |
rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE; |
#endif |
WREG32(DMA_RB_CNTL, rb_cntl); |
/* Initialize the ring buffer's read and write pointers */ |
WREG32(DMA_RB_RPTR, 0); |
WREG32(DMA_RB_WPTR, 0); |
/* set the wb address whether it's enabled or not */ |
WREG32(DMA_RB_RPTR_ADDR_HI, |
upper_32_bits(rdev->wb.gpu_addr + R600_WB_DMA_RPTR_OFFSET) & 0xFF); |
WREG32(DMA_RB_RPTR_ADDR_LO, |
((rdev->wb.gpu_addr + R600_WB_DMA_RPTR_OFFSET) & 0xFFFFFFFC)); |
if (rdev->wb.enabled) |
rb_cntl |= DMA_RPTR_WRITEBACK_ENABLE; |
WREG32(DMA_RB_BASE, ring->gpu_addr >> 8); |
/* enable DMA IBs */ |
ib_cntl = DMA_IB_ENABLE; |
#ifdef __BIG_ENDIAN |
ib_cntl |= DMA_IB_SWAP_ENABLE; |
#endif |
WREG32(DMA_IB_CNTL, ib_cntl); |
dma_cntl = RREG32(DMA_CNTL); |
dma_cntl &= ~CTXEMPTY_INT_ENABLE; |
WREG32(DMA_CNTL, dma_cntl); |
if (rdev->family >= CHIP_RV770) |
WREG32(DMA_MODE, 1); |
ring->wptr = 0; |
WREG32(DMA_RB_WPTR, ring->wptr << 2); |
WREG32(DMA_RB_CNTL, rb_cntl | DMA_RB_ENABLE); |
ring->ready = true; |
r = radeon_ring_test(rdev, R600_RING_TYPE_DMA_INDEX, ring); |
if (r) { |
ring->ready = false; |
return r; |
} |
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; |
} |
/** |
* r600_dma_fini - tear down the async dma engine |
* |
* @rdev: radeon_device pointer |
* |
* Stop the async dma engine and free the ring (r6xx-evergreen). |
*/ |
void r600_dma_fini(struct radeon_device *rdev) |
{ |
r600_dma_stop(rdev); |
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]); |
} |
/** |
* r600_dma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up. |
* Returns true if the engine appears to be locked up, false if not. |
*/ |
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(rdev, ring); |
return false; |
} |
return radeon_ring_test_lockup(rdev, ring); |
} |
/** |
* r600_dma_ring_test - simple async dma engine test |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Test the DMA engine by writing using it to write an |
* value to memory. (r6xx-SI). |
* Returns 0 for success, error for failure. |
*/ |
int r600_dma_ring_test(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
unsigned i; |
int r; |
void __iomem *ptr = (void *)rdev->vram_scratch.ptr; |
u32 tmp; |
if (!ptr) { |
DRM_ERROR("invalid vram scratch pointer\n"); |
return -EINVAL; |
} |
tmp = 0xCAFEDEAD; |
writel(tmp, ptr); |
r = radeon_ring_lock(rdev, ring, 4); |
if (r) { |
DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r); |
return r; |
} |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); |
radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff); |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring, false); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = readl(ptr); |
if (tmp == 0xDEADBEEF) |
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 (0x%08X)\n", |
ring->idx, tmp); |
r = -EINVAL; |
} |
return r; |
} |
/** |
* r600_dma_fence_ring_emit - emit a fence on the DMA ring |
* |
* @rdev: radeon_device pointer |
* @fence: radeon fence object |
* |
* Add a DMA fence packet to the ring to write |
* the fence seq number and DMA trap packet to generate |
* an interrupt if needed (r6xx-r7xx). |
*/ |
void r600_dma_fence_ring_emit(struct radeon_device *rdev, |
struct radeon_fence *fence) |
{ |
struct radeon_ring *ring = &rdev->ring[fence->ring]; |
u64 addr = rdev->fence_drv[fence->ring].gpu_addr; |
/* write the fence */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0)); |
radeon_ring_write(ring, addr & 0xfffffffc); |
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff)); |
radeon_ring_write(ring, lower_32_bits(fence->seq)); |
/* generate an interrupt */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0)); |
} |
/** |
* r600_dma_semaphore_ring_emit - emit a semaphore on the dma ring |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* @semaphore: radeon semaphore object |
* @emit_wait: wait or signal semaphore |
* |
* Add a DMA semaphore packet to the ring wait on or signal |
* other rings (r6xx-SI). |
*/ |
bool r600_dma_semaphore_ring_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait) |
{ |
u64 addr = semaphore->gpu_addr; |
u32 s = emit_wait ? 0 : 1; |
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; |
} |
/** |
* r600_dma_ib_test - test an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Test a simple IB in the DMA ring (r6xx-SI). |
* Returns 0 on success, error on failure. |
*/ |
int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
struct radeon_ib ib; |
unsigned i; |
int r; |
void __iomem *ptr = (void *)rdev->vram_scratch.ptr; |
u32 tmp = 0; |
if (!ptr) { |
DRM_ERROR("invalid vram scratch pointer\n"); |
return -EINVAL; |
} |
tmp = 0xCAFEDEAD; |
writel(tmp, ptr); |
r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); |
if (r) { |
DRM_ERROR("radeon: failed to get ib (%d).\n", r); |
return r; |
} |
ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1); |
ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc; |
ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff; |
ib.ptr[3] = 0xDEADBEEF; |
ib.length_dw = 4; |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
if (r) { |
radeon_ib_free(rdev, &ib); |
DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); |
return r; |
} |
r = radeon_fence_wait(ib.fence, false); |
if (r) { |
DRM_ERROR("radeon: fence wait failed (%d).\n", r); |
return r; |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = readl(ptr); |
if (tmp == 0xDEADBEEF) |
break; |
DRM_UDELAY(1); |
} |
if (i < rdev->usec_timeout) { |
DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i); |
} else { |
DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp); |
r = -EINVAL; |
} |
radeon_ib_free(rdev, &ib); |
return r; |
} |
/** |
* r600_dma_ring_ib_execute - Schedule an IB on the DMA engine |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to schedule |
* |
* Schedule an IB in the DMA ring (r6xx-r7xx). |
*/ |
void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
if (rdev->wb.enabled) { |
u32 next_rptr = ring->wptr + 4; |
while ((next_rptr & 7) != 5) |
next_rptr++; |
next_rptr += 3; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); |
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); |
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff); |
radeon_ring_write(ring, next_rptr); |
} |
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring. |
* Pad as necessary with NOPs. |
*/ |
while ((ring->wptr & 7) != 5) |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_INDIRECT_BUFFER, 0, 0, 0)); |
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0)); |
radeon_ring_write(ring, (ib->length_dw << 16) | (upper_32_bits(ib->gpu_addr) & 0xFF)); |
} |
/** |
* r600_copy_dma - copy pages using the 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 DMA engine (r6xx). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int r600_copy_dma(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.dma_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_dw, cur_size_in_dw; |
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_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; |
num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFE); |
r = radeon_ring_lock(rdev, ring, num_loops * 4 + 8); |
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_dw = size_in_dw; |
if (cur_size_in_dw > 0xFFFE) |
cur_size_in_dw = 0xFFFE; |
size_in_dw -= cur_size_in_dw; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw)); |
radeon_ring_write(ring, dst_offset & 0xfffffffc); |
radeon_ring_write(ring, src_offset & 0xfffffffc); |
radeon_ring_write(ring, (((upper_32_bits(dst_offset) & 0xff) << 16) | |
(upper_32_bits(src_offset) & 0xff))); |
src_offset += cur_size_in_dw * 4; |
dst_offset += cur_size_in_dw * 4; |
} |
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, false); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
/drivers/video/drm/radeon/r600_dpm.c |
---|
0,0 → 1,1357 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "r600d.h" |
#include "r600_dpm.h" |
#include "atom.h" |
const u32 r600_utc[R600_PM_NUMBER_OF_TC] = |
{ |
R600_UTC_DFLT_00, |
R600_UTC_DFLT_01, |
R600_UTC_DFLT_02, |
R600_UTC_DFLT_03, |
R600_UTC_DFLT_04, |
R600_UTC_DFLT_05, |
R600_UTC_DFLT_06, |
R600_UTC_DFLT_07, |
R600_UTC_DFLT_08, |
R600_UTC_DFLT_09, |
R600_UTC_DFLT_10, |
R600_UTC_DFLT_11, |
R600_UTC_DFLT_12, |
R600_UTC_DFLT_13, |
R600_UTC_DFLT_14, |
}; |
const u32 r600_dtc[R600_PM_NUMBER_OF_TC] = |
{ |
R600_DTC_DFLT_00, |
R600_DTC_DFLT_01, |
R600_DTC_DFLT_02, |
R600_DTC_DFLT_03, |
R600_DTC_DFLT_04, |
R600_DTC_DFLT_05, |
R600_DTC_DFLT_06, |
R600_DTC_DFLT_07, |
R600_DTC_DFLT_08, |
R600_DTC_DFLT_09, |
R600_DTC_DFLT_10, |
R600_DTC_DFLT_11, |
R600_DTC_DFLT_12, |
R600_DTC_DFLT_13, |
R600_DTC_DFLT_14, |
}; |
void r600_dpm_print_class_info(u32 class, u32 class2) |
{ |
printk("\tui class: "); |
switch (class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { |
case ATOM_PPLIB_CLASSIFICATION_UI_NONE: |
default: |
printk("none\n"); |
break; |
case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: |
printk("battery\n"); |
break; |
case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED: |
printk("balanced\n"); |
break; |
case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE: |
printk("performance\n"); |
break; |
} |
printk("\tinternal class: "); |
if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) && |
(class2 == 0)) |
printk("none"); |
else { |
if (class & ATOM_PPLIB_CLASSIFICATION_BOOT) |
printk("boot "); |
if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL) |
printk("thermal "); |
if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) |
printk("limited_pwr "); |
if (class & ATOM_PPLIB_CLASSIFICATION_REST) |
printk("rest "); |
if (class & ATOM_PPLIB_CLASSIFICATION_FORCED) |
printk("forced "); |
if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) |
printk("3d_perf "); |
if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE) |
printk("ovrdrv "); |
if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
printk("uvd "); |
if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW) |
printk("3d_low "); |
if (class & ATOM_PPLIB_CLASSIFICATION_ACPI) |
printk("acpi "); |
if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) |
printk("uvd_hd2 "); |
if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) |
printk("uvd_hd "); |
if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) |
printk("uvd_sd "); |
if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) |
printk("limited_pwr2 "); |
if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) |
printk("ulv "); |
if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) |
printk("uvd_mvc "); |
} |
printk("\n"); |
} |
void r600_dpm_print_cap_info(u32 caps) |
{ |
printk("\tcaps: "); |
if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) |
printk("single_disp "); |
if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK) |
printk("video "); |
if (caps & ATOM_PPLIB_DISALLOW_ON_DC) |
printk("no_dc "); |
printk("\n"); |
} |
void r600_dpm_print_ps_status(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
printk("\tstatus: "); |
if (rps == rdev->pm.dpm.current_ps) |
printk("c "); |
if (rps == rdev->pm.dpm.requested_ps) |
printk("r "); |
if (rps == rdev->pm.dpm.boot_ps) |
printk("b "); |
printk("\n"); |
} |
u32 r600_dpm_get_vblank_time(struct radeon_device *rdev) |
{ |
struct drm_device *dev = rdev->ddev; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
u32 line_time_us, vblank_lines; |
u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ |
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; |
} |
} |
} |
return vblank_time_us; |
} |
u32 r600_dpm_get_vrefresh(struct radeon_device *rdev) |
{ |
struct drm_device *dev = rdev->ddev; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
u32 vrefresh = 0; |
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; |
} |
void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, |
u32 *p, u32 *u) |
{ |
u32 b_c = 0; |
u32 i_c; |
u32 tmp; |
i_c = (i * r_c) / 100; |
tmp = i_c >> p_b; |
while (tmp) { |
b_c++; |
tmp >>= 1; |
} |
*u = (b_c + 1) / 2; |
*p = i_c / (1 << (2 * (*u))); |
} |
int r600_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th) |
{ |
u32 k, a, ah, al; |
u32 t1; |
if ((fl == 0) || (fh == 0) || (fl > fh)) |
return -EINVAL; |
k = (100 * fh) / fl; |
t1 = (t * (k - 100)); |
a = (1000 * (100 * h + t1)) / (10000 + (t1 / 100)); |
a = (a + 5) / 10; |
ah = ((a * t) + 5000) / 10000; |
al = a - ah; |
*th = t - ah; |
*tl = t + al; |
return 0; |
} |
void r600_gfx_clockgating_enable(struct radeon_device *rdev, bool enable) |
{ |
int i; |
if (enable) { |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); |
} else { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); |
WREG32(CG_RLC_REQ_AND_RSP, 0x2); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (((RREG32(CG_RLC_REQ_AND_RSP) & CG_RLC_RSP_TYPE_MASK) >> CG_RLC_RSP_TYPE_SHIFT) == 1) |
break; |
udelay(1); |
} |
WREG32(CG_RLC_REQ_AND_RSP, 0x0); |
WREG32(GRBM_PWR_CNTL, 0x1); |
RREG32(GRBM_PWR_CNTL); |
} |
} |
void r600_dynamicpm_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); |
} |
void r600_enable_thermal_protection(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); |
else |
WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); |
} |
void r600_enable_acpi_pm(struct radeon_device *rdev) |
{ |
WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN); |
} |
void r600_enable_dynamic_pcie_gen2(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE); |
} |
bool r600_dynamicpm_enabled(struct radeon_device *rdev) |
{ |
if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN) |
return true; |
else |
return false; |
} |
void r600_enable_sclk_control(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF); |
else |
WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF); |
} |
void r600_enable_mclk_control(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF); |
else |
WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF); |
} |
void r600_enable_spll_bypass(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(CG_SPLL_FUNC_CNTL, SPLL_BYPASS_EN, ~SPLL_BYPASS_EN); |
else |
WREG32_P(CG_SPLL_FUNC_CNTL, 0, ~SPLL_BYPASS_EN); |
} |
void r600_wait_for_spll_change(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_CHG_STATUS) |
break; |
udelay(1); |
} |
} |
void r600_set_bsp(struct radeon_device *rdev, u32 u, u32 p) |
{ |
WREG32(CG_BSP, BSP(p) | BSU(u)); |
} |
void r600_set_at(struct radeon_device *rdev, |
u32 l_to_m, u32 m_to_h, |
u32 h_to_m, u32 m_to_l) |
{ |
WREG32(CG_RT, FLS(l_to_m) | FMS(m_to_h)); |
WREG32(CG_LT, FHS(h_to_m) | FMS(m_to_l)); |
} |
void r600_set_tc(struct radeon_device *rdev, |
u32 index, u32 u_t, u32 d_t) |
{ |
WREG32(CG_FFCT_0 + (index * 4), UTC_0(u_t) | DTC_0(d_t)); |
} |
void r600_select_td(struct radeon_device *rdev, |
enum r600_td td) |
{ |
if (td == R600_TD_AUTO) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL); |
else |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL); |
if (td == R600_TD_UP) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE); |
if (td == R600_TD_DOWN) |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE); |
} |
void r600_set_vrc(struct radeon_device *rdev, u32 vrv) |
{ |
WREG32(CG_FTV, vrv); |
} |
void r600_set_tpu(struct radeon_device *rdev, u32 u) |
{ |
WREG32_P(CG_TPC, TPU(u), ~TPU_MASK); |
} |
void r600_set_tpc(struct radeon_device *rdev, u32 c) |
{ |
WREG32_P(CG_TPC, TPCC(c), ~TPCC_MASK); |
} |
void r600_set_sstu(struct radeon_device *rdev, u32 u) |
{ |
WREG32_P(CG_SSP, CG_SSTU(u), ~CG_SSTU_MASK); |
} |
void r600_set_sst(struct radeon_device *rdev, u32 t) |
{ |
WREG32_P(CG_SSP, CG_SST(t), ~CG_SST_MASK); |
} |
void r600_set_git(struct radeon_device *rdev, u32 t) |
{ |
WREG32_P(CG_GIT, CG_GICST(t), ~CG_GICST_MASK); |
} |
void r600_set_fctu(struct radeon_device *rdev, u32 u) |
{ |
WREG32_P(CG_FC_T, FC_TU(u), ~FC_TU_MASK); |
} |
void r600_set_fct(struct radeon_device *rdev, u32 t) |
{ |
WREG32_P(CG_FC_T, FC_T(t), ~FC_T_MASK); |
} |
void r600_set_ctxcgtt3d_rphc(struct radeon_device *rdev, u32 p) |
{ |
WREG32_P(CG_CTX_CGTT3D_R, PHC(p), ~PHC_MASK); |
} |
void r600_set_ctxcgtt3d_rsdc(struct radeon_device *rdev, u32 s) |
{ |
WREG32_P(CG_CTX_CGTT3D_R, SDC(s), ~SDC_MASK); |
} |
void r600_set_vddc3d_oorsu(struct radeon_device *rdev, u32 u) |
{ |
WREG32_P(CG_VDDC3D_OOR, SU(u), ~SU_MASK); |
} |
void r600_set_vddc3d_oorphc(struct radeon_device *rdev, u32 p) |
{ |
WREG32_P(CG_VDDC3D_OOR, PHC(p), ~PHC_MASK); |
} |
void r600_set_vddc3d_oorsdc(struct radeon_device *rdev, u32 s) |
{ |
WREG32_P(CG_VDDC3D_OOR, SDC(s), ~SDC_MASK); |
} |
void r600_set_mpll_lock_time(struct radeon_device *rdev, u32 lock_time) |
{ |
WREG32_P(MPLL_TIME, MPLL_LOCK_TIME(lock_time), ~MPLL_LOCK_TIME_MASK); |
} |
void r600_set_mpll_reset_time(struct radeon_device *rdev, u32 reset_time) |
{ |
WREG32_P(MPLL_TIME, MPLL_RESET_TIME(reset_time), ~MPLL_RESET_TIME_MASK); |
} |
void r600_engine_clock_entry_enable(struct radeon_device *rdev, |
u32 index, bool enable) |
{ |
if (enable) |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2), |
STEP_0_SPLL_ENTRY_VALID, ~STEP_0_SPLL_ENTRY_VALID); |
else |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2), |
0, ~STEP_0_SPLL_ENTRY_VALID); |
} |
void r600_engine_clock_entry_enable_pulse_skipping(struct radeon_device *rdev, |
u32 index, bool enable) |
{ |
if (enable) |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2), |
STEP_0_SPLL_STEP_ENABLE, ~STEP_0_SPLL_STEP_ENABLE); |
else |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2), |
0, ~STEP_0_SPLL_STEP_ENABLE); |
} |
void r600_engine_clock_entry_enable_post_divider(struct radeon_device *rdev, |
u32 index, bool enable) |
{ |
if (enable) |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2), |
STEP_0_POST_DIV_EN, ~STEP_0_POST_DIV_EN); |
else |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2), |
0, ~STEP_0_POST_DIV_EN); |
} |
void r600_engine_clock_entry_set_post_divider(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2), |
STEP_0_SPLL_POST_DIV(divider), ~STEP_0_SPLL_POST_DIV_MASK); |
} |
void r600_engine_clock_entry_set_reference_divider(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2), |
STEP_0_SPLL_REF_DIV(divider), ~STEP_0_SPLL_REF_DIV_MASK); |
} |
void r600_engine_clock_entry_set_feedback_divider(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2), |
STEP_0_SPLL_FB_DIV(divider), ~STEP_0_SPLL_FB_DIV_MASK); |
} |
void r600_engine_clock_entry_set_step_time(struct radeon_device *rdev, |
u32 index, u32 step_time) |
{ |
WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2), |
STEP_0_SPLL_STEP_TIME(step_time), ~STEP_0_SPLL_STEP_TIME_MASK); |
} |
void r600_vid_rt_set_ssu(struct radeon_device *rdev, u32 u) |
{ |
WREG32_P(VID_RT, SSTU(u), ~SSTU_MASK); |
} |
void r600_vid_rt_set_vru(struct radeon_device *rdev, u32 u) |
{ |
WREG32_P(VID_RT, VID_CRTU(u), ~VID_CRTU_MASK); |
} |
void r600_vid_rt_set_vrt(struct radeon_device *rdev, u32 rt) |
{ |
WREG32_P(VID_RT, VID_CRT(rt), ~VID_CRT_MASK); |
} |
void r600_voltage_control_enable_pins(struct radeon_device *rdev, |
u64 mask) |
{ |
WREG32(LOWER_GPIO_ENABLE, mask & 0xffffffff); |
WREG32(UPPER_GPIO_ENABLE, upper_32_bits(mask)); |
} |
void r600_voltage_control_program_voltages(struct radeon_device *rdev, |
enum r600_power_level index, u64 pins) |
{ |
u32 tmp, mask; |
u32 ix = 3 - (3 & index); |
WREG32(CTXSW_VID_LOWER_GPIO_CNTL + (ix * 4), pins & 0xffffffff); |
mask = 7 << (3 * ix); |
tmp = RREG32(VID_UPPER_GPIO_CNTL); |
tmp = (tmp & ~mask) | ((pins >> (32 - (3 * ix))) & mask); |
WREG32(VID_UPPER_GPIO_CNTL, tmp); |
} |
void r600_voltage_control_deactivate_static_control(struct radeon_device *rdev, |
u64 mask) |
{ |
u32 gpio; |
gpio = RREG32(GPIOPAD_MASK); |
gpio &= ~mask; |
WREG32(GPIOPAD_MASK, gpio); |
gpio = RREG32(GPIOPAD_EN); |
gpio &= ~mask; |
WREG32(GPIOPAD_EN, gpio); |
gpio = RREG32(GPIOPAD_A); |
gpio &= ~mask; |
WREG32(GPIOPAD_A, gpio); |
} |
void r600_power_level_enable(struct radeon_device *rdev, |
enum r600_power_level index, bool enable) |
{ |
u32 ix = 3 - (3 & index); |
if (enable) |
WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), CTXSW_FREQ_STATE_ENABLE, |
~CTXSW_FREQ_STATE_ENABLE); |
else |
WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), 0, |
~CTXSW_FREQ_STATE_ENABLE); |
} |
void r600_power_level_set_voltage_index(struct radeon_device *rdev, |
enum r600_power_level index, u32 voltage_index) |
{ |
u32 ix = 3 - (3 & index); |
WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), |
CTXSW_FREQ_VIDS_CFG_INDEX(voltage_index), ~CTXSW_FREQ_VIDS_CFG_INDEX_MASK); |
} |
void r600_power_level_set_mem_clock_index(struct radeon_device *rdev, |
enum r600_power_level index, u32 mem_clock_index) |
{ |
u32 ix = 3 - (3 & index); |
WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), |
CTXSW_FREQ_MCLK_CFG_INDEX(mem_clock_index), ~CTXSW_FREQ_MCLK_CFG_INDEX_MASK); |
} |
void r600_power_level_set_eng_clock_index(struct radeon_device *rdev, |
enum r600_power_level index, u32 eng_clock_index) |
{ |
u32 ix = 3 - (3 & index); |
WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), |
CTXSW_FREQ_SCLK_CFG_INDEX(eng_clock_index), ~CTXSW_FREQ_SCLK_CFG_INDEX_MASK); |
} |
void r600_power_level_set_watermark_id(struct radeon_device *rdev, |
enum r600_power_level index, |
enum r600_display_watermark watermark_id) |
{ |
u32 ix = 3 - (3 & index); |
u32 tmp = 0; |
if (watermark_id == R600_DISPLAY_WATERMARK_HIGH) |
tmp = CTXSW_FREQ_DISPLAY_WATERMARK; |
WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), tmp, ~CTXSW_FREQ_DISPLAY_WATERMARK); |
} |
void r600_power_level_set_pcie_gen2(struct radeon_device *rdev, |
enum r600_power_level index, bool compatible) |
{ |
u32 ix = 3 - (3 & index); |
u32 tmp = 0; |
if (compatible) |
tmp = CTXSW_FREQ_GEN2PCIE_VOLT; |
WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), tmp, ~CTXSW_FREQ_GEN2PCIE_VOLT); |
} |
enum r600_power_level r600_power_level_get_current_index(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK; |
tmp >>= CURRENT_PROFILE_INDEX_SHIFT; |
return tmp; |
} |
enum r600_power_level r600_power_level_get_target_index(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_PROFILE_INDEX_MASK; |
tmp >>= TARGET_PROFILE_INDEX_SHIFT; |
return tmp; |
} |
void r600_power_level_set_enter_index(struct radeon_device *rdev, |
enum r600_power_level index) |
{ |
WREG32_P(TARGET_AND_CURRENT_PROFILE_INDEX, DYN_PWR_ENTER_INDEX(index), |
~DYN_PWR_ENTER_INDEX_MASK); |
} |
void r600_wait_for_power_level_unequal(struct radeon_device *rdev, |
enum r600_power_level index) |
{ |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (r600_power_level_get_target_index(rdev) != index) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (r600_power_level_get_current_index(rdev) != index) |
break; |
udelay(1); |
} |
} |
void r600_wait_for_power_level(struct radeon_device *rdev, |
enum r600_power_level index) |
{ |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (r600_power_level_get_target_index(rdev) == index) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (r600_power_level_get_current_index(rdev) == index) |
break; |
udelay(1); |
} |
} |
void r600_start_dpm(struct radeon_device *rdev) |
{ |
r600_enable_sclk_control(rdev, false); |
r600_enable_mclk_control(rdev, false); |
r600_dynamicpm_enable(rdev, true); |
radeon_wait_for_vblank(rdev, 0); |
radeon_wait_for_vblank(rdev, 1); |
r600_enable_spll_bypass(rdev, true); |
r600_wait_for_spll_change(rdev); |
r600_enable_spll_bypass(rdev, false); |
r600_wait_for_spll_change(rdev); |
r600_enable_spll_bypass(rdev, true); |
r600_wait_for_spll_change(rdev); |
r600_enable_spll_bypass(rdev, false); |
r600_wait_for_spll_change(rdev); |
r600_enable_sclk_control(rdev, true); |
r600_enable_mclk_control(rdev, true); |
} |
void r600_stop_dpm(struct radeon_device *rdev) |
{ |
r600_dynamicpm_enable(rdev, false); |
} |
int r600_dpm_pre_set_power_state(struct radeon_device *rdev) |
{ |
return 0; |
} |
void r600_dpm_post_set_power_state(struct radeon_device *rdev) |
{ |
} |
bool r600_is_uvd_state(u32 class, u32 class2) |
{ |
if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
return true; |
if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) |
return true; |
if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) |
return true; |
if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) |
return true; |
if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) |
return true; |
return false; |
} |
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; |
if (low_temp < min_temp) |
low_temp = min_temp; |
if (high_temp > max_temp) |
high_temp = max_temp; |
if (high_temp < low_temp) { |
DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); |
return -EINVAL; |
} |
WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK); |
WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK); |
WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK); |
rdev->pm.dpm.thermal.min_temp = low_temp; |
rdev->pm.dpm.thermal.max_temp = high_temp; |
return 0; |
} |
bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor) |
{ |
switch (sensor) { |
case THERMAL_TYPE_RV6XX: |
case THERMAL_TYPE_RV770: |
case THERMAL_TYPE_EVERGREEN: |
case THERMAL_TYPE_SUMO: |
case THERMAL_TYPE_NI: |
case THERMAL_TYPE_SI: |
case THERMAL_TYPE_CI: |
case THERMAL_TYPE_KV: |
return true; |
case THERMAL_TYPE_ADT7473_WITH_INTERNAL: |
case THERMAL_TYPE_EMC2103_WITH_INTERNAL: |
return false; /* need special handling */ |
case THERMAL_TYPE_NONE: |
case THERMAL_TYPE_EXTERNAL: |
case THERMAL_TYPE_EXTERNAL_GPIO: |
default: |
return false; |
} |
} |
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; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4; |
struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5; |
}; |
union fan_info { |
struct _ATOM_PPLIB_FANTABLE fan; |
struct _ATOM_PPLIB_FANTABLE2 fan2; |
}; |
static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependency_table *radeon_table, |
ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table) |
{ |
u32 size = atom_table->ucNumEntries * |
sizeof(struct radeon_clock_voltage_dependency_entry); |
int i; |
ATOM_PPLIB_Clock_Voltage_Dependency_Record *entry; |
radeon_table->entries = kzalloc(size, GFP_KERNEL); |
if (!radeon_table->entries) |
return -ENOMEM; |
entry = &atom_table->entries[0]; |
for (i = 0; i < atom_table->ucNumEntries; i++) { |
radeon_table->entries[i].clk = le16_to_cpu(entry->usClockLow) | |
(entry->ucClockHigh << 16); |
radeon_table->entries[i].v = le16_to_cpu(entry->usVoltage); |
entry = (ATOM_PPLIB_Clock_Voltage_Dependency_Record *) |
((u8 *)entry + sizeof(ATOM_PPLIB_Clock_Voltage_Dependency_Record)); |
} |
radeon_table->count = atom_table->ucNumEntries; |
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 |
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16 |
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18 |
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20 |
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22 |
int r600_parse_extended_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
union power_info *power_info; |
union fan_info *fan_info; |
ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
int ret, i; |
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); |
/* fan table */ |
if (le16_to_cpu(power_info->pplib.usTableSize) >= |
sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) { |
if (power_info->pplib3.usFanTableOffset) { |
fan_info = (union fan_info *)(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib3.usFanTableOffset)); |
rdev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst; |
rdev->pm.dpm.fan.t_min = le16_to_cpu(fan_info->fan.usTMin); |
rdev->pm.dpm.fan.t_med = le16_to_cpu(fan_info->fan.usTMed); |
rdev->pm.dpm.fan.t_high = le16_to_cpu(fan_info->fan.usTHigh); |
rdev->pm.dpm.fan.pwm_min = le16_to_cpu(fan_info->fan.usPWMMin); |
rdev->pm.dpm.fan.pwm_med = le16_to_cpu(fan_info->fan.usPWMMed); |
rdev->pm.dpm.fan.pwm_high = le16_to_cpu(fan_info->fan.usPWMHigh); |
if (fan_info->fan.ucFanTableFormat >= 2) |
rdev->pm.dpm.fan.t_max = le16_to_cpu(fan_info->fan2.usTMax); |
else |
rdev->pm.dpm.fan.t_max = 10900; |
rdev->pm.dpm.fan.cycle_delay = 100000; |
rdev->pm.dpm.fan.ucode_fan_control = true; |
} |
} |
/* clock dependancy tables, shedding tables */ |
if (le16_to_cpu(power_info->pplib.usTableSize) >= |
sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE4)) { |
if (power_info->pplib4.usVddcDependencyOnSCLKOffset) { |
dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset)); |
ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
dep_table); |
if (ret) |
return ret; |
} |
if (power_info->pplib4.usVddciDependencyOnMCLKOffset) { |
dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset)); |
ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
dep_table); |
if (ret) { |
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); |
return ret; |
} |
} |
if (power_info->pplib4.usVddcDependencyOnMCLKOffset) { |
dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset)); |
ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
dep_table); |
if (ret) { |
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); |
kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries); |
return ret; |
} |
} |
if (power_info->pplib4.usMvddDependencyOnMCLKOffset) { |
dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib4.usMvddDependencyOnMCLKOffset)); |
ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk, |
dep_table); |
if (ret) { |
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); |
kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries); |
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries); |
return ret; |
} |
} |
if (power_info->pplib4.usMaxClockVoltageOnDCOffset) { |
ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v = |
(ATOM_PPLIB_Clock_Voltage_Limit_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib4.usMaxClockVoltageOnDCOffset)); |
if (clk_v->ucNumEntries) { |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk = |
le16_to_cpu(clk_v->entries[0].usSclkLow) | |
(clk_v->entries[0].ucSclkHigh << 16); |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk = |
le16_to_cpu(clk_v->entries[0].usMclkLow) | |
(clk_v->entries[0].ucMclkHigh << 16); |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc = |
le16_to_cpu(clk_v->entries[0].usVddc); |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddci = |
le16_to_cpu(clk_v->entries[0].usVddci); |
} |
} |
if (power_info->pplib4.usVddcPhaseShedLimitsTableOffset) { |
ATOM_PPLIB_PhaseSheddingLimits_Table *psl = |
(ATOM_PPLIB_PhaseSheddingLimits_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib4.usVddcPhaseShedLimitsTableOffset)); |
ATOM_PPLIB_PhaseSheddingLimits_Record *entry; |
rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries = |
kzalloc(psl->ucNumEntries * |
sizeof(struct radeon_phase_shedding_limits_entry), |
GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
entry = &psl->entries[0]; |
for (i = 0; i < psl->ucNumEntries; i++) { |
rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].sclk = |
le16_to_cpu(entry->usSclkLow) | (entry->ucSclkHigh << 16); |
rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].mclk = |
le16_to_cpu(entry->usMclkLow) | (entry->ucMclkHigh << 16); |
rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].voltage = |
le16_to_cpu(entry->usVoltage); |
entry = (ATOM_PPLIB_PhaseSheddingLimits_Record *) |
((u8 *)entry + sizeof(ATOM_PPLIB_PhaseSheddingLimits_Record)); |
} |
rdev->pm.dpm.dyn_state.phase_shedding_limits_table.count = |
psl->ucNumEntries; |
} |
} |
/* cac data */ |
if (le16_to_cpu(power_info->pplib.usTableSize) >= |
sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE5)) { |
rdev->pm.dpm.tdp_limit = le32_to_cpu(power_info->pplib5.ulTDPLimit); |
rdev->pm.dpm.near_tdp_limit = le32_to_cpu(power_info->pplib5.ulNearTDPLimit); |
rdev->pm.dpm.near_tdp_limit_adjusted = rdev->pm.dpm.near_tdp_limit; |
rdev->pm.dpm.tdp_od_limit = le16_to_cpu(power_info->pplib5.usTDPODLimit); |
if (rdev->pm.dpm.tdp_od_limit) |
rdev->pm.dpm.power_control = true; |
else |
rdev->pm.dpm.power_control = false; |
rdev->pm.dpm.tdp_adjustment = 0; |
rdev->pm.dpm.sq_ramping_threshold = le32_to_cpu(power_info->pplib5.ulSQRampingThreshold); |
rdev->pm.dpm.cac_leakage = le32_to_cpu(power_info->pplib5.ulCACLeakage); |
rdev->pm.dpm.load_line_slope = le16_to_cpu(power_info->pplib5.usLoadLineSlope); |
if (power_info->pplib5.usCACLeakageTableOffset) { |
ATOM_PPLIB_CAC_Leakage_Table *cac_table = |
(ATOM_PPLIB_CAC_Leakage_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib5.usCACLeakageTableOffset)); |
ATOM_PPLIB_CAC_Leakage_Record *entry; |
u32 size = cac_table->ucNumEntries * sizeof(struct radeon_cac_leakage_table); |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.cac_leakage_table.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
entry = &cac_table->entries[0]; |
for (i = 0; i < cac_table->ucNumEntries; i++) { |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) { |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1 = |
le16_to_cpu(entry->usVddc1); |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2 = |
le16_to_cpu(entry->usVddc2); |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3 = |
le16_to_cpu(entry->usVddc3); |
} else { |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc = |
le16_to_cpu(entry->usVddc); |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage = |
le32_to_cpu(entry->ulLeakageValue); |
} |
entry = (ATOM_PPLIB_CAC_Leakage_Record *) |
((u8 *)entry + sizeof(ATOM_PPLIB_CAC_Leakage_Record)); |
} |
rdev->pm.dpm.dyn_state.cac_leakage_table.count = cac_table->ucNumEntries; |
} |
} |
/* ext tables */ |
if (le16_to_cpu(power_info->pplib.usTableSize) >= |
sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) { |
ATOM_PPLIB_EXTENDEDHEADER *ext_hdr = (ATOM_PPLIB_EXTENDEDHEADER *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib3.usExtendendedHeaderOffset)); |
if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) && |
ext_hdr->usVCETableOffset) { |
VCEClockInfoArray *array = (VCEClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usVCETableOffset) + 1); |
ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *limits = |
(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *) |
(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 = |
kzalloc(size, GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
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++) { |
vce_clk = (VCEClockInfo *) |
((u8 *)&array->entries[0] + |
(entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo))); |
rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].evclk = |
le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16); |
rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].ecclk = |
le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16); |
rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v = |
le16_to_cpu(entry->usVoltage); |
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) { |
UVDClockInfoArray *array = (UVDClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usUVDTableOffset) + 1); |
ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *limits = |
(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usUVDTableOffset) + 1 + |
1 + (array->ucNumEntries * sizeof (UVDClockInfo))); |
ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *entry; |
u32 size = limits->numEntries * |
sizeof(struct radeon_uvd_clock_voltage_dependency_entry); |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries = |
kzalloc(size, GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count = |
limits->numEntries; |
entry = &limits->entries[0]; |
for (i = 0; i < limits->numEntries; i++) { |
UVDClockInfo *uvd_clk = (UVDClockInfo *) |
((u8 *)&array->entries[0] + |
(entry->ucUVDClockInfoIndex * sizeof(UVDClockInfo))); |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].vclk = |
le16_to_cpu(uvd_clk->usVClkLow) | (uvd_clk->ucVClkHigh << 16); |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].dclk = |
le16_to_cpu(uvd_clk->usDClkLow) | (uvd_clk->ucDClkHigh << 16); |
rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v = |
le16_to_cpu(entry->usVoltage); |
entry = (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *) |
((u8 *)entry + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record)); |
} |
} |
if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) && |
ext_hdr->usSAMUTableOffset) { |
ATOM_PPLIB_SAMClk_Voltage_Limit_Table *limits = |
(ATOM_PPLIB_SAMClk_Voltage_Limit_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usSAMUTableOffset) + 1); |
ATOM_PPLIB_SAMClk_Voltage_Limit_Record *entry; |
u32 size = limits->numEntries * |
sizeof(struct radeon_clock_voltage_dependency_entry); |
rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries = |
kzalloc(size, GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count = |
limits->numEntries; |
entry = &limits->entries[0]; |
for (i = 0; i < limits->numEntries; i++) { |
rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].clk = |
le16_to_cpu(entry->usSAMClockLow) | (entry->ucSAMClockHigh << 16); |
rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v = |
le16_to_cpu(entry->usVoltage); |
entry = (ATOM_PPLIB_SAMClk_Voltage_Limit_Record *) |
((u8 *)entry + sizeof(ATOM_PPLIB_SAMClk_Voltage_Limit_Record)); |
} |
} |
if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) && |
ext_hdr->usPPMTableOffset) { |
ATOM_PPLIB_PPM_Table *ppm = (ATOM_PPLIB_PPM_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usPPMTableOffset)); |
rdev->pm.dpm.dyn_state.ppm_table = |
kzalloc(sizeof(struct radeon_ppm_table), GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.ppm_table) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
rdev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign; |
rdev->pm.dpm.dyn_state.ppm_table->cpu_core_number = |
le16_to_cpu(ppm->usCpuCoreNumber); |
rdev->pm.dpm.dyn_state.ppm_table->platform_tdp = |
le32_to_cpu(ppm->ulPlatformTDP); |
rdev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdp = |
le32_to_cpu(ppm->ulSmallACPlatformTDP); |
rdev->pm.dpm.dyn_state.ppm_table->platform_tdc = |
le32_to_cpu(ppm->ulPlatformTDC); |
rdev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdc = |
le32_to_cpu(ppm->ulSmallACPlatformTDC); |
rdev->pm.dpm.dyn_state.ppm_table->apu_tdp = |
le32_to_cpu(ppm->ulApuTDP); |
rdev->pm.dpm.dyn_state.ppm_table->dgpu_tdp = |
le32_to_cpu(ppm->ulDGpuTDP); |
rdev->pm.dpm.dyn_state.ppm_table->dgpu_ulv_power = |
le32_to_cpu(ppm->ulDGpuUlvPower); |
rdev->pm.dpm.dyn_state.ppm_table->tj_max = |
le32_to_cpu(ppm->ulTjmax); |
} |
if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) && |
ext_hdr->usACPTableOffset) { |
ATOM_PPLIB_ACPClk_Voltage_Limit_Table *limits = |
(ATOM_PPLIB_ACPClk_Voltage_Limit_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usACPTableOffset) + 1); |
ATOM_PPLIB_ACPClk_Voltage_Limit_Record *entry; |
u32 size = limits->numEntries * |
sizeof(struct radeon_clock_voltage_dependency_entry); |
rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries = |
kzalloc(size, GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count = |
limits->numEntries; |
entry = &limits->entries[0]; |
for (i = 0; i < limits->numEntries; i++) { |
rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].clk = |
le16_to_cpu(entry->usACPClockLow) | (entry->ucACPClockHigh << 16); |
rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v = |
le16_to_cpu(entry->usVoltage); |
entry = (ATOM_PPLIB_ACPClk_Voltage_Limit_Record *) |
((u8 *)entry + sizeof(ATOM_PPLIB_ACPClk_Voltage_Limit_Record)); |
} |
} |
if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) && |
ext_hdr->usPowerTuneTableOffset) { |
u8 rev = *(u8 *)(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usPowerTuneTableOffset)); |
ATOM_PowerTune_Table *pt; |
rdev->pm.dpm.dyn_state.cac_tdp_table = |
kzalloc(sizeof(struct radeon_cac_tdp_table), GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.cac_tdp_table) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
if (rev > 0) { |
ATOM_PPLIB_POWERTUNE_Table_V1 *ppt = (ATOM_PPLIB_POWERTUNE_Table_V1 *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usPowerTuneTableOffset)); |
rdev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit = |
ppt->usMaximumPowerDeliveryLimit; |
pt = &ppt->power_tune_table; |
} else { |
ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(ext_hdr->usPowerTuneTableOffset)); |
rdev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit = 255; |
pt = &ppt->power_tune_table; |
} |
rdev->pm.dpm.dyn_state.cac_tdp_table->tdp = le16_to_cpu(pt->usTDP); |
rdev->pm.dpm.dyn_state.cac_tdp_table->configurable_tdp = |
le16_to_cpu(pt->usConfigurableTDP); |
rdev->pm.dpm.dyn_state.cac_tdp_table->tdc = le16_to_cpu(pt->usTDC); |
rdev->pm.dpm.dyn_state.cac_tdp_table->battery_power_limit = |
le16_to_cpu(pt->usBatteryPowerLimit); |
rdev->pm.dpm.dyn_state.cac_tdp_table->small_power_limit = |
le16_to_cpu(pt->usSmallPowerLimit); |
rdev->pm.dpm.dyn_state.cac_tdp_table->low_cac_leakage = |
le16_to_cpu(pt->usLowCACLeakage); |
rdev->pm.dpm.dyn_state.cac_tdp_table->high_cac_leakage = |
le16_to_cpu(pt->usHighCACLeakage); |
} |
} |
return 0; |
} |
void r600_free_extended_power_table(struct radeon_device *rdev) |
{ |
struct radeon_dpm_dynamic_state *dyn_state = &rdev->pm.dpm.dyn_state; |
kfree(dyn_state->vddc_dependency_on_sclk.entries); |
kfree(dyn_state->vddci_dependency_on_mclk.entries); |
kfree(dyn_state->vddc_dependency_on_mclk.entries); |
kfree(dyn_state->mvdd_dependency_on_mclk.entries); |
kfree(dyn_state->cac_leakage_table.entries); |
kfree(dyn_state->phase_shedding_limits_table.entries); |
kfree(dyn_state->ppm_table); |
kfree(dyn_state->cac_tdp_table); |
kfree(dyn_state->vce_clock_voltage_dependency_table.entries); |
kfree(dyn_state->uvd_clock_voltage_dependency_table.entries); |
kfree(dyn_state->samu_clock_voltage_dependency_table.entries); |
kfree(dyn_state->acp_clock_voltage_dependency_table.entries); |
} |
enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev, |
u32 sys_mask, |
enum radeon_pcie_gen asic_gen, |
enum radeon_pcie_gen default_gen) |
{ |
switch (asic_gen) { |
case RADEON_PCIE_GEN1: |
return RADEON_PCIE_GEN1; |
case RADEON_PCIE_GEN2: |
return RADEON_PCIE_GEN2; |
case RADEON_PCIE_GEN3: |
return RADEON_PCIE_GEN3; |
default: |
if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == RADEON_PCIE_GEN3)) |
return RADEON_PCIE_GEN3; |
else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == RADEON_PCIE_GEN2)) |
return RADEON_PCIE_GEN2; |
else |
return RADEON_PCIE_GEN1; |
} |
return RADEON_PCIE_GEN1; |
} |
u16 r600_get_pcie_lane_support(struct radeon_device *rdev, |
u16 asic_lanes, |
u16 default_lanes) |
{ |
switch (asic_lanes) { |
case 0: |
default: |
return default_lanes; |
case 1: |
return 1; |
case 2: |
return 2; |
case 4: |
return 4; |
case 8: |
return 8; |
case 12: |
return 12; |
case 16: |
return 16; |
} |
} |
u8 r600_encode_pci_lane_width(u32 lanes) |
{ |
u8 encoded_lanes[] = { 0, 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6 }; |
if (lanes > 16) |
return 0; |
return encoded_lanes[lanes]; |
} |
/drivers/video/drm/radeon/r600_dpm.h |
---|
0,0 → 1,233 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __R600_DPM_H__ |
#define __R600_DPM_H__ |
#define R600_ASI_DFLT 10000 |
#define R600_BSP_DFLT 0x41EB |
#define R600_BSU_DFLT 0x2 |
#define R600_AH_DFLT 5 |
#define R600_RLP_DFLT 25 |
#define R600_RMP_DFLT 65 |
#define R600_LHP_DFLT 40 |
#define R600_LMP_DFLT 15 |
#define R600_TD_DFLT 0 |
#define R600_UTC_DFLT_00 0x24 |
#define R600_UTC_DFLT_01 0x22 |
#define R600_UTC_DFLT_02 0x22 |
#define R600_UTC_DFLT_03 0x22 |
#define R600_UTC_DFLT_04 0x22 |
#define R600_UTC_DFLT_05 0x22 |
#define R600_UTC_DFLT_06 0x22 |
#define R600_UTC_DFLT_07 0x22 |
#define R600_UTC_DFLT_08 0x22 |
#define R600_UTC_DFLT_09 0x22 |
#define R600_UTC_DFLT_10 0x22 |
#define R600_UTC_DFLT_11 0x22 |
#define R600_UTC_DFLT_12 0x22 |
#define R600_UTC_DFLT_13 0x22 |
#define R600_UTC_DFLT_14 0x22 |
#define R600_DTC_DFLT_00 0x24 |
#define R600_DTC_DFLT_01 0x22 |
#define R600_DTC_DFLT_02 0x22 |
#define R600_DTC_DFLT_03 0x22 |
#define R600_DTC_DFLT_04 0x22 |
#define R600_DTC_DFLT_05 0x22 |
#define R600_DTC_DFLT_06 0x22 |
#define R600_DTC_DFLT_07 0x22 |
#define R600_DTC_DFLT_08 0x22 |
#define R600_DTC_DFLT_09 0x22 |
#define R600_DTC_DFLT_10 0x22 |
#define R600_DTC_DFLT_11 0x22 |
#define R600_DTC_DFLT_12 0x22 |
#define R600_DTC_DFLT_13 0x22 |
#define R600_DTC_DFLT_14 0x22 |
#define R600_VRC_DFLT 0x0000C003 |
#define R600_VOLTAGERESPONSETIME_DFLT 1000 |
#define R600_BACKBIASRESPONSETIME_DFLT 1000 |
#define R600_VRU_DFLT 0x3 |
#define R600_SPLLSTEPTIME_DFLT 0x1000 |
#define R600_SPLLSTEPUNIT_DFLT 0x3 |
#define R600_TPU_DFLT 0 |
#define R600_TPC_DFLT 0x200 |
#define R600_SSTU_DFLT 0 |
#define R600_SST_DFLT 0x00C8 |
#define R600_GICST_DFLT 0x200 |
#define R600_FCT_DFLT 0x0400 |
#define R600_FCTU_DFLT 0 |
#define R600_CTXCGTT3DRPHC_DFLT 0x20 |
#define R600_CTXCGTT3DRSDC_DFLT 0x40 |
#define R600_VDDC3DOORPHC_DFLT 0x100 |
#define R600_VDDC3DOORSDC_DFLT 0x7 |
#define R600_VDDC3DOORSU_DFLT 0 |
#define R600_MPLLLOCKTIME_DFLT 100 |
#define R600_MPLLRESETTIME_DFLT 150 |
#define R600_VCOSTEPPCT_DFLT 20 |
#define R600_ENDINGVCOSTEPPCT_DFLT 5 |
#define R600_REFERENCEDIVIDER_DFLT 4 |
#define R600_PM_NUMBER_OF_TC 15 |
#define R600_PM_NUMBER_OF_SCLKS 20 |
#define R600_PM_NUMBER_OF_MCLKS 4 |
#define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4 |
#define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3 |
/* XXX are these ok? */ |
#define R600_TEMP_RANGE_MIN (90 * 1000) |
#define R600_TEMP_RANGE_MAX (120 * 1000) |
enum r600_power_level { |
R600_POWER_LEVEL_LOW = 0, |
R600_POWER_LEVEL_MEDIUM = 1, |
R600_POWER_LEVEL_HIGH = 2, |
R600_POWER_LEVEL_CTXSW = 3, |
}; |
enum r600_td { |
R600_TD_AUTO, |
R600_TD_UP, |
R600_TD_DOWN, |
}; |
enum r600_display_watermark { |
R600_DISPLAY_WATERMARK_LOW = 0, |
R600_DISPLAY_WATERMARK_HIGH = 1, |
}; |
enum r600_display_gap |
{ |
R600_PM_DISPLAY_GAP_VBLANK_OR_WM = 0, |
R600_PM_DISPLAY_GAP_VBLANK = 1, |
R600_PM_DISPLAY_GAP_WATERMARK = 2, |
R600_PM_DISPLAY_GAP_IGNORE = 3, |
}; |
extern const u32 r600_utc[R600_PM_NUMBER_OF_TC]; |
extern const u32 r600_dtc[R600_PM_NUMBER_OF_TC]; |
void r600_dpm_print_class_info(u32 class, u32 class2); |
void r600_dpm_print_cap_info(u32 caps); |
void r600_dpm_print_ps_status(struct radeon_device *rdev, |
struct radeon_ps *rps); |
u32 r600_dpm_get_vblank_time(struct radeon_device *rdev); |
u32 r600_dpm_get_vrefresh(struct radeon_device *rdev); |
bool r600_is_uvd_state(u32 class, u32 class2); |
void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, |
u32 *p, u32 *u); |
int r600_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th); |
void r600_gfx_clockgating_enable(struct radeon_device *rdev, bool enable); |
void r600_dynamicpm_enable(struct radeon_device *rdev, bool enable); |
void r600_enable_thermal_protection(struct radeon_device *rdev, bool enable); |
void r600_enable_acpi_pm(struct radeon_device *rdev); |
void r600_enable_dynamic_pcie_gen2(struct radeon_device *rdev, bool enable); |
bool r600_dynamicpm_enabled(struct radeon_device *rdev); |
void r600_enable_sclk_control(struct radeon_device *rdev, bool enable); |
void r600_enable_mclk_control(struct radeon_device *rdev, bool enable); |
void r600_enable_spll_bypass(struct radeon_device *rdev, bool enable); |
void r600_wait_for_spll_change(struct radeon_device *rdev); |
void r600_set_bsp(struct radeon_device *rdev, u32 u, u32 p); |
void r600_set_at(struct radeon_device *rdev, |
u32 l_to_m, u32 m_to_h, |
u32 h_to_m, u32 m_to_l); |
void r600_set_tc(struct radeon_device *rdev, u32 index, u32 u_t, u32 d_t); |
void r600_select_td(struct radeon_device *rdev, enum r600_td td); |
void r600_set_vrc(struct radeon_device *rdev, u32 vrv); |
void r600_set_tpu(struct radeon_device *rdev, u32 u); |
void r600_set_tpc(struct radeon_device *rdev, u32 c); |
void r600_set_sstu(struct radeon_device *rdev, u32 u); |
void r600_set_sst(struct radeon_device *rdev, u32 t); |
void r600_set_git(struct radeon_device *rdev, u32 t); |
void r600_set_fctu(struct radeon_device *rdev, u32 u); |
void r600_set_fct(struct radeon_device *rdev, u32 t); |
void r600_set_ctxcgtt3d_rphc(struct radeon_device *rdev, u32 p); |
void r600_set_ctxcgtt3d_rsdc(struct radeon_device *rdev, u32 s); |
void r600_set_vddc3d_oorsu(struct radeon_device *rdev, u32 u); |
void r600_set_vddc3d_oorphc(struct radeon_device *rdev, u32 p); |
void r600_set_vddc3d_oorsdc(struct radeon_device *rdev, u32 s); |
void r600_set_mpll_lock_time(struct radeon_device *rdev, u32 lock_time); |
void r600_set_mpll_reset_time(struct radeon_device *rdev, u32 reset_time); |
void r600_engine_clock_entry_enable(struct radeon_device *rdev, |
u32 index, bool enable); |
void r600_engine_clock_entry_enable_pulse_skipping(struct radeon_device *rdev, |
u32 index, bool enable); |
void r600_engine_clock_entry_enable_post_divider(struct radeon_device *rdev, |
u32 index, bool enable); |
void r600_engine_clock_entry_set_post_divider(struct radeon_device *rdev, |
u32 index, u32 divider); |
void r600_engine_clock_entry_set_reference_divider(struct radeon_device *rdev, |
u32 index, u32 divider); |
void r600_engine_clock_entry_set_feedback_divider(struct radeon_device *rdev, |
u32 index, u32 divider); |
void r600_engine_clock_entry_set_step_time(struct radeon_device *rdev, |
u32 index, u32 step_time); |
void r600_vid_rt_set_ssu(struct radeon_device *rdev, u32 u); |
void r600_vid_rt_set_vru(struct radeon_device *rdev, u32 u); |
void r600_vid_rt_set_vrt(struct radeon_device *rdev, u32 rt); |
void r600_voltage_control_enable_pins(struct radeon_device *rdev, |
u64 mask); |
void r600_voltage_control_program_voltages(struct radeon_device *rdev, |
enum r600_power_level index, u64 pins); |
void r600_voltage_control_deactivate_static_control(struct radeon_device *rdev, |
u64 mask); |
void r600_power_level_enable(struct radeon_device *rdev, |
enum r600_power_level index, bool enable); |
void r600_power_level_set_voltage_index(struct radeon_device *rdev, |
enum r600_power_level index, u32 voltage_index); |
void r600_power_level_set_mem_clock_index(struct radeon_device *rdev, |
enum r600_power_level index, u32 mem_clock_index); |
void r600_power_level_set_eng_clock_index(struct radeon_device *rdev, |
enum r600_power_level index, u32 eng_clock_index); |
void r600_power_level_set_watermark_id(struct radeon_device *rdev, |
enum r600_power_level index, |
enum r600_display_watermark watermark_id); |
void r600_power_level_set_pcie_gen2(struct radeon_device *rdev, |
enum r600_power_level index, bool compatible); |
enum r600_power_level r600_power_level_get_current_index(struct radeon_device *rdev); |
enum r600_power_level r600_power_level_get_target_index(struct radeon_device *rdev); |
void r600_power_level_set_enter_index(struct radeon_device *rdev, |
enum r600_power_level index); |
void r600_wait_for_power_level_unequal(struct radeon_device *rdev, |
enum r600_power_level index); |
void r600_wait_for_power_level(struct radeon_device *rdev, |
enum r600_power_level index); |
void r600_start_dpm(struct radeon_device *rdev); |
void r600_stop_dpm(struct radeon_device *rdev); |
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); |
enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev, |
u32 sys_mask, |
enum radeon_pcie_gen asic_gen, |
enum radeon_pcie_gen default_gen); |
u16 r600_get_pcie_lane_support(struct radeon_device *rdev, |
u16 asic_lanes, |
u16 default_lanes); |
u8 r600_encode_pci_lane_width(u32 lanes); |
#endif |
/drivers/video/drm/radeon/r600_hdmi.c |
---|
57,28 → 57,57 |
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 → 115,16 |
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 → 132,7 |
/* |
* 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 → 141,33 |
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_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(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(acr.cts_44_1khz)); |
WREG32(HDMI0_ACR_44_1 + offset, acr.n_44_1khz); |
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(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_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; |
133,15 → 175,8 |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
uint32_t offset = dig->afmt->offset; |
uint8_t *frame = buffer + 3; |
uint8_t *header = buffer; |
/* Our header values (type, version, length) should be alright, Intel |
* is using the same. Checksum function also seems to be OK, it works |
* fine for audio infoframe. However calculated value is always lower |
* by 2 in comparison to fglrx. It breaks displaying anything in case |
* of TVs that strictly check the checksum. Hack it manually here to |
* workaround this issue. */ |
frame[0x0] += 2; |
WREG32(HDMI0_AVI_INFO0 + offset, |
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); |
WREG32(HDMI0_AVI_INFO1 + offset, |
149,7 → 184,7 |
WREG32(HDMI0_AVI_INFO2 + offset, |
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); |
WREG32(HDMI0_AVI_INFO3 + offset, |
frame[0xC] | (frame[0xD] << 8)); |
frame[0xC] | (frame[0xD] << 8) | (header[1] << 24)); |
} |
/* |
207,7 → 242,7 |
/* |
* 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; |
233,10 → 268,29 |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
u32 base_rate = 24000; |
u32 max_ratio = clock / base_rate; |
u32 dto_phase; |
u32 dto_modulo = clock; |
u32 wallclock_ratio; |
u32 dto_cntl; |
if (!dig || !dig->afmt) |
return; |
if (max_ratio >= 8) { |
dto_phase = 192 * 1000; |
wallclock_ratio = 3; |
} else if (max_ratio >= 4) { |
dto_phase = 96 * 1000; |
wallclock_ratio = 2; |
} else if (max_ratio >= 2) { |
dto_phase = 48 * 1000; |
wallclock_ratio = 1; |
} else { |
dto_phase = 24 * 1000; |
wallclock_ratio = 0; |
} |
/* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT. |
* doesn't matter which one you use. Just use the first one. |
*/ |
245,19 → 299,37 |
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE |
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator |
*/ |
if (ASIC_IS_DCE3(rdev)) { |
if (ASIC_IS_DCE32(rdev)) { |
if (dig->dig_encoder == 0) { |
dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; |
dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); |
WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); |
WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); |
WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo); |
WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ |
} else { |
dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; |
dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); |
WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl); |
WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase); |
WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo); |
WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ |
} |
} else { |
/* according to the reg specs, this should DCE3.2 only, but in |
* practice it seems to cover DCE3.0 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); |
WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); |
WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ |
} else { |
/* according to the reg specs, this should be DCE2.0 and DCE3.0 */ |
WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate / 10) | |
AUDIO_DTO_MODULE(clock / 10)); |
WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100); |
WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100); |
WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ |
} |
} |
} |
/* |
* update the info frames with the data from the current display mode |
271,56 → 343,61 |
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; |
struct hdmi_avi_infoframe frame; |
uint32_t offset; |
uint32_t acr_ctl; |
ssize_t err; |
if (!dig || !dig->afmt) |
return; |
/* Silent, r600_hdmi_enable will raise WARN for us */ |
if (!dig->afmt->enabled) |
return; |
offset = dig->afmt->offset; |
// r600_audio_set_clock(encoder, mode->clock); |
/* 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_VBI_PACKET_CONTROL + offset, |
HDMI0_NULL_SEND); /* send null packets when required */ |
r600_audio_set_dto(encoder, mode->clock); |
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, |
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_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */ |
~(HDMI0_AUDIO_SAMPLE_SEND | |
HDMI0_AUDIO_DELAY_EN_MASK | |
HDMI0_AUDIO_PACKETS_PER_LINE_MASK | |
HDMI0_60958_CS_UPDATE)); |
WREG32(HDMI0_ACR_PACKET_CONTROL + offset, |
HDMI0_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ |
HDMI0_ACR_SOURCE); /* select SW CTS value */ |
/* 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(HDMI0_VBI_PACKET_CONTROL + offset, |
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 */ |
/* TODO: HDMI0_AUDIO_INFO_UPDATE */ |
WREG32(HDMI0_INFOFRAME_CONTROL0 + offset, |
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_CONT); /* send audio info frames every frame/field */ |
HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ |
WREG32(HDMI0_INFOFRAME_CONTROL1 + offset, |
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_AUDIO_INFO_LINE(2), /* anything other than 0 */ |
~(HDMI0_AVI_INFO_LINE_MASK | |
HDMI0_AUDIO_INFO_LINE_MASK)); |
WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */ |
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) { |
335,8 → 412,29 |
} |
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); |
343,12 → 441,16 |
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); |
} |
#if 0 |
/* |
* 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) |
{ |
356,11 → 458,11 |
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 r600_audio audio = r600_audio_status(rdev); |
struct r600_audio_pin audio = r600_audio_status(rdev); |
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) |
373,60 → 475,6 |
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"); |
441,10 → 489,23 |
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); |
} |
#endif |
/* |
* enable the HDMI engine |
457,6 → 518,9 |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
u32 hdmi = HDMI0_ERROR_ACK; |
if (!dig || !dig->afmt) |
return; |
/* Silent, r600_hdmi_enable will raise WARN for us */ |
if (enable && dig->afmt->enabled) |
return; |
/drivers/video/drm/radeon/r600_reg.h |
---|
31,6 → 31,12 |
#define R600_PCIE_PORT_INDEX 0x0038 |
#define R600_PCIE_PORT_DATA 0x003c |
#define R600_RCU_INDEX 0x0100 |
#define R600_RCU_DATA 0x0104 |
#define R600_UVD_CTX_INDEX 0xf4a0 |
#define R600_UVD_CTX_DATA 0xf4a4 |
#define R600_MC_VM_FB_LOCATION 0x2180 |
#define R600_MC_FB_BASE_MASK 0x0000FFFF |
#define R600_MC_FB_BASE_SHIFT 0 |
/drivers/video/drm/radeon/r600_reg_safe.h |
---|
0,0 → 1,490 |
static const unsigned r600_reg_safe_bm[1952] = { |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFEFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFEF, 0xFFFFFFFF, 0xCFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFBD1EFFF, 0xCF3FFFFF, 0xFFFFFFFF, |
0xFFFFFFDF, 0xFFFFFFFF, 0xFFF0FEEF, 0xEFFFFFFF, |
0xFFFFFFC1, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF7, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFDF, 0xFFFFFFFF, 0xFFFF7FFE, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0x00000000, 0xFFFFFFF0, 0xFFFFFFFB, 0xFFFFFFFF, |
0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFDE, 0xFFFFFFFF, |
0xFFFFAFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0x00000000, 0x00000000, 0xFFFFFF00, 0xFFFFFFFF, |
0x00000000, 0x00000000, 0xFFFFFF00, 0xFFFFFFFF, |
0x00000000, 0x00000000, 0xFFFFFF00, 0xFFFFFFFF, |
0xFFFC0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFC3FF, 0xFFFFFFFF, 0x0000F0FF, 0x00000000, |
0x000CE000, 0x00000000, 0xFFD00000, 0x00000000, |
0x00000000, 0x00000000, 0x00000000, 0xFFFF8000, |
0x0001801F, 0xFC000000, 0xFFFFFFFF, 0xFFFFFE00, |
0x7BCFFE05, 0xFE07FDEF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xF7E20000, 0xDDDF9CDD, 0xFFFFA3FD, 0xFFFFFFFF, |
0xFFFB0E02, 0xFFFFFFFF, 0xFFFDC3E7, 0x3FFFFFFF, |
0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xDFFFFFFF, |
}; |
/drivers/video/drm/radeon/r600d.h |
---|
302,11 → 302,26 |
#define GRBM_SOFT_RESET 0x8020 |
#define SOFT_RESET_CP (1<<0) |
#define CG_THERMAL_CTRL 0x7F0 |
#define DIG_THERM_DPM(x) ((x) << 12) |
#define DIG_THERM_DPM_MASK 0x000FF000 |
#define DIG_THERM_DPM_SHIFT 12 |
#define CG_THERMAL_STATUS 0x7F4 |
#define ASIC_T(x) ((x) << 0) |
#define ASIC_T_MASK 0x1FF |
#define ASIC_T_SHIFT 0 |
#define CG_THERMAL_INT 0x7F8 |
#define DIG_THERM_INTH(x) ((x) << 8) |
#define DIG_THERM_INTH_MASK 0x0000FF00 |
#define DIG_THERM_INTH_SHIFT 8 |
#define DIG_THERM_INTL(x) ((x) << 16) |
#define DIG_THERM_INTL_MASK 0x00FF0000 |
#define DIG_THERM_INTL_SHIFT 16 |
#define THERM_INT_MASK_HIGH (1 << 24) |
#define THERM_INT_MASK_LOW (1 << 25) |
#define RV770_CG_THERMAL_INT 0x734 |
#define HDP_HOST_PATH_CNTL 0x2C00 |
#define HDP_NONSURFACE_BASE 0x2C04 |
#define HDP_NONSURFACE_INFO 0x2C08 |
587,6 → 602,7 |
#define L2_BUSY (1 << 0) |
#define WAIT_UNTIL 0x8040 |
#define WAIT_CP_DMA_IDLE_bit (1 << 8) |
#define WAIT_2D_IDLE_bit (1 << 14) |
#define WAIT_3D_IDLE_bit (1 << 15) |
#define WAIT_2D_IDLECLEAN_bit (1 << 16) |
684,16 → 700,19 |
#define RLC_UCODE_ADDR 0x3f2c |
#define RLC_UCODE_DATA 0x3f30 |
/* new for TN */ |
#define TN_RLC_SAVE_AND_RESTORE_BASE 0x3f10 |
#define TN_RLC_CLEAR_STATE_RESTORE_BASE 0x3f20 |
#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) |
921,6 → 940,9 |
#define DCCG_AUDIO_DTO0_LOAD 0x051c |
# define DTO_LOAD (1 << 31) |
#define DCCG_AUDIO_DTO0_CNTL 0x0520 |
# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0) |
# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7 |
# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0 |
#define DCCG_AUDIO_DTO1_PHASE 0x0524 |
#define DCCG_AUDIO_DTO1_MODULE 0x0528 |
945,6 → 967,42 |
# define DIG_MODE_SDVO 4 |
#define DIG1_CNTL 0x79a0 |
#define AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER 0x71bc |
#define SPEAKER_ALLOCATION(x) (((x) & 0x7f) << 0) |
#define SPEAKER_ALLOCATION_MASK (0x7f << 0) |
#define SPEAKER_ALLOCATION_SHIFT 0 |
#define HDMI_CONNECTION (1 << 16) |
#define DP_CONNECTION (1 << 17) |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0 0x71c8 /* LPCM */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1 0x71cc /* AC3 */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2 0x71d0 /* MPEG1 */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3 0x71d4 /* MP3 */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4 0x71d8 /* MPEG2 */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5 0x71dc /* AAC */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6 0x71e0 /* DTS */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7 0x71e4 /* ATRAC */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR8 0x71e8 /* one bit audio - leave at 0 (default) */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9 0x71ec /* Dolby Digital */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10 0x71f0 /* DTS-HD */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11 0x71f4 /* MAT-MLP */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR12 0x71f8 /* DTS */ |
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13 0x71fc /* WMA Pro */ |
# define MAX_CHANNELS(x) (((x) & 0x7) << 0) |
/* max channels minus one. 7 = 8 channels */ |
# define SUPPORTED_FREQUENCIES(x) (((x) & 0xff) << 8) |
# define DESCRIPTOR_BYTE_2(x) (((x) & 0xff) << 16) |
# define SUPPORTED_FREQUENCIES_STEREO(x) (((x) & 0xff) << 24) /* LPCM only */ |
/* SUPPORTED_FREQUENCIES, SUPPORTED_FREQUENCIES_STEREO |
* bit0 = 32 kHz |
* bit1 = 44.1 kHz |
* bit2 = 48 kHz |
* bit3 = 88.2 kHz |
* bit4 = 96 kHz |
* bit5 = 176.4 kHz |
* bit6 = 192 kHz |
*/ |
/* rs6xx/rs740 and r6xx share the same HDMI blocks, however, rs6xx has only one |
* instance of the blocks while r6xx has 2. DCE 3.0 cards are slightly |
* different due to the new DIG blocks, but also have 2 instances. |
971,9 → 1029,11 |
#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) |
980,6 → 1040,7 |
# 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) |
989,7 → 1050,7 |
# define HDMI0_AVI_INFO_CONT (1 << 1) |
# define HDMI0_AUDIO_INFO_SEND (1 << 4) |
# define HDMI0_AUDIO_INFO_CONT (1 << 5) |
# define HDMI0_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hmdi regs */ |
# define HDMI0_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hdmi regs */ |
# define HDMI0_AUDIO_INFO_UPDATE (1 << 7) |
# define HDMI0_MPEG_INFO_SEND (1 << 8) |
# define HDMI0_MPEG_INFO_CONT (1 << 9) |
996,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) |
1005,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 |
1061,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 |
1090,8 → 1161,10 |
# 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) |
1098,6 → 1171,7 |
# 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) |
1108,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 |
1148,6 → 1223,247 |
# 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) |
# define SPLL_SLEEP (1 << 1) |
# define SPLL_REF_DIV(x) ((x) << 2) |
# define SPLL_REF_DIV_MASK (7 << 2) |
# define SPLL_FB_DIV(x) ((x) << 5) |
# define SPLL_FB_DIV_MASK (0xff << 5) |
# define SPLL_PULSEEN (1 << 13) |
# define SPLL_PULSENUM(x) ((x) << 14) |
# define SPLL_PULSENUM_MASK (3 << 14) |
# define SPLL_SW_HILEN(x) ((x) << 16) |
# define SPLL_SW_HILEN_MASK (0xf << 16) |
# define SPLL_SW_LOLEN(x) ((x) << 20) |
# define SPLL_SW_LOLEN_MASK (0xf << 20) |
# define SPLL_DIVEN (1 << 24) |
# define SPLL_BYPASS_EN (1 << 25) |
# define SPLL_CHG_STATUS (1 << 29) |
# define SPLL_CTLREQ (1 << 30) |
# define SPLL_CTLACK (1 << 31) |
#define GENERAL_PWRMGT 0x618 |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define MOBILE_SU (1 << 2) |
# define THERMAL_PROTECTION_DIS (1 << 3) |
# define THERMAL_PROTECTION_TYPE (1 << 4) |
# define ENABLE_GEN2PCIE (1 << 5) |
# define SW_GPIO_INDEX(x) ((x) << 6) |
# define SW_GPIO_INDEX_MASK (3 << 6) |
# define LOW_VOLT_D2_ACPI (1 << 8) |
# define LOW_VOLT_D3_ACPI (1 << 9) |
# define VOLT_PWRMGT_EN (1 << 10) |
#define CG_TPC 0x61c |
# define TPCC(x) ((x) << 0) |
# define TPCC_MASK (0x7fffff << 0) |
# define TPU(x) ((x) << 23) |
# define TPU_MASK (0x1f << 23) |
#define SCLK_PWRMGT_CNTL 0x620 |
# define SCLK_PWRMGT_OFF (1 << 0) |
# define SCLK_TURNOFF (1 << 1) |
# define SPLL_TURNOFF (1 << 2) |
# define SU_SCLK_USE_BCLK (1 << 3) |
# define DYNAMIC_GFX_ISLAND_PWR_DOWN (1 << 4) |
# define DYNAMIC_GFX_ISLAND_PWR_LP (1 << 5) |
# define CLK_TURN_ON_STAGGER (1 << 6) |
# define CLK_TURN_OFF_STAGGER (1 << 7) |
# define FIR_FORCE_TREND_SEL (1 << 8) |
# define FIR_TREND_MODE (1 << 9) |
# define DYN_GFX_CLK_OFF_EN (1 << 10) |
# define VDDC3D_TURNOFF_D1 (1 << 11) |
# define VDDC3D_TURNOFF_D2 (1 << 12) |
# define VDDC3D_TURNOFF_D3 (1 << 13) |
# define SPLL_TURNOFF_D2 (1 << 14) |
# define SCLK_LOW_D1 (1 << 15) |
# define DYN_GFX_CLK_OFF_MC_EN (1 << 16) |
#define MCLK_PWRMGT_CNTL 0x624 |
# define MPLL_PWRMGT_OFF (1 << 0) |
# define YCLK_TURNOFF (1 << 1) |
# define MPLL_TURNOFF (1 << 2) |
# define SU_MCLK_USE_BCLK (1 << 3) |
# define DLL_READY (1 << 4) |
# define MC_BUSY (1 << 5) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCKA_SLEEP (1 << 8) |
# define MRDCKB_SLEEP (1 << 9) |
# define MRDCKC_SLEEP (1 << 10) |
# define MRDCKD_SLEEP (1 << 11) |
# define MRDCKE_SLEEP (1 << 12) |
# define MRDCKF_SLEEP (1 << 13) |
# define MRDCKG_SLEEP (1 << 14) |
# define MRDCKH_SLEEP (1 << 15) |
# define MRDCKA_RESET (1 << 16) |
# define MRDCKB_RESET (1 << 17) |
# define MRDCKC_RESET (1 << 18) |
# define MRDCKD_RESET (1 << 19) |
# define MRDCKE_RESET (1 << 20) |
# define MRDCKF_RESET (1 << 21) |
# define MRDCKG_RESET (1 << 22) |
# define MRDCKH_RESET (1 << 23) |
# define DLL_READY_READ (1 << 24) |
# define USE_DISPLAY_GAP (1 << 25) |
# define USE_DISPLAY_URGENT_NORMAL (1 << 26) |
# define USE_DISPLAY_GAP_CTXSW (1 << 27) |
# define MPLL_TURNOFF_D2 (1 << 28) |
# define USE_DISPLAY_URGENT_CTXSW (1 << 29) |
#define MPLL_TIME 0x634 |
# define MPLL_LOCK_TIME(x) ((x) << 0) |
# define MPLL_LOCK_TIME_MASK (0xffff << 0) |
# define MPLL_RESET_TIME(x) ((x) << 16) |
# define MPLL_RESET_TIME_MASK (0xffff << 16) |
#define SCLK_FREQ_SETTING_STEP_0_PART1 0x648 |
# define STEP_0_SPLL_POST_DIV(x) ((x) << 0) |
# define STEP_0_SPLL_POST_DIV_MASK (0xff << 0) |
# define STEP_0_SPLL_FB_DIV(x) ((x) << 8) |
# define STEP_0_SPLL_FB_DIV_MASK (0xff << 8) |
# define STEP_0_SPLL_REF_DIV(x) ((x) << 16) |
# define STEP_0_SPLL_REF_DIV_MASK (7 << 16) |
# define STEP_0_SPLL_STEP_TIME(x) ((x) << 19) |
# define STEP_0_SPLL_STEP_TIME_MASK (0x1fff << 19) |
#define SCLK_FREQ_SETTING_STEP_0_PART2 0x64c |
# define STEP_0_PULSE_HIGH_CNT(x) ((x) << 0) |
# define STEP_0_PULSE_HIGH_CNT_MASK (0x1ff << 0) |
# define STEP_0_POST_DIV_EN (1 << 9) |
# define STEP_0_SPLL_STEP_ENABLE (1 << 30) |
# define STEP_0_SPLL_ENTRY_VALID (1 << 31) |
#define VID_RT 0x6f8 |
# define VID_CRT(x) ((x) << 0) |
# define VID_CRT_MASK (0x1fff << 0) |
# define VID_CRTU(x) ((x) << 13) |
# define VID_CRTU_MASK (7 << 13) |
# define SSTU(x) ((x) << 16) |
# define SSTU_MASK (7 << 16) |
#define CTXSW_PROFILE_INDEX 0x6fc |
# define CTXSW_FREQ_VIDS_CFG_INDEX(x) ((x) << 0) |
# define CTXSW_FREQ_VIDS_CFG_INDEX_MASK (3 << 0) |
# define CTXSW_FREQ_VIDS_CFG_INDEX_SHIFT 0 |
# define CTXSW_FREQ_MCLK_CFG_INDEX(x) ((x) << 2) |
# define CTXSW_FREQ_MCLK_CFG_INDEX_MASK (3 << 2) |
# define CTXSW_FREQ_MCLK_CFG_INDEX_SHIFT 2 |
# define CTXSW_FREQ_SCLK_CFG_INDEX(x) ((x) << 4) |
# define CTXSW_FREQ_SCLK_CFG_INDEX_MASK (0x1f << 4) |
# define CTXSW_FREQ_SCLK_CFG_INDEX_SHIFT 4 |
# define CTXSW_FREQ_STATE_SPLL_RESET_EN (1 << 9) |
# define CTXSW_FREQ_STATE_ENABLE (1 << 10) |
# define CTXSW_FREQ_DISPLAY_WATERMARK (1 << 11) |
# define CTXSW_FREQ_GEN2PCIE_VOLT (1 << 12) |
#define TARGET_AND_CURRENT_PROFILE_INDEX 0x70c |
# define TARGET_PROFILE_INDEX_MASK (3 << 0) |
# define TARGET_PROFILE_INDEX_SHIFT 0 |
# define CURRENT_PROFILE_INDEX_MASK (3 << 2) |
# define CURRENT_PROFILE_INDEX_SHIFT 2 |
# define DYN_PWR_ENTER_INDEX(x) ((x) << 4) |
# define DYN_PWR_ENTER_INDEX_MASK (3 << 4) |
# define DYN_PWR_ENTER_INDEX_SHIFT 4 |
# define CURR_MCLK_INDEX_MASK (3 << 6) |
# define CURR_MCLK_INDEX_SHIFT 6 |
# define CURR_SCLK_INDEX_MASK (0x1f << 8) |
# define CURR_SCLK_INDEX_SHIFT 8 |
# define CURR_VID_INDEX_MASK (3 << 13) |
# define CURR_VID_INDEX_SHIFT 13 |
#define LOWER_GPIO_ENABLE 0x710 |
#define UPPER_GPIO_ENABLE 0x714 |
#define CTXSW_VID_LOWER_GPIO_CNTL 0x718 |
#define VID_UPPER_GPIO_CNTL 0x740 |
#define CG_CTX_CGTT3D_R 0x744 |
# define PHC(x) ((x) << 0) |
# define PHC_MASK (0x1ff << 0) |
# define SDC(x) ((x) << 9) |
# define SDC_MASK (0x3fff << 9) |
#define CG_VDDC3D_OOR 0x748 |
# define SU(x) ((x) << 23) |
# define SU_MASK (0xf << 23) |
#define CG_FTV 0x74c |
#define CG_FFCT_0 0x750 |
# define UTC_0(x) ((x) << 0) |
# define UTC_0_MASK (0x3ff << 0) |
# define DTC_0(x) ((x) << 10) |
# define DTC_0_MASK (0x3ff << 10) |
#define CG_BSP 0x78c |
# define BSP(x) ((x) << 0) |
# define BSP_MASK (0xffff << 0) |
# define BSU(x) ((x) << 16) |
# define BSU_MASK (0xf << 16) |
#define CG_RT 0x790 |
# define FLS(x) ((x) << 0) |
# define FLS_MASK (0xffff << 0) |
# define FMS(x) ((x) << 16) |
# define FMS_MASK (0xffff << 16) |
#define CG_LT 0x794 |
# define FHS(x) ((x) << 0) |
# define FHS_MASK (0xffff << 0) |
#define CG_GIT 0x798 |
# define CG_GICST(x) ((x) << 0) |
# define CG_GICST_MASK (0xffff << 0) |
# define CG_GIPOT(x) ((x) << 16) |
# define CG_GIPOT_MASK (0xffff << 16) |
#define CG_SSP 0x7a8 |
# define CG_SST(x) ((x) << 0) |
# define CG_SST_MASK (0xffff << 0) |
# define CG_SSTU(x) ((x) << 16) |
# define CG_SSTU_MASK (0xf << 16) |
#define CG_RLC_REQ_AND_RSP 0x7c4 |
# define RLC_CG_REQ_TYPE_MASK 0xf |
# define RLC_CG_REQ_TYPE_SHIFT 0 |
# define CG_RLC_RSP_TYPE_MASK 0xf0 |
# define CG_RLC_RSP_TYPE_SHIFT 4 |
#define CG_FC_T 0x7cc |
# define FC_T(x) ((x) << 0) |
# define FC_T_MASK (0xffff << 0) |
# define FC_TU(x) ((x) << 16) |
# define FC_TU_MASK (0x1f << 16) |
#define GPIOPAD_MASK 0x1798 |
#define GPIOPAD_A 0x179c |
#define GPIOPAD_EN 0x17a0 |
#define GRBM_PWR_CNTL 0x800c |
# define REQ_TYPE_MASK 0xf |
# define REQ_TYPE_SHIFT 0 |
# define RSP_TYPE_MASK 0xf0 |
# define RSP_TYPE_SHIFT 4 |
/* |
* UVD |
*/ |
1259,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 |
1281,8 → 1597,10 |
*/ |
# define PACKET3_CP_DMA_CMD_SAIC (1 << 28) |
# define PACKET3_CP_DMA_CMD_DAIC (1 << 29) |
#define PACKET3_PFP_SYNC_ME 0x42 /* r7xx+ only */ |
#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) |
/drivers/video/drm/radeon/radeon.h |
---|
64,12 → 64,14 |
#include <linux/wait.h> |
#include <linux/list.h> |
#include <linux/kref.h> |
#include <linux/interval_tree.h> |
#include <asm/div64.h> |
#include <ttm/ttm_bo_api.h> |
#include <ttm/ttm_bo_driver.h> |
#include <ttm/ttm_placement.h> |
#include <ttm/ttm_module.h> |
//#include <ttm/ttm_module.h> |
#include <ttm/ttm_execbuf_util.h> |
#include <linux/irqreturn.h> |
#include <pci.h> |
103,6 → 105,15 |
extern int radeon_msi; |
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; |
extern int radeon_use_pflipirq; |
extern int radeon_bapm; |
typedef struct pm_message { |
142,9 → 153,6 |
#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 |
164,11 → 172,27 |
/* R600+ */ |
#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) |
183,6 → 207,54 |
#define RADEON_RESET_MC (1 << 10) |
#define RADEON_RESET_DISPLAY (1 << 11) |
/* CG block flags */ |
#define RADEON_CG_BLOCK_GFX (1 << 0) |
#define RADEON_CG_BLOCK_MC (1 << 1) |
#define RADEON_CG_BLOCK_SDMA (1 << 2) |
#define RADEON_CG_BLOCK_UVD (1 << 3) |
#define RADEON_CG_BLOCK_VCE (1 << 4) |
#define RADEON_CG_BLOCK_HDP (1 << 5) |
#define RADEON_CG_BLOCK_BIF (1 << 6) |
/* CG flags */ |
#define RADEON_CG_SUPPORT_GFX_MGCG (1 << 0) |
#define RADEON_CG_SUPPORT_GFX_MGLS (1 << 1) |
#define RADEON_CG_SUPPORT_GFX_CGCG (1 << 2) |
#define RADEON_CG_SUPPORT_GFX_CGLS (1 << 3) |
#define RADEON_CG_SUPPORT_GFX_CGTS (1 << 4) |
#define RADEON_CG_SUPPORT_GFX_CGTS_LS (1 << 5) |
#define RADEON_CG_SUPPORT_GFX_CP_LS (1 << 6) |
#define RADEON_CG_SUPPORT_GFX_RLC_LS (1 << 7) |
#define RADEON_CG_SUPPORT_MC_LS (1 << 8) |
#define RADEON_CG_SUPPORT_MC_MGCG (1 << 9) |
#define RADEON_CG_SUPPORT_SDMA_LS (1 << 10) |
#define RADEON_CG_SUPPORT_SDMA_MGCG (1 << 11) |
#define RADEON_CG_SUPPORT_BIF_LS (1 << 12) |
#define RADEON_CG_SUPPORT_UVD_MGCG (1 << 13) |
#define RADEON_CG_SUPPORT_VCE_MGCG (1 << 14) |
#define RADEON_CG_SUPPORT_HDP_LS (1 << 15) |
#define RADEON_CG_SUPPORT_HDP_MGCG (1 << 16) |
/* PG flags */ |
#define RADEON_PG_SUPPORT_GFX_PG (1 << 0) |
#define RADEON_PG_SUPPORT_GFX_SMG (1 << 1) |
#define RADEON_PG_SUPPORT_GFX_DMG (1 << 2) |
#define RADEON_PG_SUPPORT_UVD (1 << 3) |
#define RADEON_PG_SUPPORT_VCE (1 << 4) |
#define RADEON_PG_SUPPORT_CP (1 << 5) |
#define RADEON_PG_SUPPORT_GDS (1 << 6) |
#define RADEON_PG_SUPPORT_RLC_SMU_HS (1 << 7) |
#define RADEON_PG_SUPPORT_SDMA (1 << 8) |
#define RADEON_PG_SUPPORT_ACP (1 << 9) |
#define RADEON_PG_SUPPORT_SAMU (1 << 10) |
/* max cursor sizes (in pixels) */ |
#define CURSOR_WIDTH 64 |
#define CURSOR_HEIGHT 64 |
#define CIK_CURSOR_WIDTH 128 |
#define CIK_CURSOR_HEIGHT 128 |
/* |
* Errata workarounds. |
*/ |
225,6 → 297,7 |
uint32_t default_mclk; |
uint32_t default_sclk; |
uint32_t default_dispclk; |
uint32_t current_dispclk; |
uint32_t dp_extclk; |
uint32_t max_pixel_clock; |
}; |
233,6 → 306,7 |
* 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); |
244,13 → 318,63 |
u32 clock, |
bool strobe_mode, |
struct atom_clock_dividers *dividers); |
int radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev, |
u32 clock, |
bool strobe_mode, |
struct atom_mpll_param *mpll_param); |
void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type); |
int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev, |
u16 voltage_level, u8 voltage_type, |
u32 *gpio_value, u32 *gpio_mask); |
void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev, |
u32 eng_clock, u32 mem_clock); |
int radeon_atom_get_voltage_step(struct radeon_device *rdev, |
u8 voltage_type, u16 *voltage_step); |
int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, |
u16 voltage_id, u16 *voltage); |
int radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev, |
u16 *voltage, |
u16 leakage_idx); |
int radeon_atom_get_leakage_id_from_vbios(struct radeon_device *rdev, |
u16 *leakage_id); |
int radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *rdev, |
u16 *vddc, u16 *vddci, |
u16 virtual_voltage_id, |
u16 vbios_voltage_id); |
int radeon_atom_get_voltage_evv(struct radeon_device *rdev, |
u16 virtual_voltage_id, |
u16 *voltage); |
int radeon_atom_round_to_true_voltage(struct radeon_device *rdev, |
u8 voltage_type, |
u16 nominal_voltage, |
u16 *true_voltage); |
int radeon_atom_get_min_voltage(struct radeon_device *rdev, |
u8 voltage_type, u16 *min_voltage); |
int radeon_atom_get_max_voltage(struct radeon_device *rdev, |
u8 voltage_type, u16 *max_voltage); |
int radeon_atom_get_voltage_table(struct radeon_device *rdev, |
u8 voltage_type, u8 voltage_mode, |
struct atom_voltage_table *voltage_table); |
bool radeon_atom_is_voltage_gpio(struct radeon_device *rdev, |
u8 voltage_type, u8 voltage_mode); |
int radeon_atom_get_svi2_info(struct radeon_device *rdev, |
u8 voltage_type, |
u8 *svd_gpio_id, u8 *svc_gpio_id); |
void radeon_atom_update_memory_dll(struct radeon_device *rdev, |
u32 mem_clock); |
void radeon_atom_set_ac_timing(struct radeon_device *rdev, |
u32 mem_clock); |
int radeon_atom_init_mc_reg_table(struct radeon_device *rdev, |
u8 module_index, |
struct atom_mc_reg_table *reg_table); |
int radeon_atom_get_memory_info(struct radeon_device *rdev, |
u8 module_index, struct atom_memory_info *mem_info); |
int radeon_atom_get_mclk_range_table(struct radeon_device *rdev, |
bool gddr5, u8 module_index, |
struct atom_memory_clock_range_table *mclk_range_table); |
int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, |
u16 voltage_id, u16 *voltage); |
void rs690_pm_info(struct radeon_device *rdev); |
extern int rv6xx_get_temp(struct radeon_device *rdev); |
extern int rv770_get_temp(struct radeon_device *rdev); |
extern int evergreen_get_temp(struct radeon_device *rdev); |
extern int sumo_get_temp(struct radeon_device *rdev); |
extern int si_get_temp(struct radeon_device *rdev); |
extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw, |
unsigned *bankh, unsigned *mtaspect, |
unsigned *tile_split); |
265,7 → 389,6 |
/* 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; |
}; |
286,8 → 409,8 |
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); |
350,6 → 473,11 |
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 */ |
356,14 → 484,13 |
struct radeon_bo_va { |
/* protected by bo being reserved */ |
struct list_head bo_list; |
uint64_t soffset; |
uint64_t eoffset; |
uint32_t flags; |
bool valid; |
uint64_t addr; |
unsigned ref_count; |
/* protected by vm mutex */ |
struct list_head vm_list; |
struct interval_tree_node it; |
struct list_head vm_status; |
/* constant after initialization */ |
struct radeon_vm *vm; |
374,15 → 501,14 |
/* Protected by gem.mutex */ |
struct list_head list; |
/* Protected by tbo.reserved */ |
u32 initial_domain; |
u32 placements[3]; |
u32 domain; |
struct ttm_placement placement; |
struct ttm_buffer_object tbo; |
struct ttm_bo_kmap_obj kmap; |
u32 flags; |
unsigned pin_count; |
void *kptr; |
void *uptr; |
u32 cpu_addr; |
u32 tiling_flags; |
u32 pitch; |
int surface_reg; |
394,18 → 520,10 |
struct radeon_device *rdev; |
struct drm_gem_object gem_base; |
struct ttm_bo_kmap_obj dma_buf_vmap; |
pid_t pid; |
}; |
#define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) |
struct radeon_bo_list { |
struct radeon_bo *bo; |
uint64_t gpu_offset; |
unsigned rdomain; |
unsigned wdomain; |
u32 tiling_flags; |
}; |
int radeon_gem_debugfs_init(struct radeon_device *rdev); |
/* sub-allocation manager, it has to be protected by another lock. |
441,6 → 559,7 |
uint64_t gpu_addr; |
void *cpu_ptr; |
uint32_t domain; |
uint32_t align; |
}; |
struct radeon_sa_bo; |
465,9 → 584,9 |
int radeon_gem_init(struct radeon_device *rdev); |
void radeon_gem_fini(struct radeon_device *rdev); |
int radeon_gem_object_create(struct radeon_device *rdev, int size, |
int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size, |
int alignment, int initial_domain, |
bool discardable, bool kernel, |
u32 flags, bool kernel, |
struct drm_gem_object **obj); |
int radeon_mode_dumb_create(struct drm_file *file_priv, |
476,29 → 595,28 |
int radeon_mode_dumb_mmap(struct drm_file *filp, |
struct drm_device *dev, |
uint32_t handle, uint64_t *offset_p); |
int radeon_mode_dumb_destroy(struct drm_file *file_priv, |
struct drm_device *dev, |
uint32_t handle); |
/* |
* 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); |
513,6 → 631,12 |
#define RADEON_GPU_PAGE_SHIFT 12 |
#define RADEON_GPU_PAGE_ALIGN(a) (((a) + RADEON_GPU_PAGE_MASK) & ~RADEON_GPU_PAGE_MASK) |
#define RADEON_GART_PAGE_DUMMY 0 |
#define RADEON_GART_PAGE_VALID (1 << 0) |
#define RADEON_GART_PAGE_READ (1 << 1) |
#define RADEON_GART_PAGE_WRITE (1 << 2) |
#define RADEON_GART_PAGE_SNOOP (1 << 3) |
struct radeon_gart { |
dma_addr_t table_addr; |
struct radeon_bo *robj; |
536,9 → 660,8 |
void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, |
int pages); |
int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, |
int pages, u32 *pagelist, |
dma_addr_t *dma_addr); |
void radeon_gart_restore(struct radeon_device *rdev); |
int pages, struct page **pagelist, |
dma_addr_t *dma_addr, uint32_t flags); |
/* |
582,7 → 705,23 |
int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg); |
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 { |
/* doorbell mmio */ |
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); |
void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell); |
/* |
* IRQS. |
*/ |
622,16 → 761,29 |
u32 afmt_status6; |
}; |
struct cik_irq_stat_regs { |
u32 disp_int; |
u32 disp_int_cont; |
u32 disp_int_cont2; |
u32 disp_int_cont3; |
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 { |
struct r500_irq_stat_regs r500; |
struct r600_irq_stat_regs r600; |
struct evergreen_irq_stat_regs evergreen; |
struct cik_irq_stat_regs cik; |
}; |
#define RADEON_MAX_HPD_PINS 6 |
#define RADEON_MAX_CRTCS 6 |
#define RADEON_MAX_AFMT_BLOCKS 6 |
struct radeon_irq { |
bool installed; |
spinlock_t lock; |
642,6 → 794,7 |
bool hpd[RADEON_MAX_HPD_PINS]; |
bool afmt[RADEON_MAX_AFMT_BLOCKS]; |
union radeon_irq_stat_regs stat_regs; |
bool dpm_thermal; |
}; |
int radeon_irq_kms_init(struct radeon_device *rdev); |
668,7 → 821,6 |
struct radeon_fence *fence; |
struct radeon_vm *vm; |
bool is_const_ib; |
struct radeon_fence *sync_to[RADEON_NUM_RINGS]; |
struct radeon_semaphore *semaphore; |
}; |
675,32 → 827,42 |
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; |
bool ready; |
u32 ptr_reg_shift; |
u32 ptr_reg_mask; |
u32 nop; |
u32 idx; |
u64 last_semaphore_signal_addr; |
u64 last_semaphore_wait_addr; |
/* for CIK queues */ |
u32 me; |
u32 pipe; |
u32 queue; |
struct radeon_bo *mqd_obj; |
u32 doorbell_index; |
unsigned wptr_offs; |
}; |
struct radeon_mec { |
struct radeon_bo *hpd_eop_obj; |
u64 hpd_eop_gpu_addr; |
u32 num_pipe; |
u32 num_mec; |
u32 num_queue; |
}; |
/* |
* VM |
*/ |
708,38 → 870,65 |
/* 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 needed to be set so we can copy directly from the GART table */ |
#define R600_PTE_GART_MASK ( R600_PTE_READABLE | R600_PTE_WRITEABLE | \ |
R600_PTE_SYSTEM | R600_PTE_VALID ) |
struct radeon_vm_pt { |
struct radeon_bo *bo; |
uint64_t addr; |
}; |
struct radeon_vm { |
struct list_head list; |
struct list_head va; |
struct rb_root va; |
unsigned id; |
/* BOs moved, but not yet updated in the PT */ |
struct list_head invalidated; |
/* 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; |
747,6 → 936,8 |
u64 vram_base_offset; |
/* is vm enabled? */ |
bool enabled; |
/* for hw to save the PD addr on suspend/resume */ |
uint32_t saved_table_addr[RADEON_NUM_VM]; |
}; |
/* |
770,45 → 961,29 |
bool enabled; |
}; |
struct r600_blit_cp_primitives { |
void (*set_render_target)(struct radeon_device *rdev, int format, |
int w, int h, u64 gpu_addr); |
void (*cp_set_surface_sync)(struct radeon_device *rdev, |
u32 sync_type, u32 size, |
u64 mc_addr); |
void (*set_shaders)(struct radeon_device *rdev); |
void (*set_vtx_resource)(struct radeon_device *rdev, u64 gpu_addr); |
void (*set_tex_resource)(struct radeon_device *rdev, |
int format, int w, int h, int pitch, |
u64 gpu_addr, u32 size); |
void (*set_scissors)(struct radeon_device *rdev, int x1, int y1, |
int x2, int y2); |
void (*draw_auto)(struct radeon_device *rdev); |
void (*set_default_state)(struct radeon_device *rdev); |
}; |
struct r600_blit { |
struct radeon_bo *shader_obj; |
struct r600_blit_cp_primitives primitives; |
int max_dim; |
int ring_size_common; |
int ring_size_per_loop; |
u64 shader_gpu_addr; |
u32 vs_offset, ps_offset; |
u32 state_offset; |
u32 state_len; |
}; |
/* |
* SI RLC stuff |
* RLC stuff |
*/ |
struct si_rlc { |
#include "clearstate_defs.h" |
struct radeon_rlc { |
/* for power gating */ |
struct radeon_bo *save_restore_obj; |
uint64_t save_restore_gpu_addr; |
volatile uint32_t *sr_ptr; |
const u32 *reg_list; |
u32 reg_list_size; |
/* for clear state */ |
struct radeon_bo *clear_state_obj; |
uint64_t clear_state_gpu_addr; |
volatile uint32_t *cs_ptr; |
const struct cs_section_def *cs_data; |
u32 clear_state_size; |
/* for cp tables */ |
struct radeon_bo *cp_table_obj; |
uint64_t cp_table_gpu_addr; |
volatile uint32_t *cp_table_ptr; |
u32 cp_table_size; |
}; |
int radeon_ib_get(struct radeon_device *rdev, int ring, |
815,9 → 990,8 |
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); |
struct radeon_ib *const_ib, bool hdp_flush); |
int radeon_ib_pool_init(struct radeon_device *rdev); |
void radeon_ib_pool_fini(struct radeon_device *rdev); |
int radeon_ib_ring_tests(struct radeon_device *rdev); |
827,13 → 1001,15 |
void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp); |
int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw); |
int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw); |
void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp); |
void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp); |
void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp, |
bool hdp_flush); |
void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp, |
bool hdp_flush); |
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); |
840,8 → 1016,7 |
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 ptr_reg_shift, u32 ptr_reg_mask, u32 nop); |
unsigned rptr_offs, u32 nop); |
void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *cp); |
858,22 → 1033,21 |
* CS. |
*/ |
struct radeon_cs_reloc { |
// struct drm_gem_object *gobj; |
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 { |
890,6 → 1064,7 |
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 */ |
905,11 → 1080,19 |
u32 cs_flags; |
u32 ring; |
s32 priority; |
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; |
unsigned type; |
954,8 → 1137,9 |
#define R600_WB_DMA_RPTR_OFFSET 1792 |
#define R600_WB_IH_WPTR_OFFSET 2048 |
#define CAYMAN_WB_DMA1_RPTR_OFFSET 2304 |
#define R600_WB_UVD_RPTR_OFFSET 2560 |
#define R600_WB_EVENT_OFFSET 3072 |
#define CIK_WB_CP1_WPTR_OFFSET 3328 |
#define CIK_WB_CP2_WPTR_OFFSET 3584 |
/** |
* struct radeon_pm - power management datas |
980,6 → 1164,7 |
enum radeon_pm_method { |
PM_METHOD_PROFILE, |
PM_METHOD_DYNPM, |
PM_METHOD_DPM, |
}; |
enum radeon_dynpm_state { |
1005,11 → 1190,24 |
}; |
enum radeon_pm_state_type { |
/* not used for dpm */ |
POWER_STATE_TYPE_DEFAULT, |
POWER_STATE_TYPE_POWERSAVE, |
/* user selectable states */ |
POWER_STATE_TYPE_BATTERY, |
POWER_STATE_TYPE_BALANCED, |
POWER_STATE_TYPE_PERFORMANCE, |
/* internal states */ |
POWER_STATE_TYPE_INTERNAL_UVD, |
POWER_STATE_TYPE_INTERNAL_UVD_SD, |
POWER_STATE_TYPE_INTERNAL_UVD_HD, |
POWER_STATE_TYPE_INTERNAL_UVD_HD2, |
POWER_STATE_TYPE_INTERNAL_UVD_MVC, |
POWER_STATE_TYPE_INTERNAL_BOOT, |
POWER_STATE_TYPE_INTERNAL_THERMAL, |
POWER_STATE_TYPE_INTERNAL_ACPI, |
POWER_STATE_TYPE_INTERNAL_ULV, |
POWER_STATE_TYPE_INTERNAL_3DPERF, |
}; |
enum radeon_pm_profile_type { |
1038,12 → 1236,18 |
enum radeon_int_thermal_type { |
THERMAL_TYPE_NONE, |
THERMAL_TYPE_EXTERNAL, |
THERMAL_TYPE_EXTERNAL_GPIO, |
THERMAL_TYPE_RV6XX, |
THERMAL_TYPE_RV770, |
THERMAL_TYPE_ADT7473_WITH_INTERNAL, |
THERMAL_TYPE_EVERGREEN, |
THERMAL_TYPE_SUMO, |
THERMAL_TYPE_NI, |
THERMAL_TYPE_SI, |
THERMAL_TYPE_EMC2103_WITH_INTERNAL, |
THERMAL_TYPE_CI, |
THERMAL_TYPE_KV, |
}; |
struct radeon_voltage { |
1097,6 → 1301,280 |
*/ |
#define RADEON_MODE_OVERCLOCK_MARGIN 500 /* 5 MHz */ |
enum radeon_dpm_auto_throttle_src { |
RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, |
RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL |
}; |
enum radeon_dpm_event_src { |
RADEON_DPM_EVENT_SRC_ANALOG = 0, |
RADEON_DPM_EVENT_SRC_EXTERNAL = 1, |
RADEON_DPM_EVENT_SRC_DIGITAL = 2, |
RADEON_DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3, |
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 */ |
u32 class2; /* vbios flags */ |
/* UVD clocks */ |
u32 vclk; |
u32 dclk; |
/* VCE clocks */ |
u32 evclk; |
u32 ecclk; |
bool vce_active; |
enum radeon_vce_level vce_level; |
/* asic priv */ |
void *ps_priv; |
}; |
struct radeon_dpm_thermal { |
/* thermal interrupt work */ |
struct work_struct work; |
/* low temperature threshold */ |
int min_temp; |
/* high temperature threshold */ |
int max_temp; |
/* was interrupt low to high or high to low */ |
bool high_to_low; |
}; |
enum radeon_clk_action |
{ |
RADEON_SCLK_UP = 1, |
RADEON_SCLK_DOWN |
}; |
struct radeon_blacklist_clocks |
{ |
u32 sclk; |
u32 mclk; |
enum radeon_clk_action action; |
}; |
struct radeon_clock_and_voltage_limits { |
u32 sclk; |
u32 mclk; |
u16 vddc; |
u16 vddci; |
}; |
struct radeon_clock_array { |
u32 count; |
u32 *values; |
}; |
struct radeon_clock_voltage_dependency_entry { |
u32 clk; |
u16 v; |
}; |
struct radeon_clock_voltage_dependency_table { |
u32 count; |
struct radeon_clock_voltage_dependency_entry *entries; |
}; |
union radeon_cac_leakage_entry { |
struct { |
u16 vddc; |
u32 leakage; |
}; |
struct { |
u16 vddc1; |
u16 vddc2; |
u16 vddc3; |
}; |
}; |
struct radeon_cac_leakage_table { |
u32 count; |
union radeon_cac_leakage_entry *entries; |
}; |
struct radeon_phase_shedding_limits_entry { |
u16 voltage; |
u32 sclk; |
u32 mclk; |
}; |
struct radeon_phase_shedding_limits_table { |
u32 count; |
struct radeon_phase_shedding_limits_entry *entries; |
}; |
struct radeon_uvd_clock_voltage_dependency_entry { |
u32 vclk; |
u32 dclk; |
u16 v; |
}; |
struct radeon_uvd_clock_voltage_dependency_table { |
u8 count; |
struct radeon_uvd_clock_voltage_dependency_entry *entries; |
}; |
struct radeon_vce_clock_voltage_dependency_entry { |
u32 ecclk; |
u32 evclk; |
u16 v; |
}; |
struct radeon_vce_clock_voltage_dependency_table { |
u8 count; |
struct radeon_vce_clock_voltage_dependency_entry *entries; |
}; |
struct radeon_ppm_table { |
u8 ppm_design; |
u16 cpu_core_number; |
u32 platform_tdp; |
u32 small_ac_platform_tdp; |
u32 platform_tdc; |
u32 small_ac_platform_tdc; |
u32 apu_tdp; |
u32 dgpu_tdp; |
u32 dgpu_ulv_power; |
u32 tj_max; |
}; |
struct radeon_cac_tdp_table { |
u16 tdp; |
u16 configurable_tdp; |
u16 tdc; |
u16 battery_power_limit; |
u16 small_power_limit; |
u16 low_cac_leakage; |
u16 high_cac_leakage; |
u16 maximum_power_delivery_limit; |
}; |
struct radeon_dpm_dynamic_state { |
struct radeon_clock_voltage_dependency_table vddc_dependency_on_sclk; |
struct radeon_clock_voltage_dependency_table vddci_dependency_on_mclk; |
struct radeon_clock_voltage_dependency_table vddc_dependency_on_mclk; |
struct radeon_clock_voltage_dependency_table mvdd_dependency_on_mclk; |
struct radeon_clock_voltage_dependency_table vddc_dependency_on_dispclk; |
struct radeon_uvd_clock_voltage_dependency_table uvd_clock_voltage_dependency_table; |
struct radeon_vce_clock_voltage_dependency_table vce_clock_voltage_dependency_table; |
struct radeon_clock_voltage_dependency_table samu_clock_voltage_dependency_table; |
struct radeon_clock_voltage_dependency_table acp_clock_voltage_dependency_table; |
struct radeon_clock_array valid_sclk_values; |
struct radeon_clock_array valid_mclk_values; |
struct radeon_clock_and_voltage_limits max_clock_voltage_on_dc; |
struct radeon_clock_and_voltage_limits max_clock_voltage_on_ac; |
u32 mclk_sclk_ratio; |
u32 sclk_mclk_delta; |
u16 vddc_vddci_delta; |
u16 min_vddc_for_pcie_gen2; |
struct radeon_cac_leakage_table cac_leakage_table; |
struct radeon_phase_shedding_limits_table phase_shedding_limits_table; |
struct radeon_ppm_table *ppm_table; |
struct radeon_cac_tdp_table *cac_tdp_table; |
}; |
struct radeon_dpm_fan { |
u16 t_min; |
u16 t_med; |
u16 t_high; |
u16 pwm_min; |
u16 pwm_med; |
u16 pwm_high; |
u8 t_hyst; |
u32 cycle_delay; |
u16 t_max; |
bool ucode_fan_control; |
}; |
enum radeon_pcie_gen { |
RADEON_PCIE_GEN1 = 0, |
RADEON_PCIE_GEN2 = 1, |
RADEON_PCIE_GEN3 = 2, |
RADEON_PCIE_GEN_INVALID = 0xffff |
}; |
enum radeon_dpm_forced_level { |
RADEON_DPM_FORCED_LEVEL_AUTO = 0, |
RADEON_DPM_FORCED_LEVEL_LOW = 1, |
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 */ |
int num_ps; |
/* current power state that is active */ |
struct radeon_ps *current_ps; |
/* requested power state */ |
struct radeon_ps *requested_ps; |
/* boot up power state */ |
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; |
u32 voltage_response_time; |
u32 backbias_response_time; |
void *priv; |
u32 new_active_crtcs; |
int new_active_crtc_count; |
u32 current_active_crtcs; |
int current_active_crtc_count; |
struct radeon_dpm_dynamic_state dyn_state; |
struct radeon_dpm_fan fan; |
u32 tdp_limit; |
u32 near_tdp_limit; |
u32 near_tdp_limit_adjusted; |
u32 sq_ramping_threshold; |
u32 cac_leakage; |
u16 tdp_od_limit; |
u32 tdp_adjustment; |
u16 load_line_slope; |
bool power_control; |
bool ac_power; |
/* special states active */ |
bool thermal_active; |
bool uvd_active; |
bool vce_active; |
/* thermal handling */ |
struct radeon_dpm_thermal thermal; |
/* forced levels */ |
enum radeon_dpm_forced_level forced_level; |
/* track UVD streams */ |
unsigned sd; |
unsigned hd; |
}; |
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; |
/* write locked while reprogramming mclk */ |
1137,7 → 1615,7 |
/* selected pm method */ |
enum radeon_pm_method pm_method; |
/* dynpm power management */ |
// struct delayed_work dynpm_idle_work; |
struct delayed_work dynpm_idle_work; |
enum radeon_dynpm_state dynpm_state; |
enum radeon_dynpm_action dynpm_planned_action; |
unsigned long dynpm_action_timeout; |
1150,6 → 1628,9 |
/* internal thermal controller on rv6xx+ */ |
enum radeon_int_thermal_type int_thermal_type; |
struct device *int_hwmon_dev; |
/* dpm */ |
bool dpm_enabled; |
struct radeon_dpm dpm; |
}; |
int radeon_pm_get_type_index(struct radeon_device *rdev, |
1166,8 → 1647,10 |
struct radeon_bo *vcpu_bo; |
void *cpu_addr; |
uint64_t gpu_addr; |
void *saved_bo; |
atomic_t handles[RADEON_MAX_UVD_HANDLES]; |
struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; |
unsigned img_size[RADEON_MAX_UVD_HANDLES]; |
struct delayed_work idle_work; |
}; |
1196,14 → 1679,123 |
int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, |
unsigned cg_upll_func_cntl); |
struct r600_audio { |
/* |
* 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; |
int bits_per_sample; |
u8 status_bits; |
u8 category_code; |
u32 offset; |
bool connected; |
u32 id; |
}; |
struct r600_audio { |
bool enabled; |
struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS]; |
int num_pins; |
}; |
/* |
* Benchmarking |
*/ |
void radeon_benchmark(struct radeon_device *rdev, int test_number); |
/* |
* Testing |
*/ |
void radeon_test_moves(struct radeon_device *rdev); |
void radeon_test_ring_sync(struct radeon_device *rdev, |
struct radeon_ring *cpA, |
struct radeon_ring *cpB); |
void radeon_test_syncing(struct radeon_device *rdev); |
/* |
* Debugfs |
*/ |
struct radeon_debugfs { |
struct drm_info_list *files; |
unsigned num_files; |
}; |
int radeon_debugfs_add_files(struct radeon_device *rdev, |
struct drm_info_list *files, |
unsigned nfiles); |
int radeon_debugfs_fence_init(struct radeon_device *rdev); |
/* |
* ASIC ring specific functions. |
*/ |
struct radeon_asic_ring { |
/* ring read/write ptr handling */ |
u32 (*get_rptr)(struct radeon_device *rdev, struct radeon_ring *ring); |
u32 (*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring); |
void (*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring); |
/* validating and patching of IBs */ |
int (*ib_parse)(struct radeon_device *rdev, struct radeon_ib *ib); |
int (*cs_parse)(struct radeon_cs_parser *p); |
/* 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 (*hdp_flush)(struct radeon_device *rdev, struct radeon_ring *ring); |
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); |
/* testing functions */ |
int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp); |
int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp); |
bool (*is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp); |
/* deprecated */ |
void (*ring_start)(struct radeon_device *rdev, struct radeon_ring *cp); |
}; |
/* |
* ASIC specific functions. |
*/ |
struct radeon_asic { |
1213,13 → 1805,8 |
int (*suspend)(struct radeon_device *rdev); |
void (*vga_set_state)(struct radeon_device *rdev, bool state); |
int (*asic_reset)(struct radeon_device *rdev); |
/* ioctl hw specific callback. Some hw might want to perform special |
* operation on specific ioctl. For instance on wait idle some hw |
* might want to perform and HDP flush through MMIO as it seems that |
* some R6XX/R7XX hw doesn't take HDP flush into account if programmed |
* through ring. |
*/ |
void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); |
/* Flush the HDP cache via MMIO */ |
void (*mmio_hdp_flush)(struct radeon_device *rdev); |
/* check if 3D engine is idle */ |
bool (*gui_idle)(struct radeon_device *rdev); |
/* wait for mc_idle */ |
1231,33 → 1818,30 |
/* 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, uint32_t flags); |
} 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, |
void (*copy_pages)(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, uint64_t src, |
unsigned count); |
void (*write_pages)(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags); |
void (*set_pages)(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags); |
void (*pad_ib)(struct radeon_ib *ib); |
} vm; |
/* ring specific callbacks */ |
struct { |
void (*ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib); |
int (*ib_parse)(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, |
struct radeon_semaphore *semaphore, bool emit_wait); |
int (*cs_parse)(struct radeon_cs_parser *p); |
void (*ring_start)(struct radeon_device *rdev, struct radeon_ring *cp); |
int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp); |
int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp); |
bool (*is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp); |
void (*vm_flush)(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); |
} ring[RADEON_NUM_RINGS]; |
struct radeon_asic_ring *ring[RADEON_NUM_RINGS]; |
/* irqs */ |
struct { |
int (*set)(struct radeon_device *rdev); |
1316,7 → 1900,7 |
bool (*sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd); |
void (*set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd); |
} hpd; |
/* power management */ |
/* static power management */ |
struct { |
void (*misc)(struct radeon_device *rdev); |
void (*prepare)(struct radeon_device *rdev); |
1331,12 → 1915,34 |
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 */ |
struct { |
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); |
void (*post_set_power_state)(struct radeon_device *rdev); |
void (*display_configuration_changed)(struct radeon_device *rdev); |
void (*fini)(struct radeon_device *rdev); |
u32 (*get_sclk)(struct radeon_device *rdev, bool low); |
u32 (*get_mclk)(struct radeon_device *rdev, bool low); |
void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps); |
void (*debugfs_print_current_performance_level)(struct radeon_device *rdev, struct seq_file *m); |
int (*force_performance_level)(struct radeon_device *rdev, enum radeon_dpm_forced_level level); |
bool (*vblank_too_short)(struct radeon_device *rdev); |
void (*powergate_uvd)(struct radeon_device *rdev, bool gate); |
void (*enable_bapm)(struct radeon_device *rdev, bool enable); |
} 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; |
}; |
1375,6 → 1981,7 |
unsigned tiling_group_size; |
unsigned tile_config; |
unsigned backend_map; |
unsigned active_simds; |
}; |
struct rv770_asic { |
1400,6 → 2007,7 |
unsigned tiling_group_size; |
unsigned tile_config; |
unsigned backend_map; |
unsigned active_simds; |
}; |
struct evergreen_asic { |
1426,6 → 2034,7 |
unsigned tiling_group_size; |
unsigned tile_config; |
unsigned backend_map; |
unsigned active_simds; |
}; |
struct cayman_asic { |
1464,6 → 2073,7 |
unsigned multi_gpu_tile_size; |
unsigned tile_config; |
unsigned active_simds; |
}; |
struct si_asic { |
1482,7 → 2092,7 |
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; |
1494,8 → 2104,41 |
unsigned tile_config; |
uint32_t tile_mode_array[32]; |
uint32_t active_cus; |
}; |
struct cik_asic { |
unsigned max_shader_engines; |
unsigned max_tile_pipes; |
unsigned max_cu_per_sh; |
unsigned max_sh_per_se; |
unsigned max_backends_per_se; |
unsigned max_texture_channel_caches; |
unsigned max_gprs; |
unsigned max_gs_threads; |
unsigned max_hw_contexts; |
unsigned sc_prim_fifo_size_frontend; |
unsigned sc_prim_fifo_size_backend; |
unsigned sc_hiz_tile_fifo_size; |
unsigned sc_earlyz_tile_fifo_size; |
unsigned num_tile_pipes; |
unsigned backend_enable_mask; |
unsigned backend_disable_mask_per_asic; |
unsigned backend_map; |
unsigned num_texture_channel_caches; |
unsigned mem_max_burst_length_bytes; |
unsigned mem_row_size_in_kb; |
unsigned shader_engine_tile_size; |
unsigned num_gpus; |
unsigned multi_gpu_tile_size; |
unsigned tile_config; |
uint32_t tile_mode_array[32]; |
uint32_t macrotile_mode_array[16]; |
uint32_t active_cus; |
}; |
union radeon_asic_config { |
struct r300_asic r300; |
struct r100_asic r100; |
1504,6 → 2147,7 |
struct evergreen_asic evergreen; |
struct cayman_asic cayman; |
struct si_asic si; |
struct cik_asic cik; |
}; |
/* |
1521,7 → 2165,57 |
u64 gpu_addr; |
}; |
/* |
* ACPI |
*/ |
struct radeon_atif_notification_cfg { |
bool enabled; |
int command_code; |
}; |
struct radeon_atif_notifications { |
bool display_switch; |
bool expansion_mode_change; |
bool thermal_state; |
bool forced_power_state; |
bool system_power_state; |
bool display_conf_change; |
bool px_gfx_switch; |
bool brightness_change; |
bool dgpu_display_event; |
}; |
struct radeon_atif_functions { |
bool system_params; |
bool sbios_requests; |
bool select_active_disp; |
bool lid_state; |
bool get_tv_standard; |
bool set_tv_standard; |
bool get_panel_expansion_mode; |
bool set_panel_expansion_mode; |
bool temperature_change; |
bool graphics_device_types; |
}; |
struct radeon_atif { |
struct radeon_atif_notifications notifications; |
struct radeon_atif_functions functions; |
struct radeon_atif_notification_cfg notification_cfg; |
struct radeon_encoder *encoder_for_bl; |
}; |
struct radeon_atcs_functions { |
bool get_ext_state; |
bool pcie_perf_req; |
bool pcie_dev_rdy; |
bool pcie_bus_width; |
}; |
struct radeon_atcs { |
struct radeon_atcs_functions functions; |
}; |
/* |
* Core structure, functions and helpers. |
*/ |
1552,6 → 2246,28 |
resource_size_t rmmio_size; |
/* protects concurrent MM_INDEX/DATA based register access */ |
spinlock_t mmio_idx_lock; |
/* protects concurrent SMC based register access */ |
spinlock_t smc_idx_lock; |
/* protects concurrent PLL register access */ |
spinlock_t pll_idx_lock; |
/* protects concurrent MC register access */ |
spinlock_t mc_idx_lock; |
/* protects concurrent PCIE register access */ |
spinlock_t pcie_idx_lock; |
/* protects concurrent PCIE_PORT register access */ |
spinlock_t pciep_idx_lock; |
/* protects concurrent PIF register access */ |
spinlock_t pif_idx_lock; |
/* protects concurrent CG register access */ |
spinlock_t cg_idx_lock; |
/* protects concurrent UVD register access */ |
spinlock_t uvd_idx_lock; |
/* protects concurrent RCU register access */ |
spinlock_t rcu_idx_lock; |
/* protects concurrent DIDT register access */ |
spinlock_t didt_idx_lock; |
/* protects concurrent ENDPOINT (audio) register access */ |
spinlock_t end_idx_lock; |
void __iomem *rmmio; |
radeon_rreg_t mc_rreg; |
radeon_wreg_t mc_wreg; |
1568,6 → 2284,7 |
struct radeon_gart gart; |
struct radeon_mode_info mode_info; |
struct radeon_scratch scratch; |
struct radeon_doorbell doorbell; |
struct radeon_mman mman; |
struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS]; |
wait_queue_head_t fence_queue; |
1580,6 → 2297,7 |
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; |
1588,6 → 2306,7 |
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 */ |
1594,36 → 2313,59 |
const struct firmware *rlc_fw; /* r6/700 RLC firmware */ |
const struct firmware *mc_fw; /* NI MC firmware */ |
const struct firmware *ce_fw; /* SI CE firmware */ |
const struct firmware *mec_fw; /* CIK MEC firmware */ |
const struct firmware *mec2_fw; /* KV MEC2 firmware */ |
const struct firmware *sdma_fw; /* CIK SDMA firmware */ |
const struct firmware *smc_fw; /* SMC firmware */ |
const struct firmware *uvd_fw; /* UVD firmware */ |
struct r600_blit r600_blit; |
const struct firmware *vce_fw; /* VCE firmware */ |
bool new_fw; |
struct r600_vram_scratch vram_scratch; |
int msi_enabled; /* msi enabled */ |
struct r600_ih ih; /* r6/700 interrupt ring */ |
struct si_rlc rlc; |
// struct work_struct hotplug_work; |
// struct work_struct audio_work; |
struct radeon_rlc rlc; |
struct radeon_mec mec; |
struct work_struct hotplug_work; |
struct work_struct audio_work; |
struct work_struct reset_work; |
int num_crtc; /* number of crtcs */ |
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */ |
bool audio_enabled; |
bool has_uvd; |
// struct r600_audio audio_status; /* audio stuff */ |
// struct notifier_block acpi_nb; |
struct r600_audio audio; /* audio stuff */ |
/* only one userspace can use Hyperz features or CMASK at a time */ |
// struct drm_file *hyperz_filp; |
// struct drm_file *cmask_filp; |
struct drm_file *hyperz_filp; |
struct drm_file *cmask_filp; |
/* i2c buses */ |
struct radeon_i2c_chan *i2c_bus[RADEON_MAX_I2C_BUS]; |
/* debugfs */ |
// struct radeon_debugfs debugfs[RADEON_DEBUGFS_MAX_COMPONENTS]; |
struct radeon_debugfs debugfs[RADEON_DEBUGFS_MAX_COMPONENTS]; |
unsigned debugfs_count; |
/* 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; |
struct radeon_atif atif; |
struct radeon_atcs atcs; |
/* srbm instance registers */ |
struct mutex srbm_mutex; |
/* clock, powergating flags */ |
u32 cg_flags; |
u32 pg_flags; |
// struct dev_pm_domain vga_pm_domain; |
bool have_disp_power_ref; |
u32 px_quirk_flags; |
/* tracking pinned memory */ |
u64 vram_pin_size; |
u64 gart_pin_size; |
}; |
bool radeon_is_px(struct drm_device *dev); |
int radeon_device_init(struct radeon_device *rdev, |
struct drm_device *ddev, |
struct pci_dev *pdev, |
1631,13 → 2373,48 |
void radeon_device_fini(struct radeon_device *rdev); |
int radeon_gpu_wait_for_idle(struct radeon_device *rdev); |
uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, |
bool always_indirect); |
void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, |
bool always_indirect); |
#define RADEON_MIN_MMIO_SIZE 0x10000 |
static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, |
bool always_indirect) |
{ |
/* The mmio size is 64kb at minimum. Allows the if to be optimized out. */ |
if ((reg < rdev->rmmio_size || reg < RADEON_MIN_MMIO_SIZE) && !always_indirect) |
return readl(((void __iomem *)rdev->rmmio) + reg); |
else { |
unsigned long flags; |
uint32_t ret; |
spin_lock_irqsave(&rdev->mmio_idx_lock, flags); |
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); |
ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); |
spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); |
return ret; |
} |
} |
static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, |
bool always_indirect) |
{ |
if ((reg < rdev->rmmio_size || reg < RADEON_MIN_MMIO_SIZE) && !always_indirect) |
writel(v, ((void __iomem *)rdev->rmmio) + reg); |
else { |
unsigned long flags; |
spin_lock_irqsave(&rdev->mmio_idx_lock, flags); |
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); |
writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); |
spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); |
} |
} |
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 index); |
void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v); |
/* |
* Cast helper |
*/ |
1665,6 → 2442,20 |
#define WREG32_PCIE(reg, v) rv370_pcie_wreg(rdev, (reg), (v)) |
#define RREG32_PCIE_PORT(reg) rdev->pciep_rreg(rdev, (reg)) |
#define WREG32_PCIE_PORT(reg, v) rdev->pciep_wreg(rdev, (reg), (v)) |
#define RREG32_SMC(reg) tn_smc_rreg(rdev, (reg)) |
#define WREG32_SMC(reg, v) tn_smc_wreg(rdev, (reg), (v)) |
#define RREG32_RCU(reg) r600_rcu_rreg(rdev, (reg)) |
#define WREG32_RCU(reg, v) r600_rcu_wreg(rdev, (reg), (v)) |
#define RREG32_CG(reg) eg_cg_rreg(rdev, (reg)) |
#define WREG32_CG(reg, v) eg_cg_wreg(rdev, (reg), (v)) |
#define RREG32_PIF_PHY0(reg) eg_pif_phy0_rreg(rdev, (reg)) |
#define WREG32_PIF_PHY0(reg, v) eg_pif_phy0_wreg(rdev, (reg), (v)) |
#define RREG32_PIF_PHY1(reg) eg_pif_phy1_rreg(rdev, (reg)) |
#define WREG32_PIF_PHY1(reg, v) eg_pif_phy1_wreg(rdev, (reg), (v)) |
#define RREG32_UVD_CTX(reg) r600_uvd_ctx_rreg(rdev, (reg)) |
#define WREG32_UVD_CTX(reg, v) r600_uvd_ctx_wreg(rdev, (reg), (v)) |
#define RREG32_DIDT(reg) cik_didt_rreg(rdev, (reg)) |
#define WREG32_DIDT(reg, v) cik_didt_wreg(rdev, (reg), (v)) |
#define WREG32_P(reg, val, mask) \ |
do { \ |
uint32_t tmp_ = RREG32(reg); \ |
1673,7 → 2464,7 |
WREG32(reg, tmp_); \ |
} while (0) |
#define WREG32_AND(reg, and) WREG32_P(reg, 0, and) |
#define WREG32_OR(reg, or) WREG32_P(reg, or, ~or) |
#define WREG32_OR(reg, or) WREG32_P(reg, or, ~(or)) |
#define WREG32_PLL_P(reg, val, mask) \ |
do { \ |
uint32_t tmp_ = RREG32_PLL(reg); \ |
1681,27 → 2472,193 |
tmp_ |= ((val) & ~(mask)); \ |
WREG32_PLL(reg, tmp_); \ |
} while (0) |
#define DREG32_SYS(sqf, rdev, reg) seq_printf((sqf), #reg " : 0x%08X\n", r100_mm_rreg((rdev), (reg), false)) |
#define RREG32_IO(reg) r100_io_rreg(rdev, (reg)) |
#define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v)) |
#define RDOORBELL32(index) cik_mm_rdoorbell(rdev, (index)) |
#define WDOORBELL32(index, v) cik_mm_wdoorbell(rdev, (index), (v)) |
/* |
* Indirect registers accessor |
*/ |
static inline uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg) |
{ |
unsigned long flags; |
uint32_t r; |
spin_lock_irqsave(&rdev->pcie_idx_lock, flags); |
WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask)); |
r = RREG32(RADEON_PCIE_DATA); |
spin_unlock_irqrestore(&rdev->pcie_idx_lock, flags); |
return r; |
} |
static inline void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->pcie_idx_lock, flags); |
WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask)); |
WREG32(RADEON_PCIE_DATA, (v)); |
spin_unlock_irqrestore(&rdev->pcie_idx_lock, flags); |
} |
static inline u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
WREG32(TN_SMC_IND_INDEX_0, (reg)); |
r = RREG32(TN_SMC_IND_DATA_0); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return r; |
} |
static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
WREG32(TN_SMC_IND_INDEX_0, (reg)); |
WREG32(TN_SMC_IND_DATA_0, (v)); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
} |
static inline u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->rcu_idx_lock, flags); |
WREG32(R600_RCU_INDEX, ((reg) & 0x1fff)); |
r = RREG32(R600_RCU_DATA); |
spin_unlock_irqrestore(&rdev->rcu_idx_lock, flags); |
return r; |
} |
static inline void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->rcu_idx_lock, flags); |
WREG32(R600_RCU_INDEX, ((reg) & 0x1fff)); |
WREG32(R600_RCU_DATA, (v)); |
spin_unlock_irqrestore(&rdev->rcu_idx_lock, flags); |
} |
static inline u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->cg_idx_lock, flags); |
WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff)); |
r = RREG32(EVERGREEN_CG_IND_DATA); |
spin_unlock_irqrestore(&rdev->cg_idx_lock, flags); |
return r; |
} |
static inline void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->cg_idx_lock, flags); |
WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff)); |
WREG32(EVERGREEN_CG_IND_DATA, (v)); |
spin_unlock_irqrestore(&rdev->cg_idx_lock, flags); |
} |
static inline u32 eg_pif_phy0_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->pif_idx_lock, flags); |
WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff)); |
r = RREG32(EVERGREEN_PIF_PHY0_DATA); |
spin_unlock_irqrestore(&rdev->pif_idx_lock, flags); |
return r; |
} |
static inline void eg_pif_phy0_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->pif_idx_lock, flags); |
WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff)); |
WREG32(EVERGREEN_PIF_PHY0_DATA, (v)); |
spin_unlock_irqrestore(&rdev->pif_idx_lock, flags); |
} |
static inline u32 eg_pif_phy1_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->pif_idx_lock, flags); |
WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff)); |
r = RREG32(EVERGREEN_PIF_PHY1_DATA); |
spin_unlock_irqrestore(&rdev->pif_idx_lock, flags); |
return r; |
} |
static inline void eg_pif_phy1_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->pif_idx_lock, flags); |
WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff)); |
WREG32(EVERGREEN_PIF_PHY1_DATA, (v)); |
spin_unlock_irqrestore(&rdev->pif_idx_lock, flags); |
} |
static inline u32 r600_uvd_ctx_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->uvd_idx_lock, flags); |
WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff)); |
r = RREG32(R600_UVD_CTX_DATA); |
spin_unlock_irqrestore(&rdev->uvd_idx_lock, flags); |
return r; |
} |
static inline void r600_uvd_ctx_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->uvd_idx_lock, flags); |
WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff)); |
WREG32(R600_UVD_CTX_DATA, (v)); |
spin_unlock_irqrestore(&rdev->uvd_idx_lock, flags); |
} |
static inline u32 cik_didt_rreg(struct radeon_device *rdev, u32 reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->didt_idx_lock, flags); |
WREG32(CIK_DIDT_IND_INDEX, (reg)); |
r = RREG32(CIK_DIDT_IND_DATA); |
spin_unlock_irqrestore(&rdev->didt_idx_lock, flags); |
return r; |
} |
static inline void cik_didt_wreg(struct radeon_device *rdev, u32 reg, u32 v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->didt_idx_lock, flags); |
WREG32(CIK_DIDT_IND_INDEX, (reg)); |
WREG32(CIK_DIDT_IND_DATA, (v)); |
spin_unlock_irqrestore(&rdev->didt_idx_lock, flags); |
} |
void r100_pll_errata_after_index(struct radeon_device *rdev); |
1750,7 → 2707,21 |
(rdev->flags & RADEON_IS_IGP)) |
#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) || \ |
(rdev->ddev->pdev->device == 0x6858) || \ |
(rdev->ddev->pdev->device == 0x6859) || \ |
(rdev->ddev->pdev->device == 0x6840) || \ |
(rdev->ddev->pdev->device == 0x6841) || \ |
(rdev->ddev->pdev->device == 0x6842) || \ |
(rdev->ddev->pdev->device == 0x6843)) |
/* |
* BIOS helpers. |
*/ |
1787,21 → 2758,27 |
#define radeon_fini(rdev) (rdev)->asic->fini((rdev)) |
#define radeon_resume(rdev) (rdev)->asic->resume((rdev)) |
#define radeon_suspend(rdev) (rdev)->asic->suspend((rdev)) |
#define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)].cs_parse((p)) |
#define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)]->cs_parse((p)) |
#define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) |
#define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev)) |
#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev)) |
#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p)) |
#define radeon_gart_set_page(rdev, i, p, f) (rdev)->asic->gart.set_page((rdev), (i), (p), (f)) |
#define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) |
#define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) |
#define radeon_asic_vm_set_page(rdev, ib, pe, addr, count, incr, flags) ((rdev)->asic->vm.set_page((rdev), (ib), (pe), (addr), (count), (incr), (flags))) |
#define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)].ring_start((rdev), (cp)) |
#define radeon_ring_test(rdev, r, cp) (rdev)->asic->ring[(r)].ring_test((rdev), (cp)) |
#define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp)) |
#define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)].ib_execute((rdev), (ib)) |
#define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib)) |
#define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)].is_lockup((rdev), (cp)) |
#define radeon_ring_vm_flush(rdev, r, vm) (rdev)->asic->ring[(r)].vm_flush((rdev), (r), (vm)) |
#define radeon_asic_vm_copy_pages(rdev, ib, pe, src, count) ((rdev)->asic->vm.copy_pages((rdev), (ib), (pe), (src), (count))) |
#define radeon_asic_vm_write_pages(rdev, ib, pe, addr, count, incr, flags) ((rdev)->asic->vm.write_pages((rdev), (ib), (pe), (addr), (count), (incr), (flags))) |
#define radeon_asic_vm_set_pages(rdev, ib, pe, addr, count, incr, flags) ((rdev)->asic->vm.set_pages((rdev), (ib), (pe), (addr), (count), (incr), (flags))) |
#define radeon_asic_vm_pad_ib(rdev, ib) ((rdev)->asic->vm.pad_ib((ib))) |
#define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)]->ring_start((rdev), (cp)) |
#define radeon_ring_test(rdev, r, cp) (rdev)->asic->ring[(r)]->ring_test((rdev), (cp)) |
#define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)]->ib_test((rdev), (cp)) |
#define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)]->ib_execute((rdev), (ib)) |
#define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)]->ib_parse((rdev), (ib)) |
#define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)]->is_lockup((rdev), (cp)) |
#define radeon_ring_vm_flush(rdev, r, vm) (rdev)->asic->ring[(r)]->vm_flush((rdev), (r), (vm)) |
#define radeon_ring_get_rptr(rdev, r) (rdev)->asic->ring[(r)->idx]->get_rptr((rdev), (r)) |
#define radeon_ring_get_wptr(rdev, r) (rdev)->asic->ring[(r)->idx]->get_wptr((rdev), (r)) |
#define radeon_ring_set_wptr(rdev, r) (rdev)->asic->ring[(r)->idx]->set_wptr((rdev), (r)) |
#define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev)) |
#define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev)) |
#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) |
1809,8 → 2786,8 |
#define radeon_get_backlight_level(rdev, e) (rdev)->asic->display.get_backlight_level((e)) |
#define radeon_hdmi_enable(rdev, e, b) (rdev)->asic->display.hdmi_enable((e), (b)) |
#define radeon_hdmi_setmode(rdev, e, m) (rdev)->asic->display.hdmi_setmode((e), (m)) |
#define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)].emit_fence((rdev), (fence)) |
#define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)].emit_semaphore((rdev), (cp), (semaphore), (emit_wait)) |
#define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)]->emit_fence((rdev), (fence)) |
#define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)]->emit_semaphore((rdev), (cp), (semaphore), (emit_wait)) |
#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f)) |
#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (f)) |
#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (f)) |
1825,6 → 2802,8 |
#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))) |
#define radeon_bandwidth_update(rdev) (rdev)->asic->display.bandwidth_update((rdev)) |
1838,17 → 2817,35 |
#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)) |
#define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev)) |
#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)) |
#define radeon_dpm_post_set_power_state(rdev) rdev->asic->dpm.post_set_power_state((rdev)) |
#define radeon_dpm_display_configuration_changed(rdev) rdev->asic->dpm.display_configuration_changed((rdev)) |
#define radeon_dpm_fini(rdev) rdev->asic->dpm.fini((rdev)) |
#define radeon_dpm_get_sclk(rdev, l) rdev->asic->dpm.get_sclk((rdev), (l)) |
#define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l)) |
#define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps)) |
#define radeon_dpm_debugfs_print_current_performance_level(rdev, m) rdev->asic->dpm.debugfs_print_current_performance_level((rdev), (m)) |
#define radeon_dpm_force_performance_level(rdev, l) rdev->asic->dpm.force_performance_level((rdev), (l)) |
#define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev)) |
#define radeon_dpm_powergate_uvd(rdev, g) rdev->asic->dpm.powergate_uvd((rdev), (g)) |
#define radeon_dpm_enable_bapm(rdev, e) rdev->asic->dpm.enable_bapm((rdev), (e)) |
/* 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); |
1869,8 → 2866,8 |
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, |
1881,19 → 2878,28 |
*/ |
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, |
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_clear_invalids(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); |
1906,11 → 2912,19 |
struct radeon_bo_va *bo_va, |
uint64_t offset, |
uint32_t flags); |
int radeon_vm_bo_rmv(struct radeon_device *rdev, |
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 |
1964,11 → 2978,28 |
#if defined(CONFIG_ACPI) |
extern int radeon_acpi_init(struct radeon_device *rdev); |
extern void radeon_acpi_fini(struct radeon_device *rdev); |
extern bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev); |
extern int radeon_acpi_pcie_performance_request(struct radeon_device *rdev, |
u8 perf_req, bool advertise); |
extern int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev); |
#else |
static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; } |
static inline void radeon_acpi_fini(struct radeon_device *rdev) { } |
#endif |
int radeon_cs_packet_parse(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
unsigned idx); |
bool radeon_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p); |
void radeon_cs_dump_packet(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt); |
int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p, |
struct radeon_cs_reloc **cs_reloc, |
int nomm); |
int r600_cs_common_vline_parse(struct radeon_cs_parser *p, |
uint32_t *vline_start_end, |
uint32_t *vline_status); |
#include "radeon_object.h" |
#define DRM_UDELAY(d) udelay(d) |
1978,12 → 3009,5 |
resource_size_t |
drm_get_resource_len(struct drm_device *dev, unsigned int resource); |
bool set_mode(struct drm_device *dev, struct drm_connector *connector, |
videomode_t *mode, bool strict); |
#ifndef __TTM__ |
#define radeon_ttm_set_active_vram_size(a, b) |
#endif |
#endif |
/drivers/video/drm/radeon/radeon_agp.c |
---|
117,9 → 117,6 |
/* 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 |
/drivers/video/drm/radeon/radeon_asic.c |
---|
126,7 → 126,11 |
rdev->mc_rreg = &rs780_mc_rreg; |
rdev->mc_wreg = &rs780_mc_wreg; |
} |
if (rdev->family >= CHIP_R600) { |
if (rdev->family >= CHIP_BONAIRE) { |
rdev->pciep_rreg = &cik_pciep_rreg; |
rdev->pciep_wreg = &cik_pciep_wreg; |
} else if (rdev->family >= CHIP_R600) { |
rdev->pciep_rreg = &r600_pciep_rreg; |
rdev->pciep_wreg = &r600_pciep_wreg; |
} |
168,6 → 172,22 |
/* |
* ASIC |
*/ |
static struct radeon_asic_ring r100_gfx_ring = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r100_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
.cs_parse = &r100_cs_parse, |
.ring_start = &r100_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
.get_rptr = &r100_gfx_get_rptr, |
.get_wptr = &r100_gfx_get_wptr, |
.set_wptr = &r100_gfx_set_wptr, |
.hdp_flush = &r100_ring_hdp_flush, |
}; |
static struct radeon_asic r100_asic = { |
.init = &r100_init, |
// .fini = &r100_fini, |
175,7 → 195,7 |
// .resume = &r100_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &r100_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &r100_mc_wait_for_idle, |
.gart = { |
183,16 → 203,7 |
.set_page = &r100_pci_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r100_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r100_cs_parse, |
.ring_start = &r100_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r100_gfx_ring |
}, |
.irq = { |
.set = &r100_irq_set, |
202,8 → 213,8 |
.bandwidth_update = &r100_bandwidth_update, |
.get_vblank_counter = &r100_get_vblank_counter, |
.wait_for_vblank = &r100_wait_for_vblank, |
// .set_backlight_level = &radeon_legacy_set_backlight_level, |
// .get_backlight_level = &radeon_legacy_get_backlight_level, |
.set_backlight_level = &radeon_legacy_set_backlight_level, |
.get_backlight_level = &radeon_legacy_get_backlight_level, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
218,29 → 229,28 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &r100_hpd_init, |
// .fini = &r100_hpd_fini, |
// .sense = &r100_hpd_sense, |
// .set_polarity = &r100_hpd_set_polarity, |
.init = &r100_hpd_init, |
.fini = &r100_hpd_fini, |
.sense = &r100_hpd_sense, |
.set_polarity = &r100_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &r100_pm_misc, |
// .prepare = &r100_pm_prepare, |
// .finish = &r100_pm_finish, |
// .init_profile = &r100_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_legacy_get_engine_clock, |
// .set_engine_clock = &radeon_legacy_set_engine_clock, |
// .get_memory_clock = &radeon_legacy_get_memory_clock, |
.misc = &r100_pm_misc, |
.prepare = &r100_pm_prepare, |
.finish = &r100_pm_finish, |
.init_profile = &r100_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_legacy_get_engine_clock, |
.set_engine_clock = &radeon_legacy_set_engine_clock, |
.get_memory_clock = &radeon_legacy_get_memory_clock, |
.set_memory_clock = NULL, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
// .set_clock_gating = &radeon_legacy_set_clock_gating, |
.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, |
}, |
}; |
251,7 → 261,7 |
// .resume = &r100_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &r100_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &r100_mc_wait_for_idle, |
.gart = { |
259,16 → 269,7 |
.set_page = &r100_pci_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r100_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r100_cs_parse, |
.ring_start = &r100_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r100_gfx_ring |
}, |
.irq = { |
.set = &r100_irq_set, |
278,8 → 279,8 |
.bandwidth_update = &r100_bandwidth_update, |
.get_vblank_counter = &r100_get_vblank_counter, |
.wait_for_vblank = &r100_wait_for_vblank, |
// .set_backlight_level = &radeon_legacy_set_backlight_level, |
// .get_backlight_level = &radeon_legacy_get_backlight_level, |
.set_backlight_level = &radeon_legacy_set_backlight_level, |
.get_backlight_level = &radeon_legacy_get_backlight_level, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
294,32 → 295,46 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &r100_hpd_init, |
// .fini = &r100_hpd_fini, |
// .sense = &r100_hpd_sense, |
// .set_polarity = &r100_hpd_set_polarity, |
.init = &r100_hpd_init, |
.fini = &r100_hpd_fini, |
.sense = &r100_hpd_sense, |
.set_polarity = &r100_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &r100_pm_misc, |
// .prepare = &r100_pm_prepare, |
// .finish = &r100_pm_finish, |
// .init_profile = &r100_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_legacy_get_engine_clock, |
// .set_engine_clock = &radeon_legacy_set_engine_clock, |
// .get_memory_clock = &radeon_legacy_get_memory_clock, |
.misc = &r100_pm_misc, |
.prepare = &r100_pm_prepare, |
.finish = &r100_pm_finish, |
.init_profile = &r100_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_legacy_get_engine_clock, |
.set_engine_clock = &radeon_legacy_set_engine_clock, |
.get_memory_clock = &radeon_legacy_get_memory_clock, |
.set_memory_clock = NULL, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
// .set_clock_gating = &radeon_legacy_set_clock_gating, |
.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, |
}, |
}; |
static struct radeon_asic_ring r300_gfx_ring = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
.cs_parse = &r300_cs_parse, |
.ring_start = &r300_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
.get_rptr = &r100_gfx_get_rptr, |
.get_wptr = &r100_gfx_get_wptr, |
.set_wptr = &r100_gfx_set_wptr, |
.hdp_flush = &r100_ring_hdp_flush, |
}; |
static struct radeon_asic r300_asic = { |
.init = &r300_init, |
// .fini = &r300_fini, |
327,7 → 342,7 |
// .resume = &r300_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &r300_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &r300_mc_wait_for_idle, |
.gart = { |
335,16 → 350,7 |
.set_page = &r100_pci_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r300_cs_parse, |
.ring_start = &r300_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring |
}, |
.irq = { |
.set = &r100_irq_set, |
354,8 → 360,8 |
.bandwidth_update = &r100_bandwidth_update, |
.get_vblank_counter = &r100_get_vblank_counter, |
.wait_for_vblank = &r100_wait_for_vblank, |
// .set_backlight_level = &radeon_legacy_set_backlight_level, |
// .get_backlight_level = &radeon_legacy_get_backlight_level, |
.set_backlight_level = &radeon_legacy_set_backlight_level, |
.get_backlight_level = &radeon_legacy_get_backlight_level, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
370,29 → 376,28 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &r100_hpd_init, |
// .fini = &r100_hpd_fini, |
// .sense = &r100_hpd_sense, |
// .set_polarity = &r100_hpd_set_polarity, |
.init = &r100_hpd_init, |
.fini = &r100_hpd_fini, |
.sense = &r100_hpd_sense, |
.set_polarity = &r100_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &r100_pm_misc, |
// .prepare = &r100_pm_prepare, |
// .finish = &r100_pm_finish, |
// .init_profile = &r100_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_legacy_get_engine_clock, |
// .set_engine_clock = &radeon_legacy_set_engine_clock, |
// .get_memory_clock = &radeon_legacy_get_memory_clock, |
// .set_memory_clock = NULL, |
// .get_pcie_lanes = &rv370_get_pcie_lanes, |
// .set_pcie_lanes = &rv370_set_pcie_lanes, |
// .set_clock_gating = &radeon_legacy_set_clock_gating, |
.misc = &r100_pm_misc, |
.prepare = &r100_pm_prepare, |
.finish = &r100_pm_finish, |
.init_profile = &r100_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_legacy_get_engine_clock, |
.set_engine_clock = &radeon_legacy_set_engine_clock, |
.get_memory_clock = &radeon_legacy_get_memory_clock, |
.set_memory_clock = NULL, |
.get_pcie_lanes = &rv370_get_pcie_lanes, |
.set_pcie_lanes = &rv370_set_pcie_lanes, |
.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, |
}, |
}; |
403,7 → 408,7 |
// .resume = &r300_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &r300_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &r300_mc_wait_for_idle, |
.gart = { |
411,16 → 416,7 |
.set_page = &rv370_pcie_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r300_cs_parse, |
.ring_start = &r300_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring |
}, |
.irq = { |
.set = &r100_irq_set, |
430,8 → 426,8 |
.bandwidth_update = &r100_bandwidth_update, |
.get_vblank_counter = &r100_get_vblank_counter, |
.wait_for_vblank = &r100_wait_for_vblank, |
// .set_backlight_level = &radeon_legacy_set_backlight_level, |
// .get_backlight_level = &radeon_legacy_get_backlight_level, |
.set_backlight_level = &radeon_legacy_set_backlight_level, |
.get_backlight_level = &radeon_legacy_get_backlight_level, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
452,23 → 448,22 |
.set_polarity = &r100_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &r100_pm_misc, |
// .prepare = &r100_pm_prepare, |
// .finish = &r100_pm_finish, |
// .init_profile = &r100_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_legacy_get_engine_clock, |
// .set_engine_clock = &radeon_legacy_set_engine_clock, |
// .get_memory_clock = &radeon_legacy_get_memory_clock, |
// .set_memory_clock = NULL, |
// .get_pcie_lanes = &rv370_get_pcie_lanes, |
// .set_pcie_lanes = &rv370_set_pcie_lanes, |
// .set_clock_gating = &radeon_legacy_set_clock_gating, |
.misc = &r100_pm_misc, |
.prepare = &r100_pm_prepare, |
.finish = &r100_pm_finish, |
.init_profile = &r100_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_legacy_get_engine_clock, |
.set_engine_clock = &radeon_legacy_set_engine_clock, |
.get_memory_clock = &radeon_legacy_get_memory_clock, |
.set_memory_clock = NULL, |
.get_pcie_lanes = &rv370_get_pcie_lanes, |
.set_pcie_lanes = &rv370_set_pcie_lanes, |
.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, |
}, |
}; |
479,7 → 474,7 |
// .resume = &r420_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &r300_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &r300_mc_wait_for_idle, |
.gart = { |
487,16 → 482,7 |
.set_page = &rv370_pcie_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r300_cs_parse, |
.ring_start = &r300_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring |
}, |
.irq = { |
.set = &r100_irq_set, |
506,8 → 492,8 |
.bandwidth_update = &r100_bandwidth_update, |
.get_vblank_counter = &r100_get_vblank_counter, |
.wait_for_vblank = &r100_wait_for_vblank, |
// .set_backlight_level = &atombios_set_backlight_level, |
// .get_backlight_level = &atombios_get_backlight_level, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
522,29 → 508,28 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &r100_hpd_init, |
// .fini = &r100_hpd_fini, |
// .sense = &r100_hpd_sense, |
// .set_polarity = &r100_hpd_set_polarity, |
.init = &r100_hpd_init, |
.fini = &r100_hpd_fini, |
.sense = &r100_hpd_sense, |
.set_polarity = &r100_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &r100_pm_misc, |
// .prepare = &r100_pm_prepare, |
// .finish = &r100_pm_finish, |
// .init_profile = &r420_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
// .get_pcie_lanes = &rv370_get_pcie_lanes, |
// .set_pcie_lanes = &rv370_set_pcie_lanes, |
// .set_clock_gating = &radeon_atom_set_clock_gating, |
.misc = &r100_pm_misc, |
.prepare = &r100_pm_prepare, |
.finish = &r100_pm_finish, |
.init_profile = &r420_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &rv370_get_pcie_lanes, |
.set_pcie_lanes = &rv370_set_pcie_lanes, |
.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, |
}, |
}; |
555,7 → 540,7 |
// .resume = &rs400_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &r300_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &rs400_mc_wait_for_idle, |
.gart = { |
563,16 → 548,7 |
.set_page = &rs400_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r300_cs_parse, |
.ring_start = &r300_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring |
}, |
.irq = { |
.set = &r100_irq_set, |
582,8 → 558,8 |
.bandwidth_update = &r100_bandwidth_update, |
.get_vblank_counter = &r100_get_vblank_counter, |
.wait_for_vblank = &r100_wait_for_vblank, |
// .set_backlight_level = &radeon_legacy_set_backlight_level, |
// .get_backlight_level = &radeon_legacy_get_backlight_level, |
.set_backlight_level = &radeon_legacy_set_backlight_level, |
.get_backlight_level = &radeon_legacy_get_backlight_level, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
598,29 → 574,28 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &r100_hpd_init, |
// .fini = &r100_hpd_fini, |
// .sense = &r100_hpd_sense, |
// .set_polarity = &r100_hpd_set_polarity, |
.init = &r100_hpd_init, |
.fini = &r100_hpd_fini, |
.sense = &r100_hpd_sense, |
.set_polarity = &r100_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &r100_pm_misc, |
// .prepare = &r100_pm_prepare, |
// .finish = &r100_pm_finish, |
// .init_profile = &r100_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_legacy_get_engine_clock, |
// .set_engine_clock = &radeon_legacy_set_engine_clock, |
// .get_memory_clock = &radeon_legacy_get_memory_clock, |
// .set_memory_clock = NULL, |
// .get_pcie_lanes = NULL, |
// .set_pcie_lanes = NULL, |
// .set_clock_gating = &radeon_legacy_set_clock_gating, |
.misc = &r100_pm_misc, |
.prepare = &r100_pm_prepare, |
.finish = &r100_pm_finish, |
.init_profile = &r100_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_legacy_get_engine_clock, |
.set_engine_clock = &radeon_legacy_set_engine_clock, |
.get_memory_clock = &radeon_legacy_get_memory_clock, |
.set_memory_clock = NULL, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
.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, |
}, |
}; |
631,7 → 606,7 |
// .resume = &rs600_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &rs600_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &rs600_mc_wait_for_idle, |
.gart = { |
639,16 → 614,7 |
.set_page = &rs600_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r300_cs_parse, |
.ring_start = &r300_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring |
}, |
.irq = { |
.set = &rs600_irq_set, |
658,8 → 624,10 |
.bandwidth_update = &rs600_bandwidth_update, |
.get_vblank_counter = &rs600_get_vblank_counter, |
.wait_for_vblank = &avivo_wait_for_vblank, |
// .set_backlight_level = &atombios_set_backlight_level, |
// .get_backlight_level = &atombios_get_backlight_level, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &r600_hdmi_enable, |
.hdmi_setmode = &r600_hdmi_setmode, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
674,29 → 642,28 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &rs600_hpd_init, |
// .fini = &rs600_hpd_fini, |
// .sense = &rs600_hpd_sense, |
// .set_polarity = &rs600_hpd_set_polarity, |
.init = &rs600_hpd_init, |
.fini = &rs600_hpd_fini, |
.sense = &rs600_hpd_sense, |
.set_polarity = &rs600_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &rs600_pm_misc, |
// .prepare = &rs600_pm_prepare, |
// .finish = &rs600_pm_finish, |
// .init_profile = &r420_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
.misc = &rs600_pm_misc, |
.prepare = &rs600_pm_prepare, |
.finish = &rs600_pm_finish, |
.init_profile = &r420_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
// .set_clock_gating = &radeon_atom_set_clock_gating, |
.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, |
}, |
}; |
707,7 → 674,7 |
// .resume = &rs690_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &rs600_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &rs690_mc_wait_for_idle, |
.gart = { |
715,16 → 682,7 |
.set_page = &rs400_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r300_cs_parse, |
.ring_start = &r300_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring |
}, |
.irq = { |
.set = &rs600_irq_set, |
734,8 → 692,10 |
.get_vblank_counter = &rs600_get_vblank_counter, |
.bandwidth_update = &rs690_bandwidth_update, |
.wait_for_vblank = &avivo_wait_for_vblank, |
// .set_backlight_level = &atombios_set_backlight_level, |
// .get_backlight_level = &atombios_get_backlight_level, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &r600_hdmi_enable, |
.hdmi_setmode = &r600_hdmi_setmode, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
750,29 → 710,28 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &rs600_hpd_init, |
// .fini = &rs600_hpd_fini, |
.init = &rs600_hpd_init, |
.fini = &rs600_hpd_fini, |
.sense = &rs600_hpd_sense, |
.set_polarity = &rs600_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &rs600_pm_misc, |
// .prepare = &rs600_pm_prepare, |
// .finish = &rs600_pm_finish, |
// .init_profile = &r420_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
.misc = &rs600_pm_misc, |
.prepare = &rs600_pm_prepare, |
.finish = &rs600_pm_finish, |
.init_profile = &r420_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
// .set_clock_gating = &radeon_atom_set_clock_gating, |
.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, |
}, |
}; |
783,7 → 742,7 |
// .resume = &rv515_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &rs600_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &rv515_mc_wait_for_idle, |
.gart = { |
791,16 → 750,7 |
.set_page = &rv370_pcie_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r300_cs_parse, |
.ring_start = &rv515_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring |
}, |
.irq = { |
.set = &rs600_irq_set, |
810,8 → 760,8 |
.get_vblank_counter = &rs600_get_vblank_counter, |
.bandwidth_update = &rv515_bandwidth_update, |
.wait_for_vblank = &avivo_wait_for_vblank, |
// .set_backlight_level = &atombios_set_backlight_level, |
// .get_backlight_level = &atombios_get_backlight_level, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
826,29 → 776,28 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &rs600_hpd_init, |
// .fini = &rs600_hpd_fini, |
// .sense = &rs600_hpd_sense, |
// .set_polarity = &rs600_hpd_set_polarity, |
.init = &rs600_hpd_init, |
.fini = &rs600_hpd_fini, |
.sense = &rs600_hpd_sense, |
.set_polarity = &rs600_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &rs600_pm_misc, |
// .prepare = &rs600_pm_prepare, |
// .finish = &rs600_pm_finish, |
// .init_profile = &r420_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
// .get_pcie_lanes = &rv370_get_pcie_lanes, |
// .set_pcie_lanes = &rv370_set_pcie_lanes, |
// .set_clock_gating = &radeon_atom_set_clock_gating, |
.misc = &rs600_pm_misc, |
.prepare = &rs600_pm_prepare, |
.finish = &rs600_pm_finish, |
.init_profile = &r420_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &rv370_get_pcie_lanes, |
.set_pcie_lanes = &rv370_set_pcie_lanes, |
.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, |
}, |
}; |
859,7 → 808,7 |
// .resume = &r520_resume, |
// .vga_set_state = &r100_vga_set_state, |
.asic_reset = &rs600_asic_reset, |
.ioctl_wait_idle = NULL, |
.mmio_hdp_flush = NULL, |
.gui_idle = &r100_gui_idle, |
.mc_wait_for_idle = &r520_mc_wait_for_idle, |
.gart = { |
867,16 → 816,7 |
.set_page = &rv370_pcie_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r100_ring_ib_execute, |
.emit_fence = &r300_fence_ring_emit, |
.emit_semaphore = &r100_semaphore_ring_emit, |
// .cs_parse = &r300_cs_parse, |
.ring_start = &rv515_ring_start, |
.ring_test = &r100_ring_test, |
.ib_test = &r100_ib_test, |
.is_lockup = &r100_gpu_is_lockup, |
} |
[RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring |
}, |
.irq = { |
.set = &rs600_irq_set, |
886,8 → 826,8 |
.bandwidth_update = &rv515_bandwidth_update, |
.get_vblank_counter = &rs600_get_vblank_counter, |
.wait_for_vblank = &avivo_wait_for_vblank, |
// .set_backlight_level = &atombios_set_backlight_level, |
// .get_backlight_level = &atombios_get_backlight_level, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
}, |
.copy = { |
.blit = &r100_copy_blit, |
902,32 → 842,57 |
.clear_reg = r100_clear_surface_reg, |
}, |
.hpd = { |
// .init = &rs600_hpd_init, |
// .fini = &rs600_hpd_fini, |
// .sense = &rs600_hpd_sense, |
// .set_polarity = &rs600_hpd_set_polarity, |
.init = &rs600_hpd_init, |
.fini = &rs600_hpd_fini, |
.sense = &rs600_hpd_sense, |
.set_polarity = &rs600_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &rs600_pm_misc, |
// .prepare = &rs600_pm_prepare, |
// .finish = &rs600_pm_finish, |
// .init_profile = &r420_pm_init_profile, |
// .get_dynpm_state = &r100_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
// .get_pcie_lanes = &rv370_get_pcie_lanes, |
// .set_pcie_lanes = &rv370_set_pcie_lanes, |
// .set_clock_gating = &radeon_atom_set_clock_gating, |
.misc = &rs600_pm_misc, |
.prepare = &rs600_pm_prepare, |
.finish = &rs600_pm_finish, |
.init_profile = &r420_pm_init_profile, |
.get_dynpm_state = &r100_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &rv370_get_pcie_lanes, |
.set_pcie_lanes = &rv370_set_pcie_lanes, |
.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, |
}, |
}; |
static struct radeon_asic_ring r600_gfx_ring = { |
.ib_execute = &r600_ring_ib_execute, |
.emit_fence = &r600_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
.cs_parse = &r600_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &r600_gfx_is_lockup, |
.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 = { |
.ib_execute = &r600_dma_ring_ib_execute, |
.emit_fence = &r600_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
.cs_parse = &r600_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &r600_dma_is_lockup, |
.get_rptr = &r600_dma_get_rptr, |
.get_wptr = &r600_dma_get_wptr, |
.set_wptr = &r600_dma_set_wptr, |
}; |
static struct radeon_asic r600_asic = { |
.init = &r600_init, |
// .fini = &r600_fini, |
935,7 → 900,7 |
// .resume = &r600_resume, |
// .vga_set_state = &r600_vga_set_state, |
.asic_reset = &r600_asic_reset, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &r600_mc_wait_for_idle, |
.get_xclk = &r600_get_xclk, |
945,25 → 910,81 |
.set_page = &rs600_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r600_ring_ib_execute, |
.emit_fence = &r600_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &r600_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &r600_gfx_is_lockup, |
[RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &r600_dma_ring_ib_execute, |
.emit_fence = &r600_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &r600_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &r600_dma_is_lockup, |
} |
.irq = { |
.set = &r600_irq_set, |
.process = &r600_irq_process, |
}, |
.display = { |
.bandwidth_update = &rv515_bandwidth_update, |
.get_vblank_counter = &rs600_get_vblank_counter, |
.wait_for_vblank = &avivo_wait_for_vblank, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &r600_hdmi_enable, |
.hdmi_setmode = &r600_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &r600_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
.copy = &r600_copy_cpdma, |
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
}, |
.surface = { |
.set_reg = r600_set_surface_reg, |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
.init = &r600_hpd_init, |
.fini = &r600_hpd_fini, |
.sense = &r600_hpd_sense, |
.set_polarity = &r600_hpd_set_polarity, |
}, |
.pm = { |
.misc = &r600_pm_misc, |
.prepare = &rs600_pm_prepare, |
.finish = &rs600_pm_finish, |
.init_profile = &r600_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &r600_get_pcie_lanes, |
.set_pcie_lanes = &r600_set_pcie_lanes, |
.set_clock_gating = NULL, |
.get_temperature = &rv6xx_get_temp, |
}, |
.pflip = { |
// .pre_page_flip = &rs600_pre_page_flip, |
// .page_flip = &rs600_page_flip, |
}, |
}; |
static struct radeon_asic rv6xx_asic = { |
.init = &r600_init, |
// .fini = &r600_fini, |
// .suspend = &r600_suspend, |
// .resume = &r600_resume, |
// .vga_set_state = &r600_vga_set_state, |
.asic_reset = &r600_asic_reset, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &r600_mc_wait_for_idle, |
.get_xclk = &r600_get_xclk, |
.get_gpu_clock_counter = &r600_get_gpu_clock_counter, |
.gart = { |
.tlb_flush = &r600_pcie_gart_tlb_flush, |
.set_page = &rs600_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring, |
}, |
.irq = { |
.set = &r600_irq_set, |
.process = &r600_irq_process, |
972,16 → 993,18 |
.bandwidth_update = &rv515_bandwidth_update, |
.get_vblank_counter = &rs600_get_vblank_counter, |
.wait_for_vblank = &avivo_wait_for_vblank, |
// .set_backlight_level = &atombios_set_backlight_level, |
// .get_backlight_level = &atombios_get_backlight_level, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &r600_hdmi_enable, |
.hdmi_setmode = &r600_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_blit, |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &r600_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
.copy = &r600_copy_dma, |
.copy_ring_index = R600_RING_TYPE_DMA_INDEX, |
.copy = &r600_copy_cpdma, |
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
}, |
.surface = { |
.set_reg = r600_set_surface_reg, |
988,29 → 1011,47 |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
// .init = &r600_hpd_init, |
// .fini = &r600_hpd_fini, |
// .sense = &r600_hpd_sense, |
// .set_polarity = &r600_hpd_set_polarity, |
.init = &r600_hpd_init, |
.fini = &r600_hpd_fini, |
.sense = &r600_hpd_sense, |
.set_polarity = &r600_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &r600_pm_misc, |
// .prepare = &rs600_pm_prepare, |
// .finish = &rs600_pm_finish, |
// .init_profile = &r600_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
// .get_pcie_lanes = &r600_get_pcie_lanes, |
// .set_pcie_lanes = &r600_set_pcie_lanes, |
.misc = &r600_pm_misc, |
.prepare = &rs600_pm_prepare, |
.finish = &rs600_pm_finish, |
.init_profile = &r600_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &r600_get_pcie_lanes, |
.set_pcie_lanes = &r600_set_pcie_lanes, |
.set_clock_gating = NULL, |
.get_temperature = &rv6xx_get_temp, |
.set_uvd_clocks = &r600_set_uvd_clocks, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &r600_dpm_post_set_power_state, |
.display_configuration_changed = &rv6xx_dpm_display_configuration_changed, |
.fini = &rv6xx_dpm_fini, |
.get_sclk = &rv6xx_dpm_get_sclk, |
.get_mclk = &rv6xx_dpm_get_mclk, |
.print_power_state = &rv6xx_dpm_print_power_state, |
.debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level, |
.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, |
}, |
}; |
1021,7 → 1062,7 |
// .resume = &r600_resume, |
// .vga_set_state = &r600_vga_set_state, |
.asic_reset = &r600_asic_reset, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &r600_mc_wait_for_idle, |
.get_xclk = &r600_get_xclk, |
1031,25 → 1072,9 |
.set_page = &rs600_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r600_ring_ib_execute, |
.emit_fence = &r600_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &r600_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &r600_gfx_is_lockup, |
[RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &r600_dma_ring_ib_execute, |
.emit_fence = &r600_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &r600_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &r600_dma_is_lockup, |
} |
}, |
.irq = { |
.set = &r600_irq_set, |
.process = &r600_irq_process, |
1058,16 → 1083,18 |
.bandwidth_update = &rs690_bandwidth_update, |
.get_vblank_counter = &rs600_get_vblank_counter, |
.wait_for_vblank = &avivo_wait_for_vblank, |
// .set_backlight_level = &atombios_set_backlight_level, |
// .get_backlight_level = &atombios_get_backlight_level, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &r600_hdmi_enable, |
.hdmi_setmode = &r600_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_blit, |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &r600_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
.copy = &r600_copy_dma, |
.copy_ring_index = R600_RING_TYPE_DMA_INDEX, |
.copy = &r600_copy_cpdma, |
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
}, |
.surface = { |
.set_reg = r600_set_surface_reg, |
1074,32 → 1101,63 |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
// .init = &r600_hpd_init, |
// .fini = &r600_hpd_fini, |
// .sense = &r600_hpd_sense, |
// .set_polarity = &r600_hpd_set_polarity, |
.init = &r600_hpd_init, |
.fini = &r600_hpd_fini, |
.sense = &r600_hpd_sense, |
.set_polarity = &r600_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &r600_pm_misc, |
// .prepare = &rs600_pm_prepare, |
// .finish = &rs600_pm_finish, |
// .init_profile = &rs780_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
.misc = &r600_pm_misc, |
.prepare = &rs600_pm_prepare, |
.finish = &rs600_pm_finish, |
.init_profile = &rs780_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = NULL, |
.set_memory_clock = NULL, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
.set_clock_gating = NULL, |
.get_temperature = &rv6xx_get_temp, |
.set_uvd_clocks = &r600_set_uvd_clocks, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &r600_dpm_post_set_power_state, |
.display_configuration_changed = &rs780_dpm_display_configuration_changed, |
.fini = &rs780_dpm_fini, |
.get_sclk = &rs780_dpm_get_sclk, |
.get_mclk = &rs780_dpm_get_mclk, |
.print_power_state = &rs780_dpm_print_power_state, |
.debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level, |
.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, |
}, |
}; |
static struct radeon_asic_ring rv770_uvd_ring = { |
.ib_execute = &uvd_v1_0_ib_execute, |
.emit_fence = &uvd_v2_2_fence_emit, |
.emit_semaphore = &uvd_v1_0_semaphore_emit, |
.cs_parse = &radeon_uvd_cs_parse, |
.ring_test = &uvd_v1_0_ring_test, |
.ib_test = &uvd_v1_0_ib_test, |
.is_lockup = &radeon_ring_test_lockup, |
.get_rptr = &uvd_v1_0_get_rptr, |
.get_wptr = &uvd_v1_0_get_wptr, |
.set_wptr = &uvd_v1_0_set_wptr, |
}; |
static struct radeon_asic rv770_asic = { |
.init = &rv770_init, |
// .fini = &rv770_fini, |
1107,7 → 1165,7 |
// .resume = &rv770_resume, |
.asic_reset = &r600_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &r600_mc_wait_for_idle, |
.get_xclk = &rv770_get_xclk, |
1117,34 → 1175,10 |
.set_page = &rs600_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &r600_ring_ib_execute, |
.emit_fence = &r600_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &r600_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &r600_gfx_is_lockup, |
[RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring, |
[R600_RING_TYPE_UVD_INDEX] = &rv770_uvd_ring, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &r600_dma_ring_ib_execute, |
.emit_fence = &r600_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &r600_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &r600_dma_is_lockup, |
}, |
[R600_RING_TYPE_UVD_INDEX] = { |
// .ib_execute = &r600_uvd_ib_execute, |
// .emit_fence = &r600_uvd_fence_emit, |
// .emit_semaphore = &r600_uvd_semaphore_emit, |
// .cs_parse = &radeon_uvd_cs_parse, |
// .ring_test = &r600_uvd_ring_test, |
// .ib_test = &r600_uvd_ib_test, |
// .is_lockup = &radeon_ring_test_lockup, |
} |
}, |
.irq = { |
.set = &r600_irq_set, |
.process = &r600_irq_process, |
1153,11 → 1187,13 |
.bandwidth_update = &rv515_bandwidth_update, |
.get_vblank_counter = &rs600_get_vblank_counter, |
.wait_for_vblank = &avivo_wait_for_vblank, |
// .set_backlight_level = &atombios_set_backlight_level, |
// .get_backlight_level = &atombios_get_backlight_level, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &r600_hdmi_enable, |
.hdmi_setmode = &dce3_1_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_blit, |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &rv770_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
1169,33 → 1205,77 |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
// .init = &r600_hpd_init, |
// .fini = &r600_hpd_fini, |
// .sense = &r600_hpd_sense, |
// .set_polarity = &r600_hpd_set_polarity, |
.init = &r600_hpd_init, |
.fini = &r600_hpd_fini, |
.sense = &r600_hpd_sense, |
.set_polarity = &r600_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &rv770_pm_misc, |
// .prepare = &rs600_pm_prepare, |
// .finish = &rs600_pm_finish, |
// .init_profile = &r600_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
// .get_pcie_lanes = &r600_get_pcie_lanes, |
// .set_pcie_lanes = &r600_set_pcie_lanes, |
// .set_clock_gating = &radeon_atom_set_clock_gating, |
.misc = &rv770_pm_misc, |
.prepare = &rs600_pm_prepare, |
.finish = &rs600_pm_finish, |
.init_profile = &r600_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &r600_get_pcie_lanes, |
.set_pcie_lanes = &r600_set_pcie_lanes, |
.set_clock_gating = &radeon_atom_set_clock_gating, |
.set_uvd_clocks = &rv770_set_uvd_clocks, |
.get_temperature = &rv770_get_temp, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &r600_dpm_post_set_power_state, |
.display_configuration_changed = &rv770_dpm_display_configuration_changed, |
.fini = &rv770_dpm_fini, |
.get_sclk = &rv770_dpm_get_sclk, |
.get_mclk = &rv770_dpm_get_mclk, |
.print_power_state = &rv770_dpm_print_power_state, |
.debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, |
.force_performance_level = &rv770_dpm_force_performance_level, |
.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, |
}, |
}; |
static struct radeon_asic_ring evergreen_gfx_ring = { |
.ib_execute = &evergreen_ring_ib_execute, |
.emit_fence = &r600_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
.cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &evergreen_gfx_is_lockup, |
.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 = { |
.ib_execute = &evergreen_dma_ring_ib_execute, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
.cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &evergreen_dma_is_lockup, |
.get_rptr = &r600_dma_get_rptr, |
.get_wptr = &r600_dma_get_wptr, |
.set_wptr = &r600_dma_set_wptr, |
}; |
static struct radeon_asic evergreen_asic = { |
.init = &evergreen_init, |
// .fini = &evergreen_fini, |
1203,7 → 1283,7 |
// .resume = &evergreen_resume, |
.asic_reset = &evergreen_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &evergreen_mc_wait_for_idle, |
.get_xclk = &rv770_get_xclk, |
1213,34 → 1293,10 |
.set_page = &rs600_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &evergreen_ring_ib_execute, |
.emit_fence = &r600_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &evergreen_gfx_is_lockup, |
[RADEON_RING_TYPE_GFX_INDEX] = &evergreen_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &evergreen_dma_ring, |
[R600_RING_TYPE_UVD_INDEX] = &rv770_uvd_ring, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &evergreen_dma_ring_ib_execute, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &evergreen_dma_is_lockup, |
}, |
[R600_RING_TYPE_UVD_INDEX] = { |
// .ib_execute = &r600_uvd_ib_execute, |
// .emit_fence = &r600_uvd_fence_emit, |
// .emit_semaphore = &r600_uvd_semaphore_emit, |
// .cs_parse = &radeon_uvd_cs_parse, |
// .ring_test = &r600_uvd_ring_test, |
// .ib_test = &r600_uvd_ib_test, |
// .is_lockup = &radeon_ring_test_lockup, |
} |
}, |
.irq = { |
.set = &evergreen_irq_set, |
.process = &evergreen_irq_process, |
1249,11 → 1305,13 |
.bandwidth_update = &evergreen_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, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &evergreen_hdmi_enable, |
.hdmi_setmode = &evergreen_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_blit, |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &evergreen_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
1265,30 → 1323,46 |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
// .init = &evergreen_hpd_init, |
// .fini = &evergreen_hpd_fini, |
// .sense = &evergreen_hpd_sense, |
// .set_polarity = &evergreen_hpd_set_polarity, |
.init = &evergreen_hpd_init, |
.fini = &evergreen_hpd_fini, |
.sense = &evergreen_hpd_sense, |
.set_polarity = &evergreen_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &evergreen_pm_misc, |
// .prepare = &evergreen_pm_prepare, |
// .finish = &evergreen_pm_finish, |
// .init_profile = &r600_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
// .get_pcie_lanes = &r600_get_pcie_lanes, |
// .set_pcie_lanes = &r600_set_pcie_lanes, |
// .set_clock_gating = NULL, |
.misc = &evergreen_pm_misc, |
.prepare = &evergreen_pm_prepare, |
.finish = &evergreen_pm_finish, |
.init_profile = &r600_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &r600_get_pcie_lanes, |
.set_pcie_lanes = &r600_set_pcie_lanes, |
.set_clock_gating = NULL, |
.set_uvd_clocks = &evergreen_set_uvd_clocks, |
.get_temperature = &evergreen_get_temp, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &r600_dpm_post_set_power_state, |
.display_configuration_changed = &cypress_dpm_display_configuration_changed, |
.fini = &cypress_dpm_fini, |
.get_sclk = &rv770_dpm_get_sclk, |
.get_mclk = &rv770_dpm_get_mclk, |
.print_power_state = &rv770_dpm_print_power_state, |
.debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, |
.force_performance_level = &rv770_dpm_force_performance_level, |
.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, |
}, |
}; |
1299,7 → 1373,7 |
// .resume = &evergreen_resume, |
.asic_reset = &evergreen_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &evergreen_mc_wait_for_idle, |
.get_xclk = &r600_get_xclk, |
1309,34 → 1383,10 |
.set_page = &rs600_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &evergreen_ring_ib_execute, |
.emit_fence = &r600_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &evergreen_gfx_is_lockup, |
[RADEON_RING_TYPE_GFX_INDEX] = &evergreen_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &evergreen_dma_ring, |
[R600_RING_TYPE_UVD_INDEX] = &rv770_uvd_ring, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &evergreen_dma_ring_ib_execute, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &evergreen_dma_is_lockup, |
}, |
[R600_RING_TYPE_UVD_INDEX] = { |
// .ib_execute = &r600_uvd_ib_execute, |
// .emit_fence = &r600_uvd_fence_emit, |
// .emit_semaphore = &r600_uvd_semaphore_emit, |
// .cs_parse = &radeon_uvd_cs_parse, |
// .ring_test = &r600_uvd_ring_test, |
// .ib_test = &r600_uvd_ib_test, |
// .is_lockup = &radeon_ring_test_lockup, |
} |
}, |
.irq = { |
.set = &evergreen_irq_set, |
.process = &evergreen_irq_process, |
1345,11 → 1395,13 |
.bandwidth_update = &evergreen_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, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &evergreen_hdmi_enable, |
.hdmi_setmode = &evergreen_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_blit, |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &evergreen_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
1361,19 → 1413,19 |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
// .init = &evergreen_hpd_init, |
// .fini = &evergreen_hpd_fini, |
// .sense = &evergreen_hpd_sense, |
// .set_polarity = &evergreen_hpd_set_polarity, |
.init = &evergreen_hpd_init, |
.fini = &evergreen_hpd_fini, |
.sense = &evergreen_hpd_sense, |
.set_polarity = &evergreen_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &evergreen_pm_misc, |
// .prepare = &evergreen_pm_prepare, |
// .finish = &evergreen_pm_finish, |
// .init_profile = &sumo_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
.misc = &evergreen_pm_misc, |
.prepare = &evergreen_pm_prepare, |
.finish = &evergreen_pm_finish, |
.init_profile = &sumo_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = NULL, |
.set_memory_clock = NULL, |
.get_pcie_lanes = NULL, |
1380,11 → 1432,28 |
.set_pcie_lanes = NULL, |
.set_clock_gating = NULL, |
.set_uvd_clocks = &sumo_set_uvd_clocks, |
.get_temperature = &sumo_get_temp, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &sumo_dpm_post_set_power_state, |
.display_configuration_changed = &sumo_dpm_display_configuration_changed, |
.fini = &sumo_dpm_fini, |
.get_sclk = &sumo_dpm_get_sclk, |
.get_mclk = &sumo_dpm_get_mclk, |
.print_power_state = &sumo_dpm_print_power_state, |
.debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level, |
.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, |
}, |
}; |
1395,7 → 1464,7 |
// .resume = &evergreen_resume, |
.asic_reset = &evergreen_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &evergreen_mc_wait_for_idle, |
.get_xclk = &rv770_get_xclk, |
1405,34 → 1474,10 |
.set_page = &rs600_gart_set_page, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &evergreen_ring_ib_execute, |
.emit_fence = &r600_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &evergreen_gfx_is_lockup, |
[RADEON_RING_TYPE_GFX_INDEX] = &evergreen_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &evergreen_dma_ring, |
[R600_RING_TYPE_UVD_INDEX] = &rv770_uvd_ring, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &evergreen_dma_ring_ib_execute, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &evergreen_dma_is_lockup, |
}, |
[R600_RING_TYPE_UVD_INDEX] = { |
// .ib_execute = &r600_uvd_ib_execute, |
// .emit_fence = &r600_uvd_fence_emit, |
// .emit_semaphore = &r600_uvd_semaphore_emit, |
// .cs_parse = &radeon_uvd_cs_parse, |
// .ring_test = &r600_uvd_ring_test, |
// .ib_test = &r600_uvd_ib_test, |
// .is_lockup = &radeon_ring_test_lockup, |
} |
}, |
.irq = { |
.set = &evergreen_irq_set, |
.process = &evergreen_irq_process, |
1441,11 → 1486,13 |
.bandwidth_update = &evergreen_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, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &evergreen_hdmi_enable, |
.hdmi_setmode = &evergreen_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_blit, |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &evergreen_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
1457,33 → 1504,94 |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
// .init = &evergreen_hpd_init, |
// .fini = &evergreen_hpd_fini, |
// .sense = &evergreen_hpd_sense, |
// .set_polarity = &evergreen_hpd_set_polarity, |
.init = &evergreen_hpd_init, |
.fini = &evergreen_hpd_fini, |
.sense = &evergreen_hpd_sense, |
.set_polarity = &evergreen_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &evergreen_pm_misc, |
// .prepare = &evergreen_pm_prepare, |
// .finish = &evergreen_pm_finish, |
// .init_profile = &btc_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
.misc = &evergreen_pm_misc, |
.prepare = &evergreen_pm_prepare, |
.finish = &evergreen_pm_finish, |
.init_profile = &btc_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &r600_get_pcie_lanes, |
.set_pcie_lanes = &r600_set_pcie_lanes, |
.set_clock_gating = NULL, |
.set_uvd_clocks = &evergreen_set_uvd_clocks, |
.get_temperature = &evergreen_get_temp, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &btc_dpm_post_set_power_state, |
.display_configuration_changed = &cypress_dpm_display_configuration_changed, |
.fini = &btc_dpm_fini, |
.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 = &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, |
}, |
}; |
static struct radeon_asic_ring cayman_gfx_ring = { |
.ib_execute = &cayman_ring_ib_execute, |
.ib_parse = &evergreen_ib_parse, |
.emit_fence = &cayman_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
.cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &cayman_gfx_is_lockup, |
.vm_flush = &cayman_vm_flush, |
.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 = { |
.ib_execute = &cayman_dma_ring_ib_execute, |
.ib_parse = &evergreen_dma_ib_parse, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
.cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &cayman_dma_is_lockup, |
.vm_flush = &cayman_dma_vm_flush, |
.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 = { |
.ib_execute = &uvd_v1_0_ib_execute, |
.emit_fence = &uvd_v2_2_fence_emit, |
.emit_semaphore = &uvd_v3_1_semaphore_emit, |
.cs_parse = &radeon_uvd_cs_parse, |
.ring_test = &uvd_v1_0_ring_test, |
.ib_test = &uvd_v1_0_ib_test, |
.is_lockup = &radeon_ring_test_lockup, |
.get_rptr = &uvd_v1_0_get_rptr, |
.get_wptr = &uvd_v1_0_get_wptr, |
.set_wptr = &uvd_v1_0_set_wptr, |
}; |
static struct radeon_asic cayman_asic = { |
.init = &cayman_init, |
// .fini = &cayman_fini, |
1491,7 → 1599,7 |
// .resume = &cayman_resume, |
.asic_reset = &cayman_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &evergreen_mc_wait_for_idle, |
.get_xclk = &rv770_get_xclk, |
1503,75 → 1611,19 |
.vm = { |
.init = &cayman_vm_init, |
.fini = &cayman_vm_fini, |
.pt_ring_index = R600_RING_TYPE_DMA_INDEX, |
.set_page = &cayman_vm_set_page, |
.copy_pages = &cayman_dma_vm_copy_pages, |
.write_pages = &cayman_dma_vm_write_pages, |
.set_pages = &cayman_dma_vm_set_pages, |
.pad_ib = &cayman_dma_vm_pad_ib, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &cayman_ring_ib_execute, |
// .ib_parse = &evergreen_ib_parse, |
.emit_fence = &cayman_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &cayman_gfx_is_lockup, |
.vm_flush = &cayman_vm_flush, |
[RADEON_RING_TYPE_GFX_INDEX] = &cayman_gfx_ring, |
[CAYMAN_RING_TYPE_CP1_INDEX] = &cayman_gfx_ring, |
[CAYMAN_RING_TYPE_CP2_INDEX] = &cayman_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &cayman_dma_ring, |
[CAYMAN_RING_TYPE_DMA1_INDEX] = &cayman_dma_ring, |
[R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, |
}, |
[CAYMAN_RING_TYPE_CP1_INDEX] = { |
.ib_execute = &cayman_ring_ib_execute, |
// .ib_parse = &evergreen_ib_parse, |
.emit_fence = &cayman_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &cayman_gfx_is_lockup, |
.vm_flush = &cayman_vm_flush, |
}, |
[CAYMAN_RING_TYPE_CP2_INDEX] = { |
.ib_execute = &cayman_ring_ib_execute, |
// .ib_parse = &evergreen_ib_parse, |
.emit_fence = &cayman_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &cayman_gfx_is_lockup, |
.vm_flush = &cayman_vm_flush, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &cayman_dma_ring_ib_execute, |
// .ib_parse = &evergreen_dma_ib_parse, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &cayman_dma_is_lockup, |
.vm_flush = &cayman_dma_vm_flush, |
}, |
[CAYMAN_RING_TYPE_DMA1_INDEX] = { |
.ib_execute = &cayman_dma_ring_ib_execute, |
// .ib_parse = &evergreen_dma_ib_parse, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &cayman_dma_is_lockup, |
.vm_flush = &cayman_dma_vm_flush, |
}, |
[R600_RING_TYPE_UVD_INDEX] = { |
// .ib_execute = &r600_uvd_ib_execute, |
// .emit_fence = &r600_uvd_fence_emit, |
// .emit_semaphore = &cayman_uvd_semaphore_emit, |
// .cs_parse = &radeon_uvd_cs_parse, |
// .ring_test = &r600_uvd_ring_test, |
// .ib_test = &r600_uvd_ib_test, |
// .is_lockup = &radeon_ring_test_lockup, |
} |
}, |
.irq = { |
.set = &evergreen_irq_set, |
.process = &evergreen_irq_process, |
1580,11 → 1632,13 |
.bandwidth_update = &evergreen_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, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &evergreen_hdmi_enable, |
.hdmi_setmode = &evergreen_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_blit, |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &evergreen_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
1596,30 → 1650,48 |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
// .init = &evergreen_hpd_init, |
// .fini = &evergreen_hpd_fini, |
// .sense = &evergreen_hpd_sense, |
// .set_polarity = &evergreen_hpd_set_polarity, |
.init = &evergreen_hpd_init, |
.fini = &evergreen_hpd_fini, |
.sense = &evergreen_hpd_sense, |
.set_polarity = &evergreen_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &evergreen_pm_misc, |
// .prepare = &evergreen_pm_prepare, |
// .finish = &evergreen_pm_finish, |
// .init_profile = &btc_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
.misc = &evergreen_pm_misc, |
.prepare = &evergreen_pm_prepare, |
.finish = &evergreen_pm_finish, |
.init_profile = &btc_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &r600_get_pcie_lanes, |
.set_pcie_lanes = &r600_set_pcie_lanes, |
.set_clock_gating = NULL, |
.set_uvd_clocks = &evergreen_set_uvd_clocks, |
.get_temperature = &evergreen_get_temp, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &ni_dpm_post_set_power_state, |
.display_configuration_changed = &cypress_dpm_display_configuration_changed, |
.fini = &ni_dpm_fini, |
.get_sclk = &ni_dpm_get_sclk, |
.get_mclk = &ni_dpm_get_mclk, |
.print_power_state = &ni_dpm_print_power_state, |
.debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level, |
.force_performance_level = &ni_dpm_force_performance_level, |
.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, |
}, |
}; |
1630,7 → 1702,7 |
// .resume = &cayman_resume, |
.asic_reset = &cayman_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &evergreen_mc_wait_for_idle, |
.get_xclk = &r600_get_xclk, |
1642,75 → 1714,19 |
.vm = { |
.init = &cayman_vm_init, |
.fini = &cayman_vm_fini, |
.pt_ring_index = R600_RING_TYPE_DMA_INDEX, |
.set_page = &cayman_vm_set_page, |
.copy_pages = &cayman_dma_vm_copy_pages, |
.write_pages = &cayman_dma_vm_write_pages, |
.set_pages = &cayman_dma_vm_set_pages, |
.pad_ib = &cayman_dma_vm_pad_ib, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &cayman_ring_ib_execute, |
// .ib_parse = &evergreen_ib_parse, |
.emit_fence = &cayman_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &cayman_gfx_is_lockup, |
.vm_flush = &cayman_vm_flush, |
[RADEON_RING_TYPE_GFX_INDEX] = &cayman_gfx_ring, |
[CAYMAN_RING_TYPE_CP1_INDEX] = &cayman_gfx_ring, |
[CAYMAN_RING_TYPE_CP2_INDEX] = &cayman_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &cayman_dma_ring, |
[CAYMAN_RING_TYPE_DMA1_INDEX] = &cayman_dma_ring, |
[R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, |
}, |
[CAYMAN_RING_TYPE_CP1_INDEX] = { |
.ib_execute = &cayman_ring_ib_execute, |
// .ib_parse = &evergreen_ib_parse, |
.emit_fence = &cayman_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &cayman_gfx_is_lockup, |
.vm_flush = &cayman_vm_flush, |
}, |
[CAYMAN_RING_TYPE_CP2_INDEX] = { |
.ib_execute = &cayman_ring_ib_execute, |
// .ib_parse = &evergreen_ib_parse, |
.emit_fence = &cayman_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
// .cs_parse = &evergreen_cs_parse, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &cayman_gfx_is_lockup, |
.vm_flush = &cayman_vm_flush, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &cayman_dma_ring_ib_execute, |
// .ib_parse = &evergreen_dma_ib_parse, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &cayman_dma_is_lockup, |
.vm_flush = &cayman_dma_vm_flush, |
}, |
[CAYMAN_RING_TYPE_DMA1_INDEX] = { |
.ib_execute = &cayman_dma_ring_ib_execute, |
// .ib_parse = &evergreen_dma_ib_parse, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
// .cs_parse = &evergreen_dma_cs_parse, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &cayman_dma_is_lockup, |
.vm_flush = &cayman_dma_vm_flush, |
}, |
[R600_RING_TYPE_UVD_INDEX] = { |
// .ib_execute = &r600_uvd_ib_execute, |
// .emit_fence = &r600_uvd_fence_emit, |
// .emit_semaphore = &cayman_uvd_semaphore_emit, |
// .cs_parse = &radeon_uvd_cs_parse, |
// .ring_test = &r600_uvd_ring_test, |
// .ib_test = &r600_uvd_ib_test, |
// .is_lockup = &radeon_ring_test_lockup, |
} |
}, |
.irq = { |
.set = &evergreen_irq_set, |
.process = &evergreen_irq_process, |
1719,11 → 1735,13 |
.bandwidth_update = &dce6_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, |
.set_backlight_level = &atombios_set_backlight_level, |
.get_backlight_level = &atombios_get_backlight_level, |
.hdmi_enable = &evergreen_hdmi_enable, |
.hdmi_setmode = &evergreen_hdmi_setmode, |
}, |
.copy = { |
.blit = &r600_copy_blit, |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &evergreen_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
1735,19 → 1753,19 |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
// .init = &evergreen_hpd_init, |
// .fini = &evergreen_hpd_fini, |
// .sense = &evergreen_hpd_sense, |
// .set_polarity = &evergreen_hpd_set_polarity, |
.init = &evergreen_hpd_init, |
.fini = &evergreen_hpd_fini, |
.sense = &evergreen_hpd_sense, |
.set_polarity = &evergreen_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &evergreen_pm_misc, |
// .prepare = &evergreen_pm_prepare, |
// .finish = &evergreen_pm_finish, |
// .init_profile = &sumo_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
.misc = &evergreen_pm_misc, |
.prepare = &evergreen_pm_prepare, |
.finish = &evergreen_pm_finish, |
.init_profile = &sumo_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = NULL, |
.set_memory_clock = NULL, |
.get_pcie_lanes = NULL, |
1754,14 → 1772,62 |
.set_pcie_lanes = NULL, |
.set_clock_gating = NULL, |
.set_uvd_clocks = &sumo_set_uvd_clocks, |
.get_temperature = &tn_get_temp, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &trinity_dpm_post_set_power_state, |
.display_configuration_changed = &trinity_dpm_display_configuration_changed, |
.fini = &trinity_dpm_fini, |
.get_sclk = &trinity_dpm_get_sclk, |
.get_mclk = &trinity_dpm_get_mclk, |
.print_power_state = &trinity_dpm_print_power_state, |
.debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level, |
.force_performance_level = &trinity_dpm_force_performance_level, |
.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, |
}, |
}; |
static struct radeon_asic_ring si_gfx_ring = { |
.ib_execute = &si_ring_ib_execute, |
.ib_parse = &si_ib_parse, |
.emit_fence = &si_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &si_gfx_is_lockup, |
.vm_flush = &si_vm_flush, |
.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 = { |
.ib_execute = &cayman_dma_ring_ib_execute, |
.ib_parse = &evergreen_dma_ib_parse, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &si_dma_is_lockup, |
.vm_flush = &si_dma_vm_flush, |
.get_rptr = &cayman_dma_get_rptr, |
.get_wptr = &cayman_dma_get_wptr, |
.set_wptr = &cayman_dma_set_wptr, |
}; |
static struct radeon_asic si_asic = { |
.init = &si_init, |
// .fini = &si_fini, |
1769,7 → 1835,7 |
// .resume = &si_resume, |
.asic_reset = &si_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
// .ioctl_wait_idle = r600_ioctl_wait_idle, |
.mmio_hdp_flush = r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &evergreen_mc_wait_for_idle, |
.get_xclk = &si_get_xclk, |
1781,92 → 1847,201 |
.vm = { |
.init = &si_vm_init, |
.fini = &si_vm_fini, |
.pt_ring_index = R600_RING_TYPE_DMA_INDEX, |
.set_page = &si_vm_set_page, |
.copy_pages = &si_dma_vm_copy_pages, |
.write_pages = &si_dma_vm_write_pages, |
.set_pages = &si_dma_vm_set_pages, |
.pad_ib = &cayman_dma_vm_pad_ib, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = { |
.ib_execute = &si_ring_ib_execute, |
// .ib_parse = &si_ib_parse, |
.emit_fence = &si_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &si_gfx_is_lockup, |
.vm_flush = &si_vm_flush, |
[RADEON_RING_TYPE_GFX_INDEX] = &si_gfx_ring, |
[CAYMAN_RING_TYPE_CP1_INDEX] = &si_gfx_ring, |
[CAYMAN_RING_TYPE_CP2_INDEX] = &si_gfx_ring, |
[R600_RING_TYPE_DMA_INDEX] = &si_dma_ring, |
[CAYMAN_RING_TYPE_DMA1_INDEX] = &si_dma_ring, |
[R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, |
}, |
[CAYMAN_RING_TYPE_CP1_INDEX] = { |
.ib_execute = &si_ring_ib_execute, |
// .ib_parse = &si_ib_parse, |
.emit_fence = &si_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &si_gfx_is_lockup, |
.vm_flush = &si_vm_flush, |
.irq = { |
.set = &si_irq_set, |
.process = &si_irq_process, |
}, |
[CAYMAN_RING_TYPE_CP2_INDEX] = { |
.ib_execute = &si_ring_ib_execute, |
// .ib_parse = &si_ib_parse, |
.emit_fence = &si_fence_ring_emit, |
.emit_semaphore = &r600_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &r600_ring_test, |
.ib_test = &r600_ib_test, |
.is_lockup = &si_gfx_is_lockup, |
.vm_flush = &si_vm_flush, |
.display = { |
.bandwidth_update = &dce6_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, |
}, |
[R600_RING_TYPE_DMA_INDEX] = { |
.ib_execute = &cayman_dma_ring_ib_execute, |
// .ib_parse = &evergreen_dma_ib_parse, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &si_dma_is_lockup, |
.vm_flush = &si_dma_vm_flush, |
.copy = { |
.blit = &r600_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &si_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
.copy = &si_copy_dma, |
.copy_ring_index = R600_RING_TYPE_DMA_INDEX, |
}, |
[CAYMAN_RING_TYPE_DMA1_INDEX] = { |
.ib_execute = &cayman_dma_ring_ib_execute, |
// .ib_parse = &evergreen_dma_ib_parse, |
.emit_fence = &evergreen_dma_fence_ring_emit, |
.emit_semaphore = &r600_dma_semaphore_ring_emit, |
.surface = { |
.set_reg = r600_set_surface_reg, |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
.init = &evergreen_hpd_init, |
.fini = &evergreen_hpd_fini, |
.sense = &evergreen_hpd_sense, |
.set_polarity = &evergreen_hpd_set_polarity, |
}, |
.pm = { |
.misc = &evergreen_pm_misc, |
.prepare = &evergreen_pm_prepare, |
.finish = &evergreen_pm_finish, |
.init_profile = &sumo_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = &r600_get_pcie_lanes, |
.set_pcie_lanes = &r600_set_pcie_lanes, |
.set_clock_gating = NULL, |
.set_uvd_clocks = &si_set_uvd_clocks, |
.get_temperature = &si_get_temp, |
}, |
.dpm = { |
.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, |
.post_set_power_state = &si_dpm_post_set_power_state, |
.display_configuration_changed = &si_dpm_display_configuration_changed, |
.fini = &si_dpm_fini, |
.get_sclk = &ni_dpm_get_sclk, |
.get_mclk = &ni_dpm_get_mclk, |
.print_power_state = &ni_dpm_print_power_state, |
.debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level, |
.force_performance_level = &si_dpm_force_performance_level, |
.vblank_too_short = &ni_dpm_vblank_too_short, |
}, |
.pflip = { |
// .pre_page_flip = &evergreen_pre_page_flip, |
// .page_flip = &evergreen_page_flip, |
}, |
}; |
static struct radeon_asic_ring ci_gfx_ring = { |
.ib_execute = &cik_ring_ib_execute, |
.ib_parse = &cik_ib_parse, |
.emit_fence = &cik_fence_gfx_ring_emit, |
.emit_semaphore = &cik_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &r600_dma_ring_test, |
.ib_test = &r600_dma_ib_test, |
.is_lockup = &si_dma_is_lockup, |
.vm_flush = &si_dma_vm_flush, |
.ring_test = &cik_ring_test, |
.ib_test = &cik_ib_test, |
.is_lockup = &cik_gfx_is_lockup, |
.vm_flush = &cik_vm_flush, |
.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 = { |
.ib_execute = &cik_ring_ib_execute, |
.ib_parse = &cik_ib_parse, |
.emit_fence = &cik_fence_compute_ring_emit, |
.emit_semaphore = &cik_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &cik_ring_test, |
.ib_test = &cik_ib_test, |
.is_lockup = &cik_gfx_is_lockup, |
.vm_flush = &cik_vm_flush, |
.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 = { |
.ib_execute = &cik_sdma_ring_ib_execute, |
.ib_parse = &cik_ib_parse, |
.emit_fence = &cik_sdma_fence_ring_emit, |
.emit_semaphore = &cik_sdma_semaphore_ring_emit, |
.cs_parse = NULL, |
.ring_test = &cik_sdma_ring_test, |
.ib_test = &cik_sdma_ib_test, |
.is_lockup = &cik_sdma_is_lockup, |
.vm_flush = &cik_dma_vm_flush, |
.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 = { |
.init = &cik_init, |
// .fini = &si_fini, |
// .suspend = &si_suspend, |
// .resume = &si_resume, |
.asic_reset = &cik_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
.mmio_hdp_flush = &r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &evergreen_mc_wait_for_idle, |
.get_xclk = &cik_get_xclk, |
.get_gpu_clock_counter = &cik_get_gpu_clock_counter, |
.gart = { |
.tlb_flush = &cik_pcie_gart_tlb_flush, |
.set_page = &rs600_gart_set_page, |
}, |
[R600_RING_TYPE_UVD_INDEX] = { |
// .ib_execute = &r600_uvd_ib_execute, |
// .emit_fence = &r600_uvd_fence_emit, |
// .emit_semaphore = &cayman_uvd_semaphore_emit, |
// .cs_parse = &radeon_uvd_cs_parse, |
// .ring_test = &r600_uvd_ring_test, |
// .ib_test = &r600_uvd_ib_test, |
// .is_lockup = &radeon_ring_test_lockup, |
} |
.vm = { |
.init = &cik_vm_init, |
.fini = &cik_vm_fini, |
.copy_pages = &cik_sdma_vm_copy_pages, |
.write_pages = &cik_sdma_vm_write_pages, |
.set_pages = &cik_sdma_vm_set_pages, |
.pad_ib = &cik_sdma_vm_pad_ib, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = &ci_gfx_ring, |
[CAYMAN_RING_TYPE_CP1_INDEX] = &ci_cp_ring, |
[CAYMAN_RING_TYPE_CP2_INDEX] = &ci_cp_ring, |
[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 = &si_irq_set, |
.process = &si_irq_process, |
.set = &cik_irq_set, |
.process = &cik_irq_process, |
}, |
.display = { |
.bandwidth_update = &dce6_bandwidth_update, |
.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, |
.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 = &si_copy_dma, |
.dma = &cik_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
.copy = &si_copy_dma, |
.copy = &cik_copy_dma, |
.copy_ring_index = R600_RING_TYPE_DMA_INDEX, |
}, |
.surface = { |
1880,27 → 2055,154 |
.set_polarity = &evergreen_hpd_set_polarity, |
}, |
.pm = { |
// .misc = &evergreen_pm_misc, |
// .prepare = &evergreen_pm_prepare, |
// .finish = &evergreen_pm_finish, |
// .init_profile = &sumo_pm_init_profile, |
// .get_dynpm_state = &r600_pm_get_dynpm_state, |
// .get_engine_clock = &radeon_atom_get_engine_clock, |
// .set_engine_clock = &radeon_atom_set_engine_clock, |
// .get_memory_clock = &radeon_atom_get_memory_clock, |
// .set_memory_clock = &radeon_atom_set_memory_clock, |
.misc = &evergreen_pm_misc, |
.prepare = &evergreen_pm_prepare, |
.finish = &evergreen_pm_finish, |
.init_profile = &sumo_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = NULL, |
.set_pcie_lanes = NULL, |
.set_clock_gating = NULL, |
// .set_uvd_clocks = &si_set_uvd_clocks, |
.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, |
.post_set_power_state = &ci_dpm_post_set_power_state, |
.display_configuration_changed = &ci_dpm_display_configuration_changed, |
.fini = &ci_dpm_fini, |
.get_sclk = &ci_dpm_get_sclk, |
.get_mclk = &ci_dpm_get_mclk, |
.print_power_state = &ci_dpm_print_power_state, |
.debugfs_print_current_performance_level = &ci_dpm_debugfs_print_current_performance_level, |
.force_performance_level = &ci_dpm_force_performance_level, |
.vblank_too_short = &ci_dpm_vblank_too_short, |
.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, |
}, |
}; |
static struct radeon_asic kv_asic = { |
.init = &cik_init, |
// .fini = &si_fini, |
// .suspend = &si_suspend, |
// .resume = &si_resume, |
.asic_reset = &cik_asic_reset, |
// .vga_set_state = &r600_vga_set_state, |
.mmio_hdp_flush = &r600_mmio_hdp_flush, |
.gui_idle = &r600_gui_idle, |
.mc_wait_for_idle = &evergreen_mc_wait_for_idle, |
.get_xclk = &cik_get_xclk, |
.get_gpu_clock_counter = &cik_get_gpu_clock_counter, |
.gart = { |
.tlb_flush = &cik_pcie_gart_tlb_flush, |
.set_page = &rs600_gart_set_page, |
}, |
.vm = { |
.init = &cik_vm_init, |
.fini = &cik_vm_fini, |
.copy_pages = &cik_sdma_vm_copy_pages, |
.write_pages = &cik_sdma_vm_write_pages, |
.set_pages = &cik_sdma_vm_set_pages, |
.pad_ib = &cik_sdma_vm_pad_ib, |
}, |
.ring = { |
[RADEON_RING_TYPE_GFX_INDEX] = &ci_gfx_ring, |
[CAYMAN_RING_TYPE_CP1_INDEX] = &ci_cp_ring, |
[CAYMAN_RING_TYPE_CP2_INDEX] = &ci_cp_ring, |
[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, |
.process = &cik_irq_process, |
}, |
.display = { |
.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 = &cik_copy_cpdma, |
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, |
.dma = &cik_copy_dma, |
.dma_ring_index = R600_RING_TYPE_DMA_INDEX, |
.copy = &cik_copy_dma, |
.copy_ring_index = R600_RING_TYPE_DMA_INDEX, |
}, |
.surface = { |
.set_reg = r600_set_surface_reg, |
.clear_reg = r600_clear_surface_reg, |
}, |
.hpd = { |
.init = &evergreen_hpd_init, |
.fini = &evergreen_hpd_fini, |
.sense = &evergreen_hpd_sense, |
.set_polarity = &evergreen_hpd_set_polarity, |
}, |
.pm = { |
.misc = &evergreen_pm_misc, |
.prepare = &evergreen_pm_prepare, |
.finish = &evergreen_pm_finish, |
.init_profile = &sumo_pm_init_profile, |
.get_dynpm_state = &r600_pm_get_dynpm_state, |
.get_engine_clock = &radeon_atom_get_engine_clock, |
.set_engine_clock = &radeon_atom_set_engine_clock, |
.get_memory_clock = &radeon_atom_get_memory_clock, |
.set_memory_clock = &radeon_atom_set_memory_clock, |
.get_pcie_lanes = NULL, |
.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, |
.post_set_power_state = &kv_dpm_post_set_power_state, |
.display_configuration_changed = &kv_dpm_display_configuration_changed, |
.fini = &kv_dpm_fini, |
.get_sclk = &kv_dpm_get_sclk, |
.get_mclk = &kv_dpm_get_mclk, |
.print_power_state = &kv_dpm_print_power_state, |
.debugfs_print_current_performance_level = &kv_dpm_debugfs_print_current_performance_level, |
.force_performance_level = &kv_dpm_force_performance_level, |
.powergate_uvd = &kv_dpm_powergate_uvd, |
.enable_bapm = &kv_dpm_enable_bapm, |
}, |
.pflip = { |
// .pre_page_flip = &evergreen_pre_page_flip, |
// .page_flip = &evergreen_page_flip, |
}, |
}; |
/** |
* radeon_asic_init - register asic specific callbacks |
* |
1981,15 → 2283,14 |
rdev->asic = &r520_asic; |
break; |
case CHIP_R600: |
rdev->asic = &r600_asic; |
break; |
case CHIP_RV610: |
case CHIP_RV630: |
case CHIP_RV620: |
case CHIP_RV635: |
case CHIP_RV670: |
rdev->asic = &r600_asic; |
if (rdev->family == CHIP_R600) |
rdev->has_uvd = false; |
else |
rdev->asic = &rv6xx_asic; |
rdev->has_uvd = true; |
break; |
case CHIP_RS780: |
2063,8 → 2364,212 |
rdev->has_uvd = false; |
else |
rdev->has_uvd = true; |
switch (rdev->family) { |
case CHIP_TAHITI: |
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_MGCG | |
RADEON_CG_SUPPORT_SDMA_MGCG | |
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_PITCAIRN: |
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_GFX_RLC_LS | |
RADEON_CG_SUPPORT_MC_LS | |
RADEON_CG_SUPPORT_MC_MGCG | |
RADEON_CG_SUPPORT_SDMA_MGCG | |
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_VERDE: |
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_GFX_RLC_LS | |
RADEON_CG_SUPPORT_MC_LS | |
RADEON_CG_SUPPORT_MC_MGCG | |
RADEON_CG_SUPPORT_SDMA_MGCG | |
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 | |
/*RADEON_PG_SUPPORT_GFX_PG | */ |
RADEON_PG_SUPPORT_SDMA; |
break; |
case CHIP_OLAND: |
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_GFX_RLC_LS | |
RADEON_CG_SUPPORT_MC_LS | |
RADEON_CG_SUPPORT_MC_MGCG | |
RADEON_CG_SUPPORT_SDMA_MGCG | |
RADEON_CG_SUPPORT_BIF_LS | |
RADEON_CG_SUPPORT_UVD_MGCG | |
RADEON_CG_SUPPORT_HDP_LS | |
RADEON_CG_SUPPORT_HDP_MGCG; |
rdev->pg_flags = 0; |
break; |
case CHIP_HAINAN: |
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_GFX_RLC_LS | |
RADEON_CG_SUPPORT_MC_LS | |
RADEON_CG_SUPPORT_MC_MGCG | |
RADEON_CG_SUPPORT_SDMA_MGCG | |
RADEON_CG_SUPPORT_BIF_LS | |
RADEON_CG_SUPPORT_HDP_LS | |
RADEON_CG_SUPPORT_HDP_MGCG; |
rdev->pg_flags = 0; |
break; |
default: |
rdev->cg_flags = 0; |
rdev->pg_flags = 0; |
break; |
} |
break; |
case CHIP_BONAIRE: |
case CHIP_HAWAII: |
rdev->asic = &ci_asic; |
rdev->num_crtc = 6; |
rdev->has_uvd = true; |
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) { |
rdev->num_crtc = 4; |
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_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; |
/*RADEON_PG_SUPPORT_GFX_PG | |
RADEON_PG_SUPPORT_GFX_SMG | |
RADEON_PG_SUPPORT_GFX_DMG | |
RADEON_PG_SUPPORT_UVD | |
RADEON_PG_SUPPORT_VCE | |
RADEON_PG_SUPPORT_CP | |
RADEON_PG_SUPPORT_GDS | |
RADEON_PG_SUPPORT_RLC_SMU_HS | |
RADEON_PG_SUPPORT_ACP | |
RADEON_PG_SUPPORT_SAMU;*/ |
} else { |
rdev->num_crtc = 2; |
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_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; |
/*RADEON_PG_SUPPORT_GFX_PG | |
RADEON_PG_SUPPORT_GFX_SMG | |
RADEON_PG_SUPPORT_UVD | |
RADEON_PG_SUPPORT_VCE | |
RADEON_PG_SUPPORT_CP | |
RADEON_PG_SUPPORT_GDS | |
RADEON_PG_SUPPORT_RLC_SMU_HS | |
RADEON_PG_SUPPORT_SAMU;*/ |
} |
rdev->has_uvd = true; |
break; |
default: |
/* FIXME: not supported yet */ |
return -EINVAL; |
} |
/drivers/video/drm/radeon/radeon_asic.h |
---|
47,7 → 47,6 |
void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level); |
u8 radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder); |
/* |
* r100,rv100,rs100,rv200,rs200 |
*/ |
68,13 → 67,14 |
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, uint32_t flags); |
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); |
136,12 → 136,20 |
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); |
void r100_ring_hdp_flush(struct radeon_device *rdev, |
struct radeon_ring *ring); |
/* |
* r200,rv250,rs300,rv280 |
*/ |
165,7 → 173,8 |
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, uint32_t flags); |
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); |
200,7 → 209,8 |
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 flags); |
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); |
223,7 → 233,8 |
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 flags); |
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); |
235,9 → 246,9 |
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); |
307,13 → 318,13 |
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); |
330,8 → 341,7 |
void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); |
int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); |
int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); |
int r600_uvd_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); |
int r600_copy_blit(struct radeon_device *rdev, |
int r600_copy_cpdma(struct radeon_device *rdev, |
uint64_t src_offset, uint64_t dst_offset, |
unsigned num_gpu_pages, struct radeon_fence **fence); |
int r600_copy_dma(struct radeon_device *rdev, |
342,7 → 352,7 |
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); |
void r600_hpd_set_polarity(struct radeon_device *rdev, |
enum radeon_hpd_id hpd); |
extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); |
extern void r600_mmio_hdp_flush(struct radeon_device *rdev); |
extern bool r600_gui_idle(struct radeon_device *rdev); |
extern void r600_pm_misc(struct radeon_device *rdev); |
extern void r600_pm_init_profile(struct radeon_device *rdev); |
362,9 → 372,13 |
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_blit_init(struct radeon_device *rdev); |
void r600_blit_fini(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); |
376,39 → 390,65 |
void r600_rlc_stop(struct radeon_device *rdev); |
/* r600 audio */ |
int r600_audio_init(struct radeon_device *rdev); |
struct r600_audio r600_audio_status(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); |
void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); |
/* r600 blit */ |
int r600_blit_prepare_copy(struct radeon_device *rdev, unsigned num_gpu_pages, |
struct radeon_fence **fence, struct radeon_sa_bo **vb, |
struct radeon_semaphore **sem); |
void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence **fence, |
struct radeon_sa_bo *vb, struct radeon_semaphore *sem); |
void r600_kms_blit_copy(struct radeon_device *rdev, |
u64 src_gpu_addr, u64 dst_gpu_addr, |
unsigned num_gpu_pages, |
struct radeon_sa_bo *vb); |
int r600_mc_wait_for_idle(struct radeon_device *rdev); |
u32 r600_get_xclk(struct radeon_device *rdev); |
uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev); |
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); |
uint32_t r600_dma_get_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring); |
void r600_dma_set_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring); |
/* rv6xx dpm */ |
int rv6xx_dpm_init(struct radeon_device *rdev); |
int rv6xx_dpm_enable(struct radeon_device *rdev); |
void rv6xx_dpm_disable(struct radeon_device *rdev); |
int rv6xx_dpm_set_power_state(struct radeon_device *rdev); |
void rv6xx_setup_asic(struct radeon_device *rdev); |
void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev); |
void rv6xx_dpm_fini(struct radeon_device *rdev); |
u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low); |
u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low); |
void rv6xx_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *ps); |
void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int rv6xx_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
/* rs780 dpm */ |
int rs780_dpm_init(struct radeon_device *rdev); |
int rs780_dpm_enable(struct radeon_device *rdev); |
void rs780_dpm_disable(struct radeon_device *rdev); |
int rs780_dpm_set_power_state(struct radeon_device *rdev); |
void rs780_dpm_setup_asic(struct radeon_device *rdev); |
void rs780_dpm_display_configuration_changed(struct radeon_device *rdev); |
void rs780_dpm_fini(struct radeon_device *rdev); |
u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low); |
u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low); |
void rs780_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *ps); |
void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int rs780_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
/* uvd */ |
int r600_uvd_init(struct radeon_device *rdev); |
int r600_uvd_rbc_start(struct radeon_device *rdev); |
void r600_uvd_rbc_stop(struct radeon_device *rdev); |
int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); |
void r600_uvd_fence_emit(struct radeon_device *rdev, |
struct radeon_fence *fence); |
void r600_uvd_semaphore_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait); |
void r600_uvd_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); |
/* |
* rv770,rv730,rv710,rv740 |
*/ |
417,7 → 457,8 |
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); |
426,8 → 467,28 |
unsigned num_gpu_pages, |
struct radeon_fence **fence); |
u32 rv770_get_xclk(struct radeon_device *rdev); |
int rv770_uvd_resume(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); |
void rv770_dpm_display_configuration_changed(struct radeon_device *rdev); |
void rv770_dpm_fini(struct radeon_device *rdev); |
u32 rv770_dpm_get_sclk(struct radeon_device *rdev, bool low); |
u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low); |
void rv770_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *ps); |
void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int rv770_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
bool rv770_dpm_vblank_too_short(struct radeon_device *rdev); |
/* |
* evergreen |
465,12 → 526,11 |
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_blit_init(struct radeon_device *rdev); |
int evergreen_mc_wait_for_idle(struct radeon_device *rdev); |
void evergreen_dma_fence_ring_emit(struct radeon_device *rdev, |
struct radeon_fence *fence); |
482,6 → 542,48 |
struct radeon_fence **fence); |
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable); |
void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); |
int evergreen_get_temp(struct radeon_device *rdev); |
int sumo_get_temp(struct radeon_device *rdev); |
int tn_get_temp(struct radeon_device *rdev); |
int cypress_dpm_init(struct radeon_device *rdev); |
void cypress_dpm_setup_asic(struct radeon_device *rdev); |
int cypress_dpm_enable(struct radeon_device *rdev); |
void cypress_dpm_disable(struct radeon_device *rdev); |
int cypress_dpm_set_power_state(struct radeon_device *rdev); |
void cypress_dpm_display_configuration_changed(struct radeon_device *rdev); |
void cypress_dpm_fini(struct radeon_device *rdev); |
bool cypress_dpm_vblank_too_short(struct radeon_device *rdev); |
int btc_dpm_init(struct radeon_device *rdev); |
void btc_dpm_setup_asic(struct radeon_device *rdev); |
int btc_dpm_enable(struct radeon_device *rdev); |
void btc_dpm_disable(struct radeon_device *rdev); |
int btc_dpm_pre_set_power_state(struct radeon_device *rdev); |
int btc_dpm_set_power_state(struct radeon_device *rdev); |
void btc_dpm_post_set_power_state(struct radeon_device *rdev); |
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); |
void sumo_dpm_post_set_power_state(struct radeon_device *rdev); |
void sumo_dpm_setup_asic(struct radeon_device *rdev); |
void sumo_dpm_display_configuration_changed(struct radeon_device *rdev); |
void sumo_dpm_fini(struct radeon_device *rdev); |
u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low); |
u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low); |
void sumo_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *ps); |
void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int sumo_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
/* |
* cayman |
488,10 → 590,6 |
*/ |
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); |
503,11 → 601,6 |
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, |
514,10 → 607,79 |
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_copy_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, uint64_t src, |
unsigned count); |
void cayman_dma_vm_write_pages(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_set_pages(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_pad_ib(struct radeon_ib *ib); |
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); |
void ni_dpm_disable(struct radeon_device *rdev); |
int ni_dpm_pre_set_power_state(struct radeon_device *rdev); |
int ni_dpm_set_power_state(struct radeon_device *rdev); |
void ni_dpm_post_set_power_state(struct radeon_device *rdev); |
void ni_dpm_fini(struct radeon_device *rdev); |
u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low); |
u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low); |
void ni_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *ps); |
void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int ni_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
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); |
void trinity_dpm_post_set_power_state(struct radeon_device *rdev); |
void trinity_dpm_setup_asic(struct radeon_device *rdev); |
void trinity_dpm_display_configuration_changed(struct radeon_device *rdev); |
void trinity_dpm_fini(struct radeon_device *rdev); |
u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low); |
u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low); |
void trinity_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *ps); |
void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int trinity_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable); |
/* DCE6 - SI */ |
void dce6_bandwidth_update(struct radeon_device *rdev); |
int dce6_audio_init(struct radeon_device *rdev); |
void dce6_audio_fini(struct radeon_device *rdev); |
/* |
* si |
537,11 → 699,6 |
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, |
548,9 → 705,223 |
uint64_t src_offset, uint64_t dst_offset, |
unsigned num_gpu_pages, |
struct radeon_fence **fence); |
void si_dma_vm_copy_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, uint64_t src, |
unsigned count); |
void si_dma_vm_write_pages(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_set_pages(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); |
int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); |
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); |
void si_dpm_post_set_power_state(struct radeon_device *rdev); |
void si_dpm_fini(struct radeon_device *rdev); |
void si_dpm_display_configuration_changed(struct radeon_device *rdev); |
void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int si_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
/* DCE8 - CIK */ |
void dce8_bandwidth_update(struct radeon_device *rdev); |
/* |
* cik |
*/ |
uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev); |
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); |
bool cik_sdma_semaphore_ring_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait); |
void cik_sdma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); |
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); |
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); |
bool cik_semaphore_ring_emit(struct radeon_device *rdev, |
struct radeon_ring *cp, |
struct radeon_semaphore *semaphore, |
bool emit_wait); |
void cik_pcie_gart_tlb_flush(struct radeon_device *rdev); |
int cik_init(struct radeon_device *rdev); |
void cik_fini(struct radeon_device *rdev); |
int cik_suspend(struct radeon_device *rdev); |
int cik_resume(struct radeon_device *rdev); |
bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); |
int cik_asic_reset(struct radeon_device *rdev); |
void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); |
int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); |
int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); |
int cik_irq_set(struct radeon_device *rdev); |
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_sdma_vm_copy_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, uint64_t src, |
unsigned count); |
void cik_sdma_vm_write_pages(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_pages(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_pad_ib(struct radeon_ib *ib); |
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_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); |
void ci_dpm_post_set_power_state(struct radeon_device *rdev); |
void ci_dpm_setup_asic(struct radeon_device *rdev); |
void ci_dpm_display_configuration_changed(struct radeon_device *rdev); |
void ci_dpm_fini(struct radeon_device *rdev); |
u32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low); |
u32 ci_dpm_get_mclk(struct radeon_device *rdev, bool low); |
void ci_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *ps); |
void ci_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int ci_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
bool ci_dpm_vblank_too_short(struct radeon_device *rdev); |
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); |
void kv_dpm_post_set_power_state(struct radeon_device *rdev); |
void kv_dpm_setup_asic(struct radeon_device *rdev); |
void kv_dpm_display_configuration_changed(struct radeon_device *rdev); |
void kv_dpm_fini(struct radeon_device *rdev); |
u32 kv_dpm_get_sclk(struct radeon_device *rdev, bool low); |
u32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low); |
void kv_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *ps); |
void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m); |
int kv_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); |
void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable); |
/* uvd v1.0 */ |
uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev, |
struct radeon_ring *ring); |
uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring); |
void uvd_v1_0_set_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring); |
int uvd_v1_0_init(struct radeon_device *rdev); |
void uvd_v1_0_fini(struct radeon_device *rdev); |
int uvd_v1_0_start(struct radeon_device *rdev); |
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); |
bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait); |
void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); |
/* uvd v2.2 */ |
int uvd_v2_2_resume(struct radeon_device *rdev); |
void uvd_v2_2_fence_emit(struct radeon_device *rdev, |
struct radeon_fence *fence); |
/* uvd v3.1 */ |
bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev, |
struct radeon_ring *ring, |
struct radeon_semaphore *semaphore, |
bool emit_wait); |
/* 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 |
/drivers/video/drm/radeon/radeon_atombios.c |
---|
30,36 → 30,15 |
#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, |
uint32_t supported_device); |
/* local */ |
static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, |
u16 voltage_id, u16 *voltage); |
union atom_supported_devices { |
struct _ATOM_SUPPORTED_DEVICES_INFO info; |
struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2; |
167,8 → 146,8 |
num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / |
sizeof(ATOM_GPIO_I2C_ASSIGMENT); |
gpio = &i2c_info->asGPIO_Info[0]; |
for (i = 0; i < num_indices; i++) { |
gpio = &i2c_info->asGPIO_Info[i]; |
radeon_lookup_i2c_gpio_quirks(rdev, gpio, i); |
176,6 → 155,8 |
i2c = radeon_get_bus_rec_for_i2c_gpio(gpio); |
break; |
} |
gpio = (ATOM_GPIO_I2C_ASSIGMENT *) |
((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); |
} |
} |
199,9 → 180,8 |
num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / |
sizeof(ATOM_GPIO_I2C_ASSIGMENT); |
gpio = &i2c_info->asGPIO_Info[0]; |
for (i = 0; i < num_indices; i++) { |
gpio = &i2c_info->asGPIO_Info[i]; |
radeon_lookup_i2c_gpio_quirks(rdev, gpio, i); |
i2c = radeon_get_bus_rec_for_i2c_gpio(gpio); |
210,6 → 190,8 |
sprintf(stmp, "0x%x", i2c.i2c_id); |
rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp); |
} |
gpio = (ATOM_GPIO_I2C_ASSIGMENT *) |
((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); |
} |
} |
} |
234,8 → 216,8 |
num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / |
sizeof(ATOM_GPIO_PIN_ASSIGNMENT); |
pin = gpio_info->asGPIO_Pin; |
for (i = 0; i < num_indices; i++) { |
pin = &gpio_info->asGPIO_Pin[i]; |
if (id == pin->ucGPIO_ID) { |
gpio.id = pin->ucGPIO_ID; |
gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4; |
243,6 → 225,8 |
gpio.valid = true; |
break; |
} |
pin = (ATOM_GPIO_PIN_ASSIGNMENT *) |
((u8 *)pin + sizeof(ATOM_GPIO_PIN_ASSIGNMENT)); |
} |
} |
715,13 → 699,16 |
(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) |
(ctx->bios + data_offset + |
le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset)); |
u8 *num_dst_objs = (u8 *) |
((u8 *)router_src_dst_table + 1 + |
(router_src_dst_table->ucNumberOfSrc * 2)); |
u16 *dst_objs = (u16 *)(num_dst_objs + 1); |
int enum_id; |
router.router_id = router_obj_id; |
for (enum_id = 0; enum_id < router_src_dst_table->ucNumberOfDst; |
enum_id++) { |
for (enum_id = 0; enum_id < (*num_dst_objs); enum_id++) { |
if (le16_to_cpu(path->usConnObjectId) == |
le16_to_cpu(router_src_dst_table->usDstObjectID[enum_id])) |
le16_to_cpu(dst_objs[enum_id])) |
break; |
} |
1240,13 → 1227,22 |
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; |
} |
*dcpll = *p1pll; |
1269,6 → 1265,7 |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; |
}; |
bool radeon_atombios_sideport_present(struct radeon_device *rdev) |
1361,6 → 1358,7 |
int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info); |
uint16_t data_offset, size; |
struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info; |
struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *ss_assign; |
uint8_t frev, crev; |
int i, num_indices; |
1372,18 → 1370,21 |
num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / |
sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT); |
ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT*) |
((u8 *)&ss_info->asSS_Info[0]); |
for (i = 0; i < num_indices; i++) { |
if (ss_info->asSS_Info[i].ucSS_Id == id) { |
if (ss_assign->ucSS_Id == id) { |
ss->percentage = |
le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage); |
ss->type = ss_info->asSS_Info[i].ucSpreadSpectrumType; |
ss->step = ss_info->asSS_Info[i].ucSS_Step; |
ss->delay = ss_info->asSS_Info[i].ucSS_Delay; |
ss->range = ss_info->asSS_Info[i].ucSS_Range; |
ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div; |
le16_to_cpu(ss_assign->usSpreadSpectrumPercentage); |
ss->type = ss_assign->ucSpreadSpectrumType; |
ss->step = ss_assign->ucSS_Step; |
ss->delay = ss_assign->ucSS_Delay; |
ss->range = ss_assign->ucSS_Range; |
ss->refdiv = ss_assign->ucRecommendedRef_Div; |
return true; |
} |
ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT*) |
((u8 *)ss_assign + sizeof(struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT)); |
} |
} |
return false; |
1438,6 → 1439,22 |
break; |
} |
break; |
case 8: |
switch (id) { |
case ASIC_INTERNAL_SS_ON_TMDS: |
percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage); |
rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz); |
break; |
case ASIC_INTERNAL_SS_ON_HDMI: |
percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage); |
rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz); |
break; |
case ASIC_INTERNAL_SS_ON_LVDS: |
percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage); |
rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz); |
break; |
} |
break; |
default: |
DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); |
break; |
1455,6 → 1472,12 |
struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3; |
}; |
union asic_ss_assignment { |
struct _ATOM_ASIC_SS_ASSIGNMENT v1; |
struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2; |
struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3; |
}; |
bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, |
struct radeon_atom_ss *ss, |
int id, u32 clock) |
1463,9 → 1486,19 |
int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); |
uint16_t data_offset, size; |
union asic_ss_info *ss_info; |
union asic_ss_assignment *ss_assign; |
uint8_t frev, crev; |
int i, num_indices; |
if (id == ASIC_INTERNAL_MEMORY_SS) { |
if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT)) |
return false; |
} |
if (id == ASIC_INTERNAL_ENGINE_SS) { |
if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT)) |
return false; |
} |
memset(ss, 0, sizeof(struct radeon_atom_ss)); |
if (atom_parse_data_header(mode_info->atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
1478,45 → 1511,68 |
num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / |
sizeof(ATOM_ASIC_SS_ASSIGNMENT); |
ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]); |
for (i = 0; i < num_indices; i++) { |
if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) && |
(clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) { |
if ((ss_assign->v1.ucClockIndication == id) && |
(clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) { |
ss->percentage = |
le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage); |
ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode; |
ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz); |
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 *) |
((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT)); |
} |
break; |
case 2: |
num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / |
sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2); |
ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]); |
for (i = 0; i < num_indices; i++) { |
if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) && |
(clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) { |
if ((ss_assign->v2.ucClockIndication == id) && |
(clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) { |
ss->percentage = |
le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage); |
ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode; |
ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz); |
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))) |
ss->rate /= 100; |
return true; |
} |
ss_assign = (union asic_ss_assignment *) |
((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2)); |
} |
break; |
case 3: |
num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / |
sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3); |
ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]); |
for (i = 0; i < num_indices; i++) { |
if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) && |
(clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) { |
if ((ss_assign->v3.ucClockIndication == id) && |
(clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) { |
ss->percentage = |
le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage); |
ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode; |
ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz); |
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; |
if (rdev->flags & RADEON_IS_IGP) |
radeon_atombios_get_igp_ss_overrides(rdev, ss, id); |
return true; |
} |
ss_assign = (union asic_ss_assignment *) |
((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3)); |
} |
break; |
default: |
1651,7 → 1707,9 |
kfree(edid); |
} |
} |
record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD); |
record += fake_edid_record->ucFakeEDIDLength ? |
fake_edid_record->ucFakeEDIDLength + 2 : |
sizeof(ATOM_FAKE_EDID_PATCH_RECORD); |
break; |
case LCD_PANEL_RESOLUTION_RECORD_TYPE: |
panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; |
1749,7 → 1807,8 |
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 */ |
1792,7 → 1851,8 |
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; |
1903,7 → 1963,7 |
"adm1032", |
"adm1030", |
"max6649", |
"lm64", |
"lm63", /* lm64 */ |
"f75375", |
"asc7xxx", |
}; |
1914,7 → 1974,7 |
"adm1032", |
"adm1030", |
"max6649", |
"lm64", |
"lm63", /* lm64 */ |
"f75375", |
"RV6xx", |
"RV770", |
1927,6 → 1987,7 |
"Northern Islands", |
"Southern Islands", |
"lm96163", |
"Sea Islands", |
}; |
union power_info { |
1944,6 → 2005,7 |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
struct _ATOM_PPLIB_SI_CLOCK_INFO si; |
struct _ATOM_PPLIB_CI_CLOCK_INFO ci; |
}; |
union pplib_power_state { |
2209,6 → 2271,16 |
(controller->ucFanParameters & |
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); |
rdev->pm.int_thermal_type = THERMAL_TYPE_SI; |
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) { |
DRM_INFO("Internal thermal controller %s fan control\n", |
(controller->ucFanParameters & |
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); |
rdev->pm.int_thermal_type = THERMAL_TYPE_CI; |
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) { |
DRM_INFO("Internal thermal controller %s fan control\n", |
(controller->ucFanParameters & |
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); |
rdev->pm.int_thermal_type = THERMAL_TYPE_KV; |
} else if ((controller->ucType == |
ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || |
(controller->ucType == |
2241,8 → 2313,8 |
} |
} |
static void radeon_atombios_get_default_voltages(struct radeon_device *rdev, |
u16 *vddc, u16 *vddci) |
void radeon_atombios_get_default_voltages(struct radeon_device *rdev, |
u16 *vddc, u16 *vddci, u16 *mvdd) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); |
2252,6 → 2324,7 |
*vddc = 0; |
*vddci = 0; |
*mvdd = 0; |
if (atom_parse_data_header(mode_info->atom_context, index, NULL, |
&frev, &crev, &data_offset)) { |
2259,10 → 2332,12 |
(union firmware_info *)(mode_info->atom_context->bios + |
data_offset); |
*vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage); |
if ((frev == 2) && (crev >= 2)) |
if ((frev == 2) && (crev >= 2)) { |
*vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage); |
*mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage); |
} |
} |
} |
static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev, |
int state_index, int mode_index, |
2271,9 → 2346,9 |
int j; |
u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
u32 misc2 = le16_to_cpu(non_clock_info->usClassification); |
u16 vddc, vddci; |
u16 vddc, vddci, mvdd; |
radeon_atombios_get_default_voltages(rdev, &vddc, &vddci); |
radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); |
rdev->pm.power_state[state_index].misc = misc; |
rdev->pm.power_state[state_index].misc2 = misc2; |
2316,7 → 2391,13 |
rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage; |
rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci; |
} else { |
/* patch the table values with the default slck/mclk from firmware info */ |
u16 max_vddci = 0; |
if (ASIC_IS_DCE4(rdev)) |
radeon_atom_get_max_voltage(rdev, |
SET_VOLTAGE_TYPE_ASIC_VDDCI, |
&max_vddci); |
/* patch the table values with the default sclk/mclk from firmware info */ |
for (j = 0; j < mode_index; j++) { |
rdev->pm.power_state[state_index].clock_info[j].mclk = |
rdev->clock.default_mclk; |
2325,6 → 2406,9 |
if (vddc) |
rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = |
vddc; |
if (max_vddci) |
rdev->pm.power_state[state_index].clock_info[j].voltage.vddci = |
max_vddci; |
} |
} |
} |
2347,6 → 2431,15 |
sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; |
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; |
} |
} else if (rdev->family >= CHIP_BONAIRE) { |
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.power_state[state_index].clock_info[mode_index].mclk = mclk; |
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; |
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = |
VOLTAGE_NONE; |
} else if (rdev->family >= CHIP_TAHITI) { |
sclk = le16_to_cpu(clock_info->si.usEngineClockLow); |
sclk |= clock_info->si.ucEngineClockHigh << 16; |
2392,6 → 2485,10 |
case ATOM_VIRTUAL_VOLTAGE_ID1: |
case ATOM_VIRTUAL_VOLTAGE_ID2: |
case ATOM_VIRTUAL_VOLTAGE_ID3: |
case ATOM_VIRTUAL_VOLTAGE_ID4: |
case ATOM_VIRTUAL_VOLTAGE_ID5: |
case ATOM_VIRTUAL_VOLTAGE_ID6: |
case ATOM_VIRTUAL_VOLTAGE_ID7: |
if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, |
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage, |
&vddc) == 0) |
2667,6 → 2764,8 |
struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3; |
struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4; |
struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5; |
struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in; |
struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out; |
}; |
int radeon_atom_get_clock_dividers(struct radeon_device *rdev, |
2699,7 → 2798,8 |
break; |
case 2: |
case 3: |
/* r6xx, r7xx, evergreen, ni */ |
case 5: |
/* r6xx, r7xx, evergreen, ni, si */ |
if (rdev->family <= CHIP_RV770) { |
args.v2.ucAction = clock_type; |
args.v2.ulClock = cpu_to_le32(clock); /* 10 khz */ |
2726,12 → 2826,15 |
ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; |
dividers->enable_dithen = (args.v3.ucCntlFlag & |
ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; |
dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); |
dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); |
dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac); |
dividers->ref_div = args.v3.ucRefDiv; |
dividers->vco_mode = (args.v3.ucCntlFlag & |
ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0; |
} else { |
/* for SI we use ComputeMemoryClockParam for memory plls */ |
if (rdev->family >= CHIP_TAHITI) |
return -EINVAL; |
args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock); |
if (strobe_mode) |
args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN; |
2757,9 → 2860,25 |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
dividers->post_div = args.v4.ucPostDiv; |
dividers->post_divider = dividers->post_div = args.v4.ucPostDiv; |
dividers->real_clock = le32_to_cpu(args.v4.ulClock); |
break; |
case 6: |
/* CI */ |
/* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */ |
args.v6_in.ulClock.ulComputeClockFlag = clock_type; |
args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */ |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv); |
dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac); |
dividers->ref_div = args.v6_out.ucPllRefDiv; |
dividers->post_div = args.v6_out.ucPllPostDiv; |
dividers->flags = args.v6_out.ucPllCntlFlag; |
dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock); |
dividers->post_divider = args.v6_out.ulClock.ucPostDiv; |
break; |
default: |
return -EINVAL; |
} |
2766,6 → 2885,57 |
return 0; |
} |
int radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev, |
u32 clock, |
bool strobe_mode, |
struct atom_mpll_param *mpll_param) |
{ |
COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args; |
int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam); |
u8 frev, crev; |
memset(&args, 0, sizeof(args)); |
memset(mpll_param, 0, sizeof(struct atom_mpll_param)); |
if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) |
return -EINVAL; |
switch (frev) { |
case 2: |
switch (crev) { |
case 1: |
/* SI */ |
args.ulClock = cpu_to_le32(clock); /* 10 khz */ |
args.ucInputFlag = 0; |
if (strobe_mode) |
args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN; |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac); |
mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv); |
mpll_param->post_div = args.ucPostDiv; |
mpll_param->dll_speed = args.ucDllSpeed; |
mpll_param->bwcntl = args.ucBWCntl; |
mpll_param->vco_mode = |
(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 = |
(args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0; |
mpll_param->half_rate = |
(args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0; |
break; |
default: |
return -EINVAL; |
} |
break; |
default: |
return -EINVAL; |
} |
return 0; |
} |
void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) |
{ |
DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; |
2819,6 → 2989,48 |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev, |
u32 eng_clock, u32 mem_clock) |
{ |
SET_ENGINE_CLOCK_PS_ALLOCATION args; |
int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); |
u32 tmp; |
memset(&args, 0, sizeof(args)); |
tmp = eng_clock & SET_CLOCK_FREQ_MASK; |
tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24); |
args.ulTargetEngineClock = cpu_to_le32(tmp); |
if (mem_clock) |
args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK); |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
void radeon_atom_update_memory_dll(struct radeon_device *rdev, |
u32 mem_clock) |
{ |
u32 args; |
int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); |
args = cpu_to_le32(mem_clock); /* 10 khz */ |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
void radeon_atom_set_ac_timing(struct radeon_device *rdev, |
u32 mem_clock) |
{ |
SET_MEMORY_CLOCK_PS_ALLOCATION args; |
int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); |
u32 tmp = mem_clock | (COMPUTE_MEMORY_PLL_PARAM << 24); |
args.ulTargetMemoryClock = cpu_to_le32(tmp); /* 10 khz */ |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
union set_voltage { |
struct _SET_VOLTAGE_PS_ALLOCATION alloc; |
struct _SET_VOLTAGE_PARAMETERS v1; |
2863,7 → 3075,7 |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, |
int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, |
u16 voltage_id, u16 *voltage) |
{ |
union set_voltage args; |
2902,6 → 3114,898 |
return 0; |
} |
int radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev, |
u16 *voltage, |
u16 leakage_idx) |
{ |
return radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage); |
} |
int radeon_atom_get_leakage_id_from_vbios(struct radeon_device *rdev, |
u16 *leakage_id) |
{ |
union set_voltage args; |
int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); |
u8 frev, crev; |
if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) |
return -EINVAL; |
switch (crev) { |
case 3: |
case 4: |
args.v3.ucVoltageType = 0; |
args.v3.ucVoltageMode = ATOM_GET_LEAKAGE_ID; |
args.v3.usVoltageLevel = 0; |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
*leakage_id = le16_to_cpu(args.v3.usVoltageLevel); |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
return 0; |
} |
int radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *rdev, |
u16 *vddc, u16 *vddci, |
u16 virtual_voltage_id, |
u16 vbios_voltage_id) |
{ |
int index = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo); |
u8 frev, crev; |
u16 data_offset, size; |
int i, j; |
ATOM_ASIC_PROFILING_INFO_V2_1 *profile; |
u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf; |
*vddc = 0; |
*vddci = 0; |
if (!atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) |
return -EINVAL; |
profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (frev) { |
case 1: |
return -EINVAL; |
case 2: |
switch (crev) { |
case 1: |
if (size < sizeof(ATOM_ASIC_PROFILING_INFO_V2_1)) |
return -EINVAL; |
leakage_bin = (u16 *) |
(rdev->mode_info.atom_context->bios + data_offset + |
le16_to_cpu(profile->usLeakageBinArrayOffset)); |
vddc_id_buf = (u16 *) |
(rdev->mode_info.atom_context->bios + data_offset + |
le16_to_cpu(profile->usElbVDDC_IdArrayOffset)); |
vddc_buf = (u16 *) |
(rdev->mode_info.atom_context->bios + data_offset + |
le16_to_cpu(profile->usElbVDDC_LevelArrayOffset)); |
vddci_id_buf = (u16 *) |
(rdev->mode_info.atom_context->bios + data_offset + |
le16_to_cpu(profile->usElbVDDCI_IdArrayOffset)); |
vddci_buf = (u16 *) |
(rdev->mode_info.atom_context->bios + data_offset + |
le16_to_cpu(profile->usElbVDDCI_LevelArrayOffset)); |
if (profile->ucElbVDDC_Num > 0) { |
for (i = 0; i < profile->ucElbVDDC_Num; i++) { |
if (vddc_id_buf[i] == virtual_voltage_id) { |
for (j = 0; j < profile->ucLeakageBinNum; j++) { |
if (vbios_voltage_id <= leakage_bin[j]) { |
*vddc = vddc_buf[j * profile->ucElbVDDC_Num + i]; |
break; |
} |
} |
break; |
} |
} |
} |
if (profile->ucElbVDDCI_Num > 0) { |
for (i = 0; i < profile->ucElbVDDCI_Num; i++) { |
if (vddci_id_buf[i] == virtual_voltage_id) { |
for (j = 0; j < profile->ucLeakageBinNum; j++) { |
if (vbios_voltage_id <= leakage_bin[j]) { |
*vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i]; |
break; |
} |
} |
break; |
} |
} |
} |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
return 0; |
} |
union get_voltage_info { |
struct _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 in; |
struct _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 evv_out; |
}; |
int radeon_atom_get_voltage_evv(struct radeon_device *rdev, |
u16 virtual_voltage_id, |
u16 *voltage) |
{ |
int index = GetIndexIntoMasterTable(COMMAND, GetVoltageInfo); |
u32 entry_id; |
u32 count = rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; |
union get_voltage_info args; |
for (entry_id = 0; entry_id < count; entry_id++) { |
if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].v == |
virtual_voltage_id) |
break; |
} |
if (entry_id >= count) |
return -EINVAL; |
args.in.ucVoltageType = VOLTAGE_TYPE_VDDC; |
args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE; |
args.in.ulSCLKFreq = |
cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk); |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
*voltage = le16_to_cpu(args.evv_out.usVoltageLevel); |
return 0; |
} |
int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev, |
u16 voltage_level, u8 voltage_type, |
u32 *gpio_value, u32 *gpio_mask) |
{ |
union set_voltage args; |
int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); |
u8 frev, crev; |
if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) |
return -EINVAL; |
switch (crev) { |
case 1: |
return -EINVAL; |
case 2: |
args.v2.ucVoltageType = voltage_type; |
args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK; |
args.v2.usVoltageLevel = cpu_to_le16(voltage_level); |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
*gpio_mask = le32_to_cpu(*(u32 *)&args.v2); |
args.v2.ucVoltageType = voltage_type; |
args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL; |
args.v2.usVoltageLevel = cpu_to_le16(voltage_level); |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
*gpio_value = le32_to_cpu(*(u32 *)&args.v2); |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
return 0; |
} |
union voltage_object_info { |
struct _ATOM_VOLTAGE_OBJECT_INFO v1; |
struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2; |
struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3; |
}; |
union voltage_object { |
struct _ATOM_VOLTAGE_OBJECT v1; |
struct _ATOM_VOLTAGE_OBJECT_V2 v2; |
union _ATOM_VOLTAGE_OBJECT_V3 v3; |
}; |
static ATOM_VOLTAGE_OBJECT *atom_lookup_voltage_object_v1(ATOM_VOLTAGE_OBJECT_INFO *v1, |
u8 voltage_type) |
{ |
u32 size = le16_to_cpu(v1->sHeader.usStructureSize); |
u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO, asVoltageObj[0]); |
u8 *start = (u8 *)v1; |
while (offset < size) { |
ATOM_VOLTAGE_OBJECT *vo = (ATOM_VOLTAGE_OBJECT *)(start + offset); |
if (vo->ucVoltageType == voltage_type) |
return vo; |
offset += offsetof(ATOM_VOLTAGE_OBJECT, asFormula.ucVIDAdjustEntries) + |
vo->asFormula.ucNumOfVoltageEntries; |
} |
return NULL; |
} |
static ATOM_VOLTAGE_OBJECT_V2 *atom_lookup_voltage_object_v2(ATOM_VOLTAGE_OBJECT_INFO_V2 *v2, |
u8 voltage_type) |
{ |
u32 size = le16_to_cpu(v2->sHeader.usStructureSize); |
u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V2, asVoltageObj[0]); |
u8 *start = (u8*)v2; |
while (offset < size) { |
ATOM_VOLTAGE_OBJECT_V2 *vo = (ATOM_VOLTAGE_OBJECT_V2 *)(start + offset); |
if (vo->ucVoltageType == voltage_type) |
return vo; |
offset += offsetof(ATOM_VOLTAGE_OBJECT_V2, asFormula.asVIDAdjustEntries) + |
(vo->asFormula.ucNumOfVoltageEntries * sizeof(VOLTAGE_LUT_ENTRY)); |
} |
return NULL; |
} |
static ATOM_VOLTAGE_OBJECT_V3 *atom_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3, |
u8 voltage_type, u8 voltage_mode) |
{ |
u32 size = le16_to_cpu(v3->sHeader.usStructureSize); |
u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]); |
u8 *start = (u8*)v3; |
while (offset < size) { |
ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset); |
if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) && |
(vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode)) |
return vo; |
offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize); |
} |
return NULL; |
} |
bool |
radeon_atom_is_voltage_gpio(struct radeon_device *rdev, |
u8 voltage_type, u8 voltage_mode) |
{ |
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); |
u8 frev, crev; |
u16 data_offset, size; |
union voltage_object_info *voltage_info; |
union voltage_object *voltage_object = NULL; |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
voltage_info = (union voltage_object_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (frev) { |
case 1: |
case 2: |
switch (crev) { |
case 1: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type); |
if (voltage_object && |
(voltage_object->v1.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO)) |
return true; |
break; |
case 2: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type); |
if (voltage_object && |
(voltage_object->v2.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO)) |
return true; |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return false; |
} |
break; |
case 3: |
switch (crev) { |
case 1: |
if (atom_lookup_voltage_object_v3(&voltage_info->v3, |
voltage_type, voltage_mode)) |
return true; |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return false; |
} |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return false; |
} |
} |
return false; |
} |
int radeon_atom_get_svi2_info(struct radeon_device *rdev, |
u8 voltage_type, |
u8 *svd_gpio_id, u8 *svc_gpio_id) |
{ |
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); |
u8 frev, crev; |
u16 data_offset, size; |
union voltage_object_info *voltage_info; |
union voltage_object *voltage_object = NULL; |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
voltage_info = (union voltage_object_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (frev) { |
case 3: |
switch (crev) { |
case 1: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v3(&voltage_info->v3, |
voltage_type, |
VOLTAGE_OBJ_SVID2); |
if (voltage_object) { |
*svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId; |
*svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId; |
} else { |
return -EINVAL; |
} |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return -EINVAL; |
} |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return -EINVAL; |
} |
} |
return 0; |
} |
int radeon_atom_get_max_voltage(struct radeon_device *rdev, |
u8 voltage_type, u16 *max_voltage) |
{ |
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); |
u8 frev, crev; |
u16 data_offset, size; |
union voltage_object_info *voltage_info; |
union voltage_object *voltage_object = NULL; |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
voltage_info = (union voltage_object_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (crev) { |
case 1: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type); |
if (voltage_object) { |
ATOM_VOLTAGE_FORMULA *formula = |
&voltage_object->v1.asFormula; |
if (formula->ucFlag & 1) |
*max_voltage = |
le16_to_cpu(formula->usVoltageBaseLevel) + |
formula->ucNumOfVoltageEntries / 2 * |
le16_to_cpu(formula->usVoltageStep); |
else |
*max_voltage = |
le16_to_cpu(formula->usVoltageBaseLevel) + |
(formula->ucNumOfVoltageEntries - 1) * |
le16_to_cpu(formula->usVoltageStep); |
return 0; |
} |
break; |
case 2: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type); |
if (voltage_object) { |
ATOM_VOLTAGE_FORMULA_V2 *formula = |
&voltage_object->v2.asFormula; |
if (formula->ucNumOfVoltageEntries) { |
VOLTAGE_LUT_ENTRY *lut = (VOLTAGE_LUT_ENTRY *) |
((u8 *)&formula->asVIDAdjustEntries[0] + |
(sizeof(VOLTAGE_LUT_ENTRY) * (formula->ucNumOfVoltageEntries - 1))); |
*max_voltage = |
le16_to_cpu(lut->usVoltageValue); |
return 0; |
} |
} |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return -EINVAL; |
} |
} |
return -EINVAL; |
} |
int radeon_atom_get_min_voltage(struct radeon_device *rdev, |
u8 voltage_type, u16 *min_voltage) |
{ |
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); |
u8 frev, crev; |
u16 data_offset, size; |
union voltage_object_info *voltage_info; |
union voltage_object *voltage_object = NULL; |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
voltage_info = (union voltage_object_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (crev) { |
case 1: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type); |
if (voltage_object) { |
ATOM_VOLTAGE_FORMULA *formula = |
&voltage_object->v1.asFormula; |
*min_voltage = |
le16_to_cpu(formula->usVoltageBaseLevel); |
return 0; |
} |
break; |
case 2: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type); |
if (voltage_object) { |
ATOM_VOLTAGE_FORMULA_V2 *formula = |
&voltage_object->v2.asFormula; |
if (formula->ucNumOfVoltageEntries) { |
*min_voltage = |
le16_to_cpu(formula->asVIDAdjustEntries[ |
0 |
].usVoltageValue); |
return 0; |
} |
} |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return -EINVAL; |
} |
} |
return -EINVAL; |
} |
int radeon_atom_get_voltage_step(struct radeon_device *rdev, |
u8 voltage_type, u16 *voltage_step) |
{ |
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); |
u8 frev, crev; |
u16 data_offset, size; |
union voltage_object_info *voltage_info; |
union voltage_object *voltage_object = NULL; |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
voltage_info = (union voltage_object_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (crev) { |
case 1: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type); |
if (voltage_object) { |
ATOM_VOLTAGE_FORMULA *formula = |
&voltage_object->v1.asFormula; |
if (formula->ucFlag & 1) |
*voltage_step = |
(le16_to_cpu(formula->usVoltageStep) + 1) / 2; |
else |
*voltage_step = |
le16_to_cpu(formula->usVoltageStep); |
return 0; |
} |
break; |
case 2: |
return -EINVAL; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return -EINVAL; |
} |
} |
return -EINVAL; |
} |
int radeon_atom_round_to_true_voltage(struct radeon_device *rdev, |
u8 voltage_type, |
u16 nominal_voltage, |
u16 *true_voltage) |
{ |
u16 min_voltage, max_voltage, voltage_step; |
if (radeon_atom_get_max_voltage(rdev, voltage_type, &max_voltage)) |
return -EINVAL; |
if (radeon_atom_get_min_voltage(rdev, voltage_type, &min_voltage)) |
return -EINVAL; |
if (radeon_atom_get_voltage_step(rdev, voltage_type, &voltage_step)) |
return -EINVAL; |
if (nominal_voltage <= min_voltage) |
*true_voltage = min_voltage; |
else if (nominal_voltage >= max_voltage) |
*true_voltage = max_voltage; |
else |
*true_voltage = min_voltage + |
((nominal_voltage - min_voltage) / voltage_step) * |
voltage_step; |
return 0; |
} |
int radeon_atom_get_voltage_table(struct radeon_device *rdev, |
u8 voltage_type, u8 voltage_mode, |
struct atom_voltage_table *voltage_table) |
{ |
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); |
u8 frev, crev; |
u16 data_offset, size; |
int i, ret; |
union voltage_object_info *voltage_info; |
union voltage_object *voltage_object = NULL; |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
voltage_info = (union voltage_object_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (frev) { |
case 1: |
case 2: |
switch (crev) { |
case 1: |
DRM_ERROR("old table version %d, %d\n", frev, crev); |
return -EINVAL; |
case 2: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type); |
if (voltage_object) { |
ATOM_VOLTAGE_FORMULA_V2 *formula = |
&voltage_object->v2.asFormula; |
VOLTAGE_LUT_ENTRY *lut; |
if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES) |
return -EINVAL; |
lut = &formula->asVIDAdjustEntries[0]; |
for (i = 0; i < formula->ucNumOfVoltageEntries; i++) { |
voltage_table->entries[i].value = |
le16_to_cpu(lut->usVoltageValue); |
ret = radeon_atom_get_voltage_gpio_settings(rdev, |
voltage_table->entries[i].value, |
voltage_type, |
&voltage_table->entries[i].smio_low, |
&voltage_table->mask_low); |
if (ret) |
return ret; |
lut = (VOLTAGE_LUT_ENTRY *) |
((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY)); |
} |
voltage_table->count = formula->ucNumOfVoltageEntries; |
return 0; |
} |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return -EINVAL; |
} |
break; |
case 3: |
switch (crev) { |
case 1: |
voltage_object = (union voltage_object *) |
atom_lookup_voltage_object_v3(&voltage_info->v3, |
voltage_type, voltage_mode); |
if (voltage_object) { |
ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio = |
&voltage_object->v3.asGpioVoltageObj; |
VOLTAGE_LUT_ENTRY_V2 *lut; |
if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES) |
return -EINVAL; |
lut = &gpio->asVolGpioLut[0]; |
for (i = 0; i < gpio->ucGpioEntryNum; i++) { |
voltage_table->entries[i].value = |
le16_to_cpu(lut->usVoltageValue); |
voltage_table->entries[i].smio_low = |
le32_to_cpu(lut->ulVoltageId); |
lut = (VOLTAGE_LUT_ENTRY_V2 *) |
((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY_V2)); |
} |
voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal); |
voltage_table->count = gpio->ucGpioEntryNum; |
voltage_table->phase_delay = gpio->ucPhaseDelay; |
return 0; |
} |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return -EINVAL; |
} |
break; |
default: |
DRM_ERROR("unknown voltage object table\n"); |
return -EINVAL; |
} |
} |
return -EINVAL; |
} |
union vram_info { |
struct _ATOM_VRAM_INFO_V3 v1_3; |
struct _ATOM_VRAM_INFO_V4 v1_4; |
struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1; |
}; |
int radeon_atom_get_memory_info(struct radeon_device *rdev, |
u8 module_index, struct atom_memory_info *mem_info) |
{ |
int index = GetIndexIntoMasterTable(DATA, VRAM_Info); |
u8 frev, crev, i; |
u16 data_offset, size; |
union vram_info *vram_info; |
memset(mem_info, 0, sizeof(struct atom_memory_info)); |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
vram_info = (union vram_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (frev) { |
case 1: |
switch (crev) { |
case 3: |
/* r6xx */ |
if (module_index < vram_info->v1_3.ucNumOfVRAMModule) { |
ATOM_VRAM_MODULE_V3 *vram_module = |
(ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo; |
for (i = 0; i < module_index; i++) { |
if (le16_to_cpu(vram_module->usSize) == 0) |
return -EINVAL; |
vram_module = (ATOM_VRAM_MODULE_V3 *) |
((u8 *)vram_module + le16_to_cpu(vram_module->usSize)); |
} |
mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf; |
mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0; |
} else |
return -EINVAL; |
break; |
case 4: |
/* r7xx, evergreen */ |
if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { |
ATOM_VRAM_MODULE_V4 *vram_module = |
(ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; |
for (i = 0; i < module_index; i++) { |
if (le16_to_cpu(vram_module->usModuleSize) == 0) |
return -EINVAL; |
vram_module = (ATOM_VRAM_MODULE_V4 *) |
((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); |
} |
mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; |
mem_info->mem_type = vram_module->ucMemoryType & 0xf0; |
} else |
return -EINVAL; |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
break; |
case 2: |
switch (crev) { |
case 1: |
/* ni */ |
if (module_index < vram_info->v2_1.ucNumOfVRAMModule) { |
ATOM_VRAM_MODULE_V7 *vram_module = |
(ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo; |
for (i = 0; i < module_index; i++) { |
if (le16_to_cpu(vram_module->usModuleSize) == 0) |
return -EINVAL; |
vram_module = (ATOM_VRAM_MODULE_V7 *) |
((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); |
} |
mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; |
mem_info->mem_type = vram_module->ucMemoryType & 0xf0; |
} else |
return -EINVAL; |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
return 0; |
} |
return -EINVAL; |
} |
int radeon_atom_get_mclk_range_table(struct radeon_device *rdev, |
bool gddr5, u8 module_index, |
struct atom_memory_clock_range_table *mclk_range_table) |
{ |
int index = GetIndexIntoMasterTable(DATA, VRAM_Info); |
u8 frev, crev, i; |
u16 data_offset, size; |
union vram_info *vram_info; |
u32 mem_timing_size = gddr5 ? |
sizeof(ATOM_MEMORY_TIMING_FORMAT_V2) : sizeof(ATOM_MEMORY_TIMING_FORMAT); |
memset(mclk_range_table, 0, sizeof(struct atom_memory_clock_range_table)); |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
vram_info = (union vram_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (frev) { |
case 1: |
switch (crev) { |
case 3: |
DRM_ERROR("old table version %d, %d\n", frev, crev); |
return -EINVAL; |
case 4: |
/* r7xx, evergreen */ |
if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { |
ATOM_VRAM_MODULE_V4 *vram_module = |
(ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; |
ATOM_MEMORY_TIMING_FORMAT *format; |
for (i = 0; i < module_index; i++) { |
if (le16_to_cpu(vram_module->usModuleSize) == 0) |
return -EINVAL; |
vram_module = (ATOM_VRAM_MODULE_V4 *) |
((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); |
} |
mclk_range_table->num_entries = (u8) |
((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / |
mem_timing_size); |
format = &vram_module->asMemTiming[0]; |
for (i = 0; i < mclk_range_table->num_entries; i++) { |
mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange); |
format = (ATOM_MEMORY_TIMING_FORMAT *) |
((u8 *)format + mem_timing_size); |
} |
} else |
return -EINVAL; |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
break; |
case 2: |
DRM_ERROR("new table version %d, %d\n", frev, crev); |
return -EINVAL; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
return 0; |
} |
return -EINVAL; |
} |
#define MEM_ID_MASK 0xff000000 |
#define MEM_ID_SHIFT 24 |
#define CLOCK_RANGE_MASK 0x00ffffff |
#define CLOCK_RANGE_SHIFT 0 |
#define LOW_NIBBLE_MASK 0xf |
#define DATA_EQU_PREV 0 |
#define DATA_FROM_TABLE 4 |
int radeon_atom_init_mc_reg_table(struct radeon_device *rdev, |
u8 module_index, |
struct atom_mc_reg_table *reg_table) |
{ |
int index = GetIndexIntoMasterTable(DATA, VRAM_Info); |
u8 frev, crev, num_entries, t_mem_id, num_ranges = 0; |
u32 i = 0, j; |
u16 data_offset, size; |
union vram_info *vram_info; |
memset(reg_table, 0, sizeof(struct atom_mc_reg_table)); |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, |
&frev, &crev, &data_offset)) { |
vram_info = (union vram_info *) |
(rdev->mode_info.atom_context->bios + data_offset); |
switch (frev) { |
case 1: |
DRM_ERROR("old table version %d, %d\n", frev, crev); |
return -EINVAL; |
case 2: |
switch (crev) { |
case 1: |
if (module_index < vram_info->v2_1.ucNumOfVRAMModule) { |
ATOM_INIT_REG_BLOCK *reg_block = |
(ATOM_INIT_REG_BLOCK *) |
((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset)); |
ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = |
(ATOM_MEMORY_SETTING_DATA_BLOCK *) |
((u8 *)reg_block + (2 * sizeof(u16)) + |
le16_to_cpu(reg_block->usRegIndexTblSize)); |
ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0]; |
num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) / |
sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1; |
if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
while (i < num_entries) { |
if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER) |
break; |
reg_table->mc_reg_address[i].s1 = |
(u16)(le16_to_cpu(format->usRegIndex)); |
reg_table->mc_reg_address[i].pre_reg_data = |
(u8)(format->ucPreRegDataLength); |
i++; |
format = (ATOM_INIT_REG_INDEX_FORMAT *) |
((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT)); |
} |
reg_table->last = i; |
while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) && |
(num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) { |
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)((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)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] = |
reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1]; |
} |
} |
num_ranges++; |
} |
reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *) |
((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)); |
} |
if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) |
return -EINVAL; |
reg_table->num_entries = num_ranges; |
} else |
return -EINVAL; |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
break; |
default: |
DRM_ERROR("Unknown table version %d, %d\n", frev, crev); |
return -EINVAL; |
} |
return 0; |
} |
return -EINVAL; |
} |
void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
2921,6 → 4025,10 |
/* 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); |
/drivers/video/drm/radeon/radeon_benchmark.c |
---|
41,7 → 41,7 |
struct radeon_fence *fence = NULL; |
int i, r; |
start_jiffies = GetTimerTicks(); |
start_jiffies = jiffies; |
for (i = 0; i < n; i++) { |
switch (flag) { |
case RADEON_BENCHMARK_COPY_DMA: |
65,7 → 65,7 |
goto exit_do_move; |
radeon_fence_unref(&fence); |
} |
end_jiffies = GetTimerTicks(); |
end_jiffies = jiffies; |
r = jiffies_to_msecs(end_jiffies - start_jiffies); |
exit_do_move: |
100,7 → 100,7 |
ENTER(); |
n = RADEON_BENCHMARK_ITERATIONS; |
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, NULL, &sobj); |
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, 0, NULL, &sobj); |
if (r) { |
goto out_cleanup; |
} |
108,11 → 108,11 |
if (unlikely(r != 0)) |
goto out_cleanup; |
r = radeon_bo_pin(sobj, sdomain, &saddr); |
// radeon_bo_unreserve(sobj); |
radeon_bo_unreserve(sobj); |
if (r) { |
goto out_cleanup; |
} |
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, NULL, &dobj); |
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, 0, NULL, &dobj); |
if (r) { |
goto out_cleanup; |
} |
120,16 → 120,13 |
if (unlikely(r != 0)) |
goto out_cleanup; |
r = radeon_bo_pin(dobj, ddomain, &daddr); |
// radeon_bo_unreserve(dobj); |
radeon_bo_unreserve(dobj); |
if (r) { |
goto out_cleanup; |
} |
dbgprintf("done\n"); |
/* r100 doesn't have dma engine so skip the test */ |
/* also, VRAM-to-VRAM test doesn't make much sense for DMA */ |
/* skip it as well if domains are the same */ |
if ((rdev->asic->copy.dma) && (sdomain != ddomain)) { |
if (rdev->asic->copy.dma) { |
time = radeon_benchmark_do_move(rdev, size, saddr, daddr, |
RADEON_BENCHMARK_COPY_DMA, n); |
if (time < 0) |
139,6 → 136,7 |
sdomain, ddomain, "dma"); |
} |
if (rdev->asic->copy.blit) { |
time = radeon_benchmark_do_move(rdev, size, saddr, daddr, |
RADEON_BENCHMARK_COPY_BLIT, n); |
if (time < 0) |
146,6 → 144,7 |
if (time > 0) |
radeon_benchmark_log_results(n, size, time, |
sdomain, ddomain, "blit"); |
} |
out_cleanup: |
if (sobj) { |
/drivers/video/drm/radeon/radeon_bios.c |
---|
160,7 → 160,7 |
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; |
474,7 → 474,7 |
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); |
} |
511,7 → 511,7 |
(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)); |
} |
529,7 → 529,7 |
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; |
587,7 → 587,7 |
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"); |
/drivers/video/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, |
147,7 → 131,7 |
enum radeon_combios_table_offset table) |
{ |
struct radeon_device *rdev = dev->dev_private; |
int rev; |
int rev, size; |
uint16_t offset = 0, check_offset; |
if (!rdev->bios) |
156,174 → 140,106 |
switch (table) { |
/* absolute offset tables */ |
case COMBIOS_ASIC_INIT_1_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0xc); |
if (check_offset) |
offset = check_offset; |
check_offset = 0xc; |
break; |
case COMBIOS_BIOS_SUPPORT_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x14); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x14; |
break; |
case COMBIOS_DAC_PROGRAMMING_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x2a); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x2a; |
break; |
case COMBIOS_MAX_COLOR_DEPTH_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x2c); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x2c; |
break; |
case COMBIOS_CRTC_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x2e); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x2e; |
break; |
case COMBIOS_PLL_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x30); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x30; |
break; |
case COMBIOS_TV_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x32); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x32; |
break; |
case COMBIOS_DFP_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x34); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x34; |
break; |
case COMBIOS_HW_CONFIG_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x36); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x36; |
break; |
case COMBIOS_MULTIMEDIA_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x38); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x38; |
break; |
case COMBIOS_TV_STD_PATCH_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x3e); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x3e; |
break; |
case COMBIOS_LCD_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x40); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x40; |
break; |
case COMBIOS_MOBILE_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x42); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x42; |
break; |
case COMBIOS_PLL_INIT_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x46); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x46; |
break; |
case COMBIOS_MEM_CONFIG_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x48); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x48; |
break; |
case COMBIOS_SAVE_MASK_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x4a); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x4a; |
break; |
case COMBIOS_HARDCODED_EDID_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x4c); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x4c; |
break; |
case COMBIOS_ASIC_INIT_2_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x4e); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x4e; |
break; |
case COMBIOS_CONNECTOR_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x50); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x50; |
break; |
case COMBIOS_DYN_CLK_1_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x52); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x52; |
break; |
case COMBIOS_RESERVED_MEM_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x54); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x54; |
break; |
case COMBIOS_EXT_TMDS_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x58); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x58; |
break; |
case COMBIOS_MEM_CLK_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x5a); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x5a; |
break; |
case COMBIOS_EXT_DAC_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x5c); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x5c; |
break; |
case COMBIOS_MISC_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x5e); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x5e; |
break; |
case COMBIOS_CRT_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x60); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x60; |
break; |
case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x62); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x62; |
break; |
case COMBIOS_COMPONENT_VIDEO_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x64); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x64; |
break; |
case COMBIOS_FAN_SPEED_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x66); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x66; |
break; |
case COMBIOS_OVERDRIVE_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x68); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x68; |
break; |
case COMBIOS_OEM_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x6a); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x6a; |
break; |
case COMBIOS_DYN_CLK_2_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x6c); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x6c; |
break; |
case COMBIOS_POWER_CONNECTOR_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x6e); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x6e; |
break; |
case COMBIOS_I2C_INFO_TABLE: |
check_offset = RBIOS16(rdev->bios_header_start + 0x70); |
if (check_offset) |
offset = check_offset; |
check_offset = 0x70; |
break; |
/* relative offset tables */ |
case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */ |
439,11 → 355,16 |
} |
break; |
default: |
check_offset = 0; |
break; |
} |
size = RBIOS8(rdev->bios_header_start + 0x6); |
/* check absolute offset tables */ |
if (table < COMBIOS_ASIC_INIT_3_TABLE && check_offset && check_offset < size) |
offset = RBIOS16(rdev->bios_header_start + check_offset); |
return offset; |
} |
bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) |
965,16 → 886,22 |
dac = RBIOS8(dac_info + 0x3) & 0xf; |
p_dac->ps2_pdac_adj = (bg << 8) | (dac); |
} |
/* if the values are all zeros, use the table */ |
if (p_dac->ps2_pdac_adj) |
/* if the values are zeros, use the table */ |
if ((dac == 0) || (bg == 0)) |
found = 0; |
else |
found = 1; |
} |
/* quirks */ |
/* Radeon 7000 (RV100) */ |
if (((dev->pdev->device == 0x5159) && |
(dev->pdev->subsystem_vendor == 0x174B) && |
(dev->pdev->subsystem_device == 0x7c28)) || |
/* Radeon 9100 (R200) */ |
if ((dev->pdev->device == 0x514D) && |
((dev->pdev->device == 0x514D) && |
(dev->pdev->subsystem_vendor == 0x174B) && |
(dev->pdev->subsystem_device == 0x7149)) { |
(dev->pdev->subsystem_device == 0x7149))) { |
/* vbios value is bad, use the default */ |
found = 0; |
} |
/drivers/video/drm/radeon/radeon_connectors.c |
---|
31,18 → 31,8 |
#include "radeon.h" |
#include "atom.h" |
#define DISABLE_DP 0 |
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); |
void radeon_connector_hotplug(struct drm_connector *connector) |
{ |
struct drm_device *dev = connector->dev; |
58,6 → 48,7 |
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; |
99,7 → 90,7 |
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); |
} |
} |
110,12 → 101,13 |
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: |
case DRM_MODE_CONNECTOR_HDMIB: |
if (radeon_connector->use_digital) { |
if (drm_detect_hdmi_monitor(radeon_connector->edid)) { |
if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
if (connector->display_info.bpc) |
bpc = connector->display_info.bpc; |
} |
123,7 → 115,7 |
break; |
case DRM_MODE_CONNECTOR_DVID: |
case DRM_MODE_CONNECTOR_HDMIA: |
if (drm_detect_hdmi_monitor(radeon_connector->edid)) { |
if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
if (connector->display_info.bpc) |
bpc = connector->display_info.bpc; |
} |
132,7 → 124,7 |
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) || |
drm_detect_hdmi_monitor(radeon_connector->edid)) { |
drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
if (connector->display_info.bpc) |
bpc = connector->display_info.bpc; |
} |
155,6 → 147,73 |
} |
break; |
} |
if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
/* 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); |
} |
} |
else if (bpc > 8) { |
/* max_tmds_clock missing, but hdmi spec mandates it for deep color. */ |
DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n", |
connector->name); |
bpc = 8; |
} |
} |
if ((radeon_deep_color == 0) && (bpc > 8)) { |
DRM_DEBUG("%s: Deep color disabled. Set radeon module param deep_color=1 to enable.\n", |
connector->name); |
bpc = 8; |
} |
DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n", |
connector->name, connector->display_info.bpc, bpc); |
return bpc; |
} |
166,7 → 225,6 |
struct drm_encoder *best_encoder = NULL; |
struct drm_encoder *encoder = NULL; |
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
struct drm_mode_object *obj; |
bool connected; |
int i; |
176,14 → 234,11 |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, |
connector->encoder_ids[i], |
DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, |
connector->encoder_ids[i]); |
if (!encoder) |
continue; |
encoder = obj_to_encoder(obj); |
if ((encoder == best_encoder) && (status == connector_status_connected)) |
connected = true; |
else |
199,7 → 254,6 |
static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type) |
{ |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
int i; |
207,11 → 261,10 |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
if (!encoder) |
continue; |
encoder = obj_to_encoder(obj); |
if (encoder->encoder_type == encoder_type) |
return encoder; |
} |
218,22 → 271,123 |
return NULL; |
} |
struct edid *radeon_connector_edid(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_property_blob *edid_blob = connector->edid_blob_ptr; |
if (radeon_connector->edid) { |
return radeon_connector->edid; |
} else if (edid_blob) { |
struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL); |
if (edid) |
radeon_connector->edid = edid; |
} |
return radeon_connector->edid; |
} |
static void radeon_connector_get_edid(struct drm_connector *connector) |
{ |
struct drm_device *dev = connector->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
if (radeon_connector->edid) |
return; |
/* 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(connector) != |
ENCODER_OBJECT_ID_NONE) && |
radeon_connector->ddc_bus->has_aux) { |
radeon_connector->edid = drm_get_edid(connector, |
&radeon_connector->ddc_bus->aux.ddc); |
} else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || |
(connector->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) && |
radeon_connector->ddc_bus->has_aux) |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->aux.ddc); |
else if (radeon_connector->ddc_bus) |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->adapter); |
} else if (radeon_connector->ddc_bus) { |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->adapter); |
} |
if (!radeon_connector->edid) { |
if (rdev->is_atom_bios) { |
/* some laptops provide a hardcoded edid in rom for LCDs */ |
if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) || |
(connector->connector_type == DRM_MODE_CONNECTOR_eDP))) |
radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); |
} else { |
/* some servers provide a hardcoded edid in rom for KVMs */ |
radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); |
} |
} |
} |
static void radeon_connector_free_edid(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
if (radeon_connector->edid) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
} |
} |
static int radeon_ddc_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret; |
if (radeon_connector->edid) { |
drm_mode_connector_update_edid_property(connector, radeon_connector->edid); |
ret = drm_add_edid_modes(connector, radeon_connector->edid); |
drm_edid_to_eld(connector, radeon_connector->edid); |
return ret; |
} |
drm_mode_connector_update_edid_property(connector, NULL); |
return 0; |
} |
static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) |
{ |
int enc_id = connector->encoder_ids[0]; |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
/* pick the encoder ids */ |
if (enc_id) { |
obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
if (enc_id) |
return drm_encoder_find(connector->dev, enc_id); |
return NULL; |
encoder = obj_to_encoder(obj); |
return encoder; |
} |
return NULL; |
static void radeon_get_native_mode(struct drm_connector *connector) |
{ |
struct drm_encoder *encoder = radeon_best_single_encoder(connector); |
struct radeon_encoder *radeon_encoder; |
if (encoder == NULL) |
return; |
radeon_encoder = to_radeon_encoder(encoder); |
if (!list_empty(&connector->probed_modes)) { |
struct drm_display_mode *preferred_mode = |
list_first_entry(&connector->probed_modes, |
struct drm_display_mode, head); |
radeon_encoder->native_mode = *preferred_mode; |
} else { |
radeon_encoder->native_mode.clock = 0; |
} |
} |
/* |
* radeon_connector_analog_encoder_conflict_solve |
270,13 → 424,17 |
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; |
399,6 → 557,36 |
} |
} |
if (property == rdev->mode_info.audio_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->audio != val) { |
radeon_connector->audio = val; |
radeon_property_change_mode(&radeon_encoder->base); |
} |
} |
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); |
501,9 → 689,38 |
radeon_property_change_mode(&radeon_encoder->base); |
} |
if (property == dev->mode_config.scaling_mode_property) { |
enum radeon_rmx_type rmx_type; |
if (connector->encoder) |
radeon_encoder = to_radeon_encoder(connector->encoder); |
else { |
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); |
} |
switch (val) { |
default: |
case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; |
case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; |
case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; |
case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; |
} |
if (radeon_encoder->rmx_type == rmx_type) |
return 0; |
if ((rmx_type != DRM_MODE_SCALE_NONE) && |
(radeon_encoder->native_mode.clock == 0)) |
return 0; |
radeon_encoder->rmx_type = rmx_type; |
radeon_property_change_mode(&radeon_encoder->base); |
} |
return 0; |
} |
static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, |
struct drm_connector *connector) |
{ |
541,13 → 758,12 |
static int radeon_lvds_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_encoder *encoder; |
int ret = 0; |
struct drm_display_mode *mode; |
if (radeon_connector->ddc_bus) { |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
if (ret > 0) { |
encoder = radeon_best_single_encoder(connector); |
if (encoder) { |
557,7 → 773,6 |
} |
return ret; |
} |
} |
encoder = radeon_best_single_encoder(connector); |
if (!encoder) |
626,16 → 841,9 |
} |
/* check for edid as well */ |
radeon_connector_get_edid(connector); |
if (radeon_connector->edid) |
ret = connector_status_connected; |
else { |
if (radeon_connector->ddc_bus) { |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->adapter); |
if (radeon_connector->edid) |
ret = connector_status_connected; |
} |
} |
/* check acpi lid status ??? */ |
radeon_connector_update_scratch_regs(connector, ret); |
646,10 → 854,9 |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
if (radeon_connector->edid) |
kfree(radeon_connector->edid); |
radeon_connector_free_edid(connector); |
kfree(radeon_connector->con_priv); |
// drm_sysfs_connector_remove(connector); |
drm_connector_unregister(connector); |
drm_connector_cleanup(connector); |
kfree(connector); |
} |
706,11 → 913,13 |
static int radeon_vga_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret; |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
radeon_get_native_mode(connector); |
return ret; |
} |
747,29 → 956,27 |
dret = radeon_ddc_probe(radeon_connector, false); |
if (dret) { |
radeon_connector->detected_by_load = false; |
if (radeon_connector->edid) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
} |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); |
radeon_connector_free_edid(connector); |
radeon_connector_get_edid(connector); |
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); |
radeon_connector->use_digital = |
!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); |
/* some oems have boards with separate digital and analog connectors |
* with a shared ddc line (often vga + hdmi) |
*/ |
if (radeon_connector->use_digital && radeon_connector->shared_ddc) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
radeon_connector_free_edid(connector); |
ret = connector_status_disconnected; |
} else |
} else { |
ret = connector_status_connected; |
} |
} |
} else { |
/* if we aren't forcing don't do destructive polling */ |
778,9 → 985,8 |
* 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) { |
805,6 → 1011,8 |
} |
radeon_connector_update_scratch_regs(connector, ret); |
out: |
return ret; |
} |
861,6 → 1069,7 |
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; |
892,15 → 1101,6 |
.set_property = radeon_connector_set_property, |
}; |
static int radeon_dvi_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret; |
ret = radeon_ddc_get_modes(radeon_connector); |
return ret; |
} |
static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector) |
{ |
struct drm_device *dev = connector->dev; |
941,32 → 1141,33 |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
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; |
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); |
if (dret) { |
radeon_connector->detected_by_load = false; |
if (radeon_connector->edid) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
} |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); |
radeon_connector_free_edid(connector); |
radeon_connector_get_edid(connector); |
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) { |
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; |
973,18 → 1174,18 |
broken_edid = true; /* defer use_digital to later */ |
} |
} else { |
radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); |
radeon_connector->use_digital = |
!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); |
/* some oems have boards with separate digital and analog connectors |
* with a shared ddc line (often vga + hdmi) |
*/ |
if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
radeon_connector_free_edid(connector); |
ret = connector_status_disconnected; |
} else |
} else { |
ret = connector_status_connected; |
} |
/* This gets complicated. We have boards with VGA + HDMI with a |
* shared DDC line and we have boards with DVI-D + HDMI with a shared |
* DDC line. The latter is more complex because with DVI<->HDMI adapters |
1004,8 → 1205,7 |
if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { |
/* hpd is our only option in this case */ |
if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
radeon_connector_free_edid(connector); |
ret = connector_status_disconnected; |
} |
} |
1039,14 → 1239,11 |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, |
connector->encoder_ids[i], |
DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, |
connector->encoder_ids[i]); |
if (!encoder) |
continue; |
encoder = obj_to_encoder(obj); |
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && |
encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) |
continue; |
1098,6 → 1295,8 |
/* 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: |
return ret; |
} |
1106,7 → 1305,6 |
{ |
int enc_id = connector->encoder_ids[0]; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
int i; |
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { |
1113,12 → 1311,10 |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
if (!encoder) |
continue; |
encoder = obj_to_encoder(obj); |
if (radeon_connector->use_digital == true) { |
if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) |
return encoder; |
1133,15 → 1329,10 |
/* then check use digitial */ |
/* pick the first one */ |
if (enc_id) { |
obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
if (enc_id) |
return drm_encoder_find(connector->dev, enc_id); |
return NULL; |
encoder = obj_to_encoder(obj); |
return encoder; |
} |
return NULL; |
} |
static void radeon_dvi_force(struct drm_connector *connector) |
{ |
1172,18 → 1363,16 |
(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)) { |
else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
/* HDMI 1.3+ supports max clock of 340 Mhz */ |
if (mode->clock > 340000) |
return MODE_CLOCK_HIGH; |
else |
return MODE_OK; |
} else |
} else { |
return MODE_CLOCK_HIGH; |
} else |
return MODE_CLOCK_HIGH; |
} |
} |
/* check against the max pixel clock */ |
if ((mode->clock / 10) > rdev->clock.max_pixel_clock) |
1193,7 → 1382,7 |
} |
static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { |
.get_modes = radeon_dvi_get_modes, |
.get_modes = radeon_vga_get_modes, |
.mode_valid = radeon_dvi_mode_valid, |
.best_encoder = radeon_dvi_encoder, |
}; |
1207,21 → 1396,6 |
.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); |
1237,7 → 1411,8 |
if (!radeon_dig_connector->edp_on) |
atombios_set_edp_panel_power(connector, |
ATOM_TRANSMITTER_ACTION_POWER_ON); |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
if (!radeon_dig_connector->edp_on) |
atombios_set_edp_panel_power(connector, |
ATOM_TRANSMITTER_ACTION_POWER_OFF); |
1248,7 → 1423,8 |
if (encoder) |
radeon_atom_ext_encoder_setup_ddc(encoder); |
} |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
} |
if (ret > 0) { |
1281,7 → 1457,10 |
if (encoder) |
radeon_atom_ext_encoder_setup_ddc(encoder); |
} |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
radeon_get_native_mode(connector); |
} |
return ret; |
1289,7 → 1468,6 |
u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector) |
{ |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
struct radeon_encoder *radeon_encoder; |
int i; |
1298,11 → 1476,10 |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
if (!encoder) |
continue; |
encoder = obj_to_encoder(obj); |
radeon_encoder = to_radeon_encoder(encoder); |
switch (radeon_encoder->encoder_id) { |
1317,9 → 1494,8 |
return ENCODER_OBJECT_ID_NONE; |
} |
bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) |
static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) |
{ |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
struct radeon_encoder *radeon_encoder; |
int i; |
1329,11 → 1505,10 |
if (connector->encoder_ids[i] == 0) |
break; |
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
if (!encoder) |
continue; |
encoder = obj_to_encoder(obj); |
radeon_encoder = to_radeon_encoder(encoder); |
if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) |
found = true; |
1348,7 → 1523,7 |
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; |
} |
1365,21 → 1540,16 |
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 DISABLE_DP |
connector->status = connector_status_disconnected; |
return connector->status; |
#endif |
if (!force && radeon_check_hpd_status_unchanged(connector)) { |
ret = connector->status; |
goto out; |
} |
if (!force && radeon_check_hpd_status_unchanged(connector)) |
return connector->status; |
radeon_connector_free_edid(connector); |
if (radeon_connector->edid) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
} |
if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || |
(connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { |
if (encoder) { |
1429,7 → 1599,7 |
if (radeon_dp_getdpcd(radeon_connector)) |
ret = connector_status_connected; |
} else { |
/* try non-aux ddc (DP to DVI/HMDI/etc. adapter) */ |
/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */ |
if (radeon_ddc_probe(radeon_connector, false)) |
ret = connector_status_connected; |
} |
1437,6 → 1607,7 |
} |
radeon_connector_update_scratch_regs(connector, ret); |
out: |
return ret; |
} |
1443,6 → 1614,8 |
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; |
1473,16 → 1646,25 |
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(connector))) { |
/* 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 = { |
.get_modes = radeon_dp_get_modes, |
.mode_valid = radeon_dp_mode_valid, |
1494,10 → 1676,28 |
.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, |
}; |
static const struct drm_connector_funcs radeon_edp_connector_funcs = { |
.dpms = drm_helper_connector_dpms, |
.detect = radeon_dp_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.set_property = radeon_lvds_set_property, |
.destroy = radeon_connector_destroy, |
.force = radeon_dvi_force, |
}; |
static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = { |
.dpms = drm_helper_connector_dpms, |
.detect = radeon_dp_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.set_property = radeon_lvds_set_property, |
.destroy = radeon_connector_destroy, |
.force = radeon_dvi_force, |
}; |
void |
radeon_add_atom_connector(struct drm_device *dev, |
uint32_t connector_id, |
1518,6 → 1718,7 |
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; |
1589,18 → 1790,11 |
goto failed; |
radeon_dig_connector->igp_lane_info = igp_lane_info; |
radeon_connector->con_priv = radeon_dig_connector; |
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 */ |
if (connector_type == DRM_MODE_CONNECTOR_eDP) |
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); |
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); |
if (radeon_connector->ddc_bus) |
has_aux = true; |
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) |
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); |
} |
switch (connector_type) { |
1607,6 → 1801,10 |
case DRM_MODE_CONNECTOR_VGA: |
case DRM_MODE_CONNECTOR_DVIA: |
default: |
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); |
connector->interlace_allowed = true; |
connector->doublescan_allowed = true; |
radeon_connector->dac_load_detect = true; |
1613,6 → 1811,9 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.load_detect_property, |
1); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
break; |
case DRM_MODE_CONNECTOR_DVII: |
case DRM_MODE_CONNECTOR_DVID: |
1619,6 → 1820,10 |
case DRM_MODE_CONNECTOR_HDMIA: |
case DRM_MODE_CONNECTOR_HDMIB: |
case DRM_MODE_CONNECTOR_DisplayPort: |
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); |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.underscan_property, |
UNDERSCAN_OFF); |
1628,6 → 1833,20 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.underscan_vborder_property, |
0); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
drm_object_attach_property(&radeon_connector->base.base, |
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) |
1643,6 → 1862,10 |
break; |
case DRM_MODE_CONNECTOR_LVDS: |
case DRM_MODE_CONNECTOR_eDP: |
drm_connector_init(dev, &radeon_connector->base, |
&radeon_lvds_bridge_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, |
&radeon_dp_connector_helper_funcs); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_FULLSCREEN); |
1665,6 → 1888,10 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.load_detect_property, |
1); |
if (ASIC_IS_AVIVO(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
/* no HPD on analog connectors */ |
radeon_connector->hpd.hpd = RADEON_HPD_NONE; |
connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
1683,6 → 1910,10 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.load_detect_property, |
1); |
if (ASIC_IS_AVIVO(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
/* no HPD on analog connectors */ |
radeon_connector->hpd.hpd = RADEON_HPD_NONE; |
connector->interlace_allowed = true; |
1716,7 → 1947,18 |
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.dither_property, |
RADEON_FMT_DITHER_DISABLE); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
} |
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 (connector_type == DRM_MODE_CONNECTOR_DVII) { |
radeon_connector->dac_load_detect = true; |
drm_object_attach_property(&radeon_connector->base.base, |
1756,7 → 1998,18 |
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.dither_property, |
RADEON_FMT_DITHER_DISABLE); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
} |
if (ASIC_IS_DCE2(rdev) && (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) |
1773,12 → 2026,10 |
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; |
1795,7 → 2046,18 |
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.dither_property, |
RADEON_FMT_DITHER_DISABLE); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
} |
if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.audio_property, |
RADEON_AUDIO_AUTO); |
} |
connector->interlace_allowed = true; |
/* in theory with a DP to VGA converter... */ |
connector->doublescan_allowed = false; |
1806,15 → 2068,13 |
goto failed; |
radeon_dig_connector->igp_lane_info = igp_lane_info; |
radeon_connector->con_priv = radeon_dig_connector; |
drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); |
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, |
1871,7 → 2131,11 |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
connector->display_info.subpixel_order = subpixel_order; |
drm_sysfs_connector_add(connector); |
drm_connector_register(connector); |
if (has_aux) |
radeon_dp_aux_init(radeon_connector); |
return; |
failed: |
2028,5 → 2292,5 |
} else |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
connector->display_info.subpixel_order = subpixel_order; |
drm_sysfs_connector_add(connector); |
drm_connector_register(connector); |
} |
/drivers/video/drm/radeon/radeon_cs.c |
---|
0,0 → 1,832 |
/* |
* Copyright 2008 Jerome Glisse. |
* 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, 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 (including the next |
* paragraph) 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 |
* PRECISION INSIGHT 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. |
* |
* 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) |
static inline unsigned long |
copy_from_user(void *to, const void __user *from, unsigned long n) |
{ |
memcpy(to, from, n); |
return n; |
} |
/* 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; |
if (p->chunk_relocs_idx == -1) { |
return 0; |
} |
chunk = &p->chunks[p->chunk_relocs_idx]; |
p->dma_reloc_idx = 0; |
/* FIXME: we assume that each relocs use 4 dwords */ |
p->nrelocs = chunk->length_dw / 4; |
p->relocs_ptr = kcalloc(p->nrelocs, sizeof(void *), GFP_KERNEL); |
if (p->relocs_ptr == NULL) { |
return -ENOMEM; |
} |
p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_cs_reloc), GFP_KERNEL); |
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]; |
for (j = 0; j < i; j++) { |
if (r->handle == p->relocs[j].handle) { |
p->relocs_ptr[i] = &p->relocs[j]; |
duplicate = true; |
break; |
} |
} |
if (duplicate) { |
p->relocs[i].handle = 0; |
continue; |
} |
p->relocs[i].gobj = drm_gem_object_lookup(ddev, p->filp, |
r->handle); |
if (p->relocs[i].gobj == NULL) { |
DRM_ERROR("gem object lookup failed 0x%x\n", |
r->handle); |
return -ENOENT; |
} |
p->relocs_ptr[i] = &p->relocs[i]; |
p->relocs[i].robj = gem_to_radeon_bo(p->relocs[i].gobj); |
/* 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 & RADEON_RELOC_PRIO_MASK) * 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 && |
(i == 0 || drm_pci_device_is_agp(p->rdev->ddev))) { |
/* TODO: is this still needed for NI+ ? */ |
p->relocs[i].prefered_domains = |
RADEON_GEM_DOMAIN_VRAM; |
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; |
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].allowed_domains = domain; |
} |
p->relocs[i].tv.bo = &p->relocs[i].robj->tbo; |
p->relocs[i].handle = r->handle; |
radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head, |
priority); |
} |
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) |
{ |
p->priority = priority; |
switch (ring) { |
default: |
DRM_ERROR("unknown ring id: %d\n", ring); |
return -EINVAL; |
case RADEON_CS_RING_GFX: |
p->ring = RADEON_RING_TYPE_GFX_INDEX; |
break; |
case RADEON_CS_RING_COMPUTE: |
if (p->rdev->family >= CHIP_TAHITI) { |
if (p->priority > 0) |
p->ring = CAYMAN_RING_TYPE_CP1_INDEX; |
else |
p->ring = CAYMAN_RING_TYPE_CP2_INDEX; |
} else |
p->ring = RADEON_RING_TYPE_GFX_INDEX; |
break; |
case RADEON_CS_RING_DMA: |
if (p->rdev->family >= CHIP_CAYMAN) { |
if (p->priority > 0) |
p->ring = R600_RING_TYPE_DMA_INDEX; |
else |
p->ring = CAYMAN_RING_TYPE_DMA1_INDEX; |
} else if (p->rdev->family >= CHIP_RV770) { |
p->ring = R600_RING_TYPE_DMA_INDEX; |
} else { |
return -EINVAL; |
} |
break; |
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; |
} |
static void radeon_cs_sync_rings(struct radeon_cs_parser *p) |
{ |
int i; |
for (i = 0; i < p->nrelocs; i++) { |
if (!p->relocs[i].robj) |
continue; |
radeon_semaphore_sync_to(p->ib.semaphore, |
p->relocs[i].robj->tbo.sync_obj); |
} |
} |
/* XXX: note that this is called from the legacy UMS CS ioctl as well */ |
int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) |
{ |
struct drm_radeon_cs *cs = data; |
uint64_t *chunk_array_ptr; |
unsigned size, i; |
u32 ring = RADEON_CS_RING_GFX; |
s32 priority = 0; |
if (!cs->num_chunks) { |
return 0; |
} |
/* get chunks */ |
INIT_LIST_HEAD(&p->validated); |
p->idx = 0; |
p->ib.sa_bo = NULL; |
p->ib.semaphore = NULL; |
p->const_ib.sa_bo = NULL; |
p->const_ib.semaphore = NULL; |
p->chunk_ib_idx = -1; |
p->chunk_relocs_idx = -1; |
p->chunk_flags_idx = -1; |
p->chunk_const_ib_idx = -1; |
p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL); |
if (p->chunks_array == NULL) { |
return -ENOMEM; |
} |
chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks); |
if (copy_from_user(p->chunks_array, chunk_array_ptr, |
sizeof(uint64_t)*cs->num_chunks)) { |
return -EFAULT; |
} |
p->cs_flags = 0; |
p->nchunks = cs->num_chunks; |
p->chunks = kcalloc(p->nchunks, sizeof(struct radeon_cs_chunk), GFP_KERNEL); |
if (p->chunks == NULL) { |
return -ENOMEM; |
} |
for (i = 0; i < p->nchunks; i++) { |
struct drm_radeon_cs_chunk __user **chunk_ptr = NULL; |
struct drm_radeon_cs_chunk user_chunk; |
uint32_t __user *cdata; |
chunk_ptr = (void __user*)(unsigned long)p->chunks_array[i]; |
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].chunk_id = user_chunk.chunk_id; |
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) { |
p->chunk_relocs_idx = i; |
} |
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) { |
p->chunk_ib_idx = i; |
/* zero length IB isn't useful */ |
if (p->chunks[i].length_dw == 0) |
return -EINVAL; |
} |
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_CONST_IB) { |
p->chunk_const_ib_idx = i; |
/* zero length CONST IB isn't useful */ |
if (p->chunks[i].length_dw == 0) |
return -EINVAL; |
} |
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) { |
p->chunk_flags_idx = i; |
/* zero length flags aren't useful */ |
if (p->chunks[i].length_dw == 0) |
return -EINVAL; |
} |
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]; |
} |
} |
/* these are KMS only */ |
if (p->rdev) { |
if ((p->cs_flags & RADEON_CS_USE_VM) && |
!p->rdev->vm_manager.enabled) { |
DRM_ERROR("VM not active on asic!\n"); |
return -EINVAL; |
} |
if (radeon_cs_get_ring(p, ring, priority)) |
return -EINVAL; |
/* we only support VM on some SI+ rings */ |
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; |
} |
} |
} |
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. |
* @error: error number |
* |
* If error is set than unvalidate buffer, otherwise just free memory |
* used by parsing context. |
**/ |
static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bool backoff) |
{ |
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); |
} else if (backoff) { |
ttm_eu_backoff_reservation(&parser->ticket, |
&parser->validated); |
} |
if (parser->relocs != NULL) { |
for (i = 0; i < parser->nrelocs; i++) { |
if (parser->relocs[i].gobj) |
drm_gem_object_unreference_unlocked(parser->relocs[i].gobj); |
} |
} |
kfree(parser->track); |
kfree(parser->relocs); |
kfree(parser->relocs_ptr); |
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); |
radeon_ib_free(parser->rdev, &parser->const_ib); |
} |
static int radeon_cs_ib_chunk(struct radeon_device *rdev, |
struct radeon_cs_parser *parser) |
{ |
int r; |
if (parser->chunk_ib_idx == -1) |
return 0; |
if (parser->cs_flags & RADEON_CS_USE_VM) |
return 0; |
r = radeon_cs_parse(rdev, parser->ring, parser); |
if (r || parser->parser_error) { |
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, true); |
if (r) { |
DRM_ERROR("Failed to schedule IB !\n"); |
} |
return r; |
} |
static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p, |
struct radeon_vm *vm) |
{ |
struct radeon_device *rdev = p->rdev; |
struct radeon_bo_va *bo_va; |
int i, 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; |
} |
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 radeon_vm_clear_invalids(rdev, vm); |
} |
static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, |
struct radeon_cs_parser *parser) |
{ |
struct radeon_fpriv *fpriv = parser->filp->driver_priv; |
struct radeon_vm *vm = &fpriv->vm; |
int r; |
if (parser->chunk_ib_idx == -1) |
return 0; |
if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) |
return 0; |
if (parser->const_ib.length_dw) { |
r = radeon_ring_ib_parse(rdev, parser->ring, &parser->const_ib); |
if (r) { |
return r; |
} |
} |
r = radeon_ring_ib_parse(rdev, parser->ring, &parser->ib); |
if (r) { |
return r; |
} |
if (parser->ring == R600_RING_TYPE_UVD_INDEX) |
radeon_uvd_note_usage(rdev); |
mutex_lock(&vm->mutex); |
r = radeon_bo_vm_update_pte(parser, vm); |
if (r) { |
goto out; |
} |
radeon_cs_sync_rings(parser); |
radeon_semaphore_sync_to(parser->ib.semaphore, vm->fence); |
if ((rdev->family >= CHIP_TAHITI) && |
(parser->chunk_const_ib_idx != -1)) { |
r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib, true); |
} else { |
r = radeon_ib_schedule(rdev, &parser->ib, NULL, true); |
} |
out: |
mutex_unlock(&vm->mutex); |
return r; |
} |
static int radeon_cs_handle_lockup(struct radeon_device *rdev, int r) |
{ |
if (r == -EDEADLK) { |
r = radeon_gpu_reset(rdev); |
if (!r) |
r = -EAGAIN; |
} |
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; |
struct radeon_cs_parser parser; |
int r; |
// down_read(&rdev->exclusive_lock); |
if (!rdev->accel_working) { |
// up_read(&rdev->exclusive_lock); |
return -EBUSY; |
} |
/* initialize parser */ |
memset(&parser, 0, sizeof(struct radeon_cs_parser)); |
parser.filp = filp; |
parser.rdev = rdev; |
parser.dev = rdev->dev; |
parser.family = rdev->family; |
r = radeon_cs_parser_init(&parser, data); |
if (r) { |
DRM_ERROR("Failed to initialize parser !\n"); |
radeon_cs_parser_fini(&parser, r, false); |
// up_read(&rdev->exclusive_lock); |
r = radeon_cs_handle_lockup(rdev, r); |
return r; |
} |
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); |
return r; |
} |
trace_radeon_cs(&parser); |
r = radeon_cs_ib_chunk(rdev, &parser); |
if (r) { |
goto out; |
} |
r = radeon_cs_ib_vm_chunk(rdev, &parser); |
if (r) { |
goto out; |
} |
out: |
radeon_cs_parser_fini(&parser, r, true); |
// up_read(&rdev->exclusive_lock); |
r = radeon_cs_handle_lockup(rdev, r); |
return r; |
} |
/** |
* radeon_cs_packet_parse() - parse cp packet and point ib index to next packet |
* @parser: parser structure holding parsing context. |
* @pkt: where to store packet information |
* |
* Assume that chunk_ib_index is properly set. Will return -EINVAL |
* if packet is bigger than remaining ib size. or if packets is unknown. |
**/ |
int radeon_cs_packet_parse(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
unsigned idx) |
{ |
struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; |
struct radeon_device *rdev = p->rdev; |
uint32_t header; |
if (idx >= ib_chunk->length_dw) { |
DRM_ERROR("Can not parse packet at %d after CS end %d !\n", |
idx, ib_chunk->length_dw); |
return -EINVAL; |
} |
header = radeon_get_ib_value(p, idx); |
pkt->idx = idx; |
pkt->type = RADEON_CP_PACKET_GET_TYPE(header); |
pkt->count = RADEON_CP_PACKET_GET_COUNT(header); |
pkt->one_reg_wr = 0; |
switch (pkt->type) { |
case RADEON_PACKET_TYPE0: |
if (rdev->family < CHIP_R600) { |
pkt->reg = R100_CP_PACKET0_GET_REG(header); |
pkt->one_reg_wr = |
RADEON_CP_PACKET0_GET_ONE_REG_WR(header); |
} else |
pkt->reg = R600_CP_PACKET0_GET_REG(header); |
break; |
case RADEON_PACKET_TYPE3: |
pkt->opcode = RADEON_CP_PACKET3_GET_OPCODE(header); |
break; |
case RADEON_PACKET_TYPE2: |
pkt->count = -1; |
break; |
default: |
DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx); |
return -EINVAL; |
} |
if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) { |
DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n", |
pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); |
return -EINVAL; |
} |
return 0; |
} |
/** |
* radeon_cs_packet_next_is_pkt3_nop() - test if the next packet is P3 NOP |
* @p: structure holding the parser context. |
* |
* Check if the next packet is NOP relocation packet3. |
**/ |
bool radeon_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p) |
{ |
struct radeon_cs_packet p3reloc; |
int r; |
r = radeon_cs_packet_parse(p, &p3reloc, p->idx); |
if (r) |
return false; |
if (p3reloc.type != RADEON_PACKET_TYPE3) |
return false; |
if (p3reloc.opcode != RADEON_PACKET3_NOP) |
return false; |
return true; |
} |
/** |
* radeon_cs_dump_packet() - dump raw packet context |
* @p: structure holding the parser context. |
* @pkt: structure holding the packet. |
* |
* Used mostly for debugging and error reporting. |
**/ |
void radeon_cs_dump_packet(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt) |
{ |
volatile uint32_t *ib; |
unsigned i; |
unsigned idx; |
ib = p->ib.ptr; |
idx = pkt->idx; |
for (i = 0; i <= (pkt->count + 1); i++, idx++) |
DRM_INFO("ib[%d]=0x%08X\n", idx, ib[idx]); |
} |
/** |
* radeon_cs_packet_next_reloc() - parse next (should be reloc) packet |
* @parser: parser structure holding parsing context. |
* @data: pointer to relocation data |
* @offset_start: starting offset |
* @offset_mask: offset mask (to align start offset on) |
* @reloc: reloc informations |
* |
* Check if next packet is relocation packet3, do bo validation and compute |
* GPU offset using the provided start. |
**/ |
int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p, |
struct radeon_cs_reloc **cs_reloc, |
int nomm) |
{ |
struct radeon_cs_chunk *relocs_chunk; |
struct radeon_cs_packet p3reloc; |
unsigned idx; |
int r; |
if (p->chunk_relocs_idx == -1) { |
DRM_ERROR("No relocation chunk !\n"); |
return -EINVAL; |
} |
*cs_reloc = NULL; |
relocs_chunk = &p->chunks[p->chunk_relocs_idx]; |
r = radeon_cs_packet_parse(p, &p3reloc, p->idx); |
if (r) |
return r; |
p->idx += p3reloc.count + 2; |
if (p3reloc.type != RADEON_PACKET_TYPE3 || |
p3reloc.opcode != RADEON_PACKET3_NOP) { |
DRM_ERROR("No packet3 for relocation for packet at %d.\n", |
p3reloc.idx); |
radeon_cs_dump_packet(p, &p3reloc); |
return -EINVAL; |
} |
idx = radeon_get_ib_value(p, p3reloc.idx + 1); |
if (idx >= relocs_chunk->length_dw) { |
DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", |
idx, relocs_chunk->length_dw); |
radeon_cs_dump_packet(p, &p3reloc); |
return -EINVAL; |
} |
/* FIXME: we assume reloc size is 4 dwords */ |
if (nomm) { |
*cs_reloc = p->relocs; |
(*cs_reloc)->gpu_offset = |
(u64)relocs_chunk->kdata[idx + 3] << 32; |
(*cs_reloc)->gpu_offset |= relocs_chunk->kdata[idx + 0]; |
} else |
*cs_reloc = p->relocs_ptr[(idx / 4)]; |
return 0; |
} |
/drivers/video/drm/radeon/radeon_cursor.c |
---|
0,0 → 1,314 |
/* |
* Copyright 2007-8 Advanced Micro Devices, Inc. |
* Copyright 2008 Red Hat Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Dave Airlie |
* Alex Deucher |
*/ |
#include <drm/drmP.h> |
#include <drm/radeon_drm.h> |
#include "radeon.h" |
static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock) |
{ |
struct radeon_device *rdev = crtc->dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
uint32_t cur_lock; |
if (ASIC_IS_DCE4(rdev)) { |
cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset); |
if (lock) |
cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK; |
else |
cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK; |
WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock); |
} else if (ASIC_IS_AVIVO(rdev)) { |
cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset); |
if (lock) |
cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK; |
else |
cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK; |
WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock); |
} else { |
cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset); |
if (lock) |
cur_lock |= RADEON_CUR_LOCK; |
else |
cur_lock &= ~RADEON_CUR_LOCK; |
WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock); |
} |
} |
static void radeon_hide_cursor(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct radeon_device *rdev = crtc->dev->dev_private; |
if (ASIC_IS_DCE4(rdev)) { |
WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset, |
EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | |
EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); |
} else if (ASIC_IS_AVIVO(rdev)) { |
WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, |
(AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); |
} else { |
u32 reg; |
switch (radeon_crtc->crtc_id) { |
case 0: |
reg = RADEON_CRTC_GEN_CNTL; |
break; |
case 1: |
reg = RADEON_CRTC2_GEN_CNTL; |
break; |
default: |
return; |
} |
WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN); |
} |
} |
static void radeon_show_cursor(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct radeon_device *rdev = crtc->dev->dev_private; |
if (ASIC_IS_DCE4(rdev)) { |
WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset); |
WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN | |
EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | |
EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); |
} else if (ASIC_IS_AVIVO(rdev)) { |
WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); |
WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | |
(AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); |
} else { |
switch (radeon_crtc->crtc_id) { |
case 0: |
WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); |
break; |
case 1: |
WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL); |
break; |
default: |
return; |
} |
WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN | |
(RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)), |
~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK)); |
} |
} |
static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, |
uint64_t gpu_addr) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct radeon_device *rdev = crtc->dev->dev_private; |
if (ASIC_IS_DCE4(rdev)) { |
WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, |
upper_32_bits(gpu_addr)); |
WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, |
gpu_addr & 0xffffffff); |
} else if (ASIC_IS_AVIVO(rdev)) { |
if (rdev->family >= CHIP_RV770) { |
if (radeon_crtc->crtc_id) |
WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); |
else |
WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); |
} |
WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, |
gpu_addr & 0xffffffff); |
} else { |
radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr; |
/* offset is from DISP(2)_BASE_ADDRESS */ |
WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); |
} |
} |
int radeon_crtc_cursor_set(struct drm_crtc *crtc, |
struct drm_file *file_priv, |
uint32_t handle, |
uint32_t width, |
uint32_t height) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct radeon_device *rdev = crtc->dev->dev_private; |
struct drm_gem_object *obj; |
struct radeon_bo *robj; |
uint64_t gpu_addr; |
int ret; |
if (!handle) { |
/* turn off cursor */ |
radeon_hide_cursor(crtc); |
obj = NULL; |
goto unpin; |
} |
if ((width > radeon_crtc->max_cursor_width) || |
(height > radeon_crtc->max_cursor_height)) { |
DRM_ERROR("bad cursor width or height %d x %d\n", width, height); |
return -EINVAL; |
} |
obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); |
if (!obj) { |
DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); |
return -ENOENT; |
} |
robj = gem_to_radeon_bo(obj); |
ret = radeon_bo_reserve(robj, false); |
if (unlikely(ret != 0)) |
goto fail; |
/* Only 27 bit offset for legacy cursor */ |
ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, |
ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, |
&gpu_addr); |
radeon_bo_unreserve(robj); |
if (ret) |
goto fail; |
radeon_crtc->cursor_width = width; |
radeon_crtc->cursor_height = height; |
radeon_lock_cursor(crtc, true); |
radeon_set_cursor(crtc, obj, gpu_addr); |
radeon_show_cursor(crtc); |
radeon_lock_cursor(crtc, false); |
unpin: |
if (radeon_crtc->cursor_bo) { |
robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); |
ret = radeon_bo_reserve(robj, false); |
if (likely(ret == 0)) { |
radeon_bo_unpin(robj); |
radeon_bo_unreserve(robj); |
} |
drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); |
} |
radeon_crtc->cursor_bo = obj; |
return 0; |
fail: |
drm_gem_object_unreference_unlocked(obj); |
return ret; |
} |
int radeon_crtc_cursor_move(struct drm_crtc *crtc, |
int x, int y) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct radeon_device *rdev = crtc->dev->dev_private; |
int xorigin = 0, yorigin = 0; |
int w = radeon_crtc->cursor_width; |
if (ASIC_IS_AVIVO(rdev)) { |
/* avivo cursor are offset into the total surface */ |
x += crtc->x; |
y += crtc->y; |
} |
DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); |
if (x < 0) { |
xorigin = min(-x, radeon_crtc->max_cursor_width - 1); |
x = 0; |
} |
if (y < 0) { |
yorigin = min(-y, radeon_crtc->max_cursor_height - 1); |
y = 0; |
} |
/* fixed on DCE6 and newer */ |
if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { |
int i = 0; |
struct drm_crtc *crtc_p; |
/* |
* avivo cursor image can't end on 128 pixel boundary or |
* go past the end of the frame if both crtcs are enabled |
* |
* NOTE: It is safe to access crtc->enabled of other crtcs |
* without holding either the mode_config lock or the other |
* crtc's lock as long as write access to this flag _always_ |
* grabs all locks. |
*/ |
list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { |
if (crtc_p->enabled) |
i++; |
} |
if (i > 1) { |
int cursor_end, frame_end; |
cursor_end = x - xorigin + w; |
frame_end = crtc->x + crtc->mode.crtc_hdisplay; |
if (cursor_end >= frame_end) { |
w = w - (cursor_end - frame_end); |
if (!(frame_end & 0x7f)) |
w--; |
} else { |
if (!(cursor_end & 0x7f)) |
w--; |
} |
if (w <= 0) { |
w = 1; |
cursor_end = x - xorigin + w; |
if (!(cursor_end & 0x7f)) { |
x--; |
WARN_ON_ONCE(x < 0); |
} |
} |
} |
} |
radeon_lock_cursor(crtc, true); |
if (ASIC_IS_DCE4(rdev)) { |
WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); |
WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); |
WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset, |
((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); |
} else if (ASIC_IS_AVIVO(rdev)) { |
WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); |
WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); |
WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, |
((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); |
} else { |
if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) |
y *= 2; |
WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset, |
(RADEON_CUR_LOCK |
| (xorigin << 16) |
| yorigin)); |
WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset, |
(RADEON_CUR_LOCK |
| (x << 16) |
| y)); |
/* offset is from DISP(2)_BASE_ADDRESS */ |
WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + |
(yorigin * 256))); |
} |
radeon_lock_cursor(crtc, false); |
return 0; |
} |
/drivers/video/drm/radeon/radeon_device.c |
---|
40,37 → 40,47 |
#include <drm/drm_pciids.h> |
#define PCI_VENDOR_ID_ATI 0x1002 |
#define PCI_VENDOR_ID_APPLE 0x106b |
int radeon_no_wb = 1; |
int radeon_no_wb; |
int radeon_modeset = -1; |
int radeon_dynclks = -1; |
int radeon_r4xx_atom = 0; |
int radeon_agpmode = 0; |
int radeon_vram_limit = 0; |
int radeon_gart_size = 512; /* default gart size */ |
int radeon_gart_size = -1; /* auto */ |
int radeon_benchmarking = 0; |
int radeon_testing = 0; |
int radeon_connector_table = 0; |
int radeon_tv = 1; |
int radeon_new_pll = -1; |
int radeon_dynpm = -1; |
int radeon_audio = 1; |
int radeon_audio = -1; |
int radeon_disp_priority = 0; |
int radeon_hw_i2c = 0; |
int radeon_pcie_gen2 = 0; |
int radeon_disp_priority = 0; |
int radeon_pcie_gen2 = -1; |
int radeon_msi = -1; |
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 = 8; |
int radeon_vm_block_size = -1; |
int radeon_deep_color = 0; |
int radeon_use_pflipirq = 2; |
int irq_override = 0; |
int radeon_bapm = -1; |
extern display_t *rdisplay; |
struct drm_device *main_drm_device; |
extern display_t *os_display; |
extern struct drm_device *main_device; |
extern videomode_t usermode; |
void parse_cmdline(char *cmdline, videomode_t *mode, char *log, int *kms); |
int init_display(struct radeon_device *rdev, videomode_t *mode); |
int init_display_kms(struct radeon_device *rdev, videomode_t *mode); |
int init_display_kms(struct drm_device *dev, videomode_t *usermode); |
int get_modes(videomode_t *mode, u32_t *count); |
int set_user_mode(videomode_t *mode); |
145,9 → 155,68 |
"VERDE", |
"OLAND", |
"HAINAN", |
"BONAIRE", |
"KAVERI", |
"KABINI", |
"HAWAII", |
"MULLINS", |
"LAST", |
}; |
#define RADEON_PX_QUIRK_DISABLE_PX (1 << 0) |
#define RADEON_PX_QUIRK_LONG_WAKEUP (1 << 1) |
struct radeon_px_quirk { |
u32 chip_vendor; |
u32 chip_device; |
u32 subsys_vendor; |
u32 subsys_device; |
u32 px_quirk_flags; |
}; |
static struct radeon_px_quirk radeon_px_quirk_list[] = { |
/* Acer aspire 5560g (CPU: AMD A4-3305M; GPU: AMD Radeon HD 6480g + 7470m) |
* https://bugzilla.kernel.org/show_bug.cgi?id=74551 |
*/ |
{ PCI_VENDOR_ID_ATI, 0x6760, 0x1025, 0x0672, RADEON_PX_QUIRK_DISABLE_PX }, |
/* Asus K73TA laptop with AMD A6-3400M APU and Radeon 6550 GPU |
* https://bugzilla.kernel.org/show_bug.cgi?id=51381 |
*/ |
{ PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX }, |
/* macbook pro 8.2 */ |
{ PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP }, |
{ 0, 0, 0, 0, 0 }, |
}; |
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; |
} |
static void radeon_device_handle_px_quirks(struct radeon_device *rdev) |
{ |
struct radeon_px_quirk *p = radeon_px_quirk_list; |
/* Apply PX quirks */ |
while (p && p->chip_device != 0) { |
if (rdev->pdev->vendor == p->chip_vendor && |
rdev->pdev->device == p->chip_device && |
rdev->pdev->subsystem_vendor == p->subsys_vendor && |
rdev->pdev->subsystem_device == p->subsys_device) { |
rdev->px_quirk_flags = p->px_quirk_flags; |
break; |
} |
++p; |
} |
if (rdev->px_quirk_flags & RADEON_PX_QUIRK_DISABLE_PX) |
rdev->flags &= ~RADEON_IS_PX; |
} |
/** |
* radeon_program_register_sequence - program an array of registers. |
* |
184,6 → 253,11 |
} |
} |
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. |
* |
198,6 → 272,9 |
int i; |
for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) { |
if (rdev->surface_regs[i].bo) |
radeon_bo_get_surface_reg(rdev->surface_regs[i].bo); |
else |
radeon_clear_surface_reg(rdev, i); |
} |
/* enable surfaces */ |
276,6 → 353,87 |
} |
/* |
* GPU doorbell aperture helpers function. |
*/ |
/** |
* radeon_doorbell_init - Init doorbell driver information. |
* |
* @rdev: radeon_device pointer |
* |
* Init doorbell driver information (CIK) |
* Returns 0 on success, error on failure. |
*/ |
static int radeon_doorbell_init(struct radeon_device *rdev) |
{ |
/* doorbell bar mapping */ |
rdev->doorbell.base = pci_resource_start(rdev->pdev, 2); |
rdev->doorbell.size = pci_resource_len(rdev->pdev, 2); |
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.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); |
memset(&rdev->doorbell.used, 0, sizeof(rdev->doorbell.used)); |
return 0; |
} |
/** |
* radeon_doorbell_fini - Tear down doorbell driver information. |
* |
* @rdev: radeon_device pointer |
* |
* Tear down doorbell driver information (CIK) |
*/ |
static void radeon_doorbell_fini(struct radeon_device *rdev) |
{ |
iounmap(rdev->doorbell.ptr); |
rdev->doorbell.ptr = NULL; |
} |
/** |
* radeon_doorbell_get - Allocate a doorbell entry |
* |
* @rdev: radeon_device pointer |
* @doorbell: doorbell index |
* |
* 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) |
{ |
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; |
} |
} |
/** |
* radeon_doorbell_free - Free a doorbell entry |
* |
* @rdev: radeon_device pointer |
* @doorbell: doorbell index |
* |
* 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_doorbells) |
__clear_bit(doorbell, rdev->doorbell.used); |
} |
/* |
* radeon_wb_*() |
* Writeback is the the method by which the the GPU updates special pages |
* in memory with the status of certain GPU events (fences, ring pointers, |
306,6 → 464,11 |
{ |
radeon_wb_disable(rdev); |
if (rdev->wb.wb_obj) { |
if (!radeon_bo_reserve(rdev->wb.wb_obj, false)) { |
radeon_bo_kunmap(rdev->wb.wb_obj); |
radeon_bo_unpin(rdev->wb.wb_obj); |
radeon_bo_unreserve(rdev->wb.wb_obj); |
} |
radeon_bo_unref(&rdev->wb.wb_obj); |
rdev->wb.wb = NULL; |
rdev->wb.wb_obj = NULL; |
327,7 → 490,8 |
if (rdev->wb.wb_obj == NULL) { |
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_GTT, NULL, &rdev->wb.wb_obj); |
RADEON_GEM_DOMAIN_GTT, 0, NULL, |
&rdev->wb.wb_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) create WB bo failed\n", r); |
return r; |
618,15 → 782,11 |
{ |
if (rdev->dummy_page.page) |
return 0; |
rdev->dummy_page.page = (void*)AllocPage(); |
rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO); |
if (rdev->dummy_page.page == NULL) |
return -ENOMEM; |
rdev->dummy_page.addr = MapIoMem((addr_t)rdev->dummy_page.page, 4096, 3); |
if (!rdev->dummy_page.addr) { |
// __free_page(rdev->dummy_page.page); |
rdev->dummy_page.page = NULL; |
return -ENOMEM; |
} |
rdev->dummy_page.addr = pci_map_page(rdev->pdev, rdev->dummy_page.page, |
0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); |
return 0; |
} |
641,7 → 801,7 |
{ |
if (rdev->dummy_page.page == NULL) |
return; |
KernelFree((void*)rdev->dummy_page.addr); |
rdev->dummy_page.page = NULL; |
} |
944,15 → 1104,27 |
radeon_vram_limit = 0; |
} |
if (radeon_gart_size == -1) { |
/* default to a larger gart size on newer asics */ |
if (rdev->family >= CHIP_RV770) |
radeon_gart_size = 1024; |
else |
radeon_gart_size = 512; |
} |
/* gtt size must be power of two and greater or equal to 32M */ |
if (radeon_gart_size < 32) { |
dev_warn(rdev->dev, "gart size (%d) too small forcing to 512M\n", |
dev_warn(rdev->dev, "gart size (%d) too small\n", |
radeon_gart_size); |
if (rdev->family >= CHIP_RV770) |
radeon_gart_size = 1024; |
else |
radeon_gart_size = 512; |
} else if (!radeon_check_pot_argument(radeon_gart_size)) { |
dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n", |
radeon_gart_size); |
if (rdev->family >= CHIP_RV770) |
radeon_gart_size = 1024; |
else |
radeon_gart_size = 512; |
} |
rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20; |
972,8 → 1144,69 |
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 == -1) { |
/* Total bits covered by PD + PTs */ |
unsigned bits = ilog2(radeon_vm_size) + 17; |
/* Make sure the PD is 4K in size up to 8GB address space. |
Above that split equal between PD and PTs */ |
if (radeon_vm_size <= 8) |
radeon_vm_block_size = bits - 9; |
else |
radeon_vm_block_size = (bits + 3) / 2; |
} else 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; |
} |
} |
/** |
* radeon_device_init - initialize the driver |
* |
* @rdev: radeon_device pointer |
* @pdev: drm dev pointer |
* @pdev: pci dev pointer |
* @flags: driver flags |
* |
* Initializes the driver info and hw (all asics). |
* Returns 0 for success or an error on failure. |
* Called at driver startup. |
*/ |
int radeon_device_init(struct radeon_device *rdev, |
struct drm_device *ddev, |
struct pci_dev *pdev, |
981,8 → 1214,10 |
{ |
int r, i; |
int dma_bits; |
bool runtime = false; |
rdev->shutdown = false; |
rdev->dev = &pdev->dev; |
rdev->ddev = ddev; |
rdev->pdev = pdev; |
rdev->flags = flags; |
989,7 → 1224,7 |
rdev->family = flags & RADEON_FAMILY_MASK; |
rdev->is_atom_bios = false; |
rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT; |
rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; |
rdev->mc.gtt_size = 512 * 1024 * 1024; |
rdev->accel_working = false; |
/* set up ring ids */ |
for (i = 0; i < RADEON_NUM_RINGS; i++) { |
1008,6 → 1243,7 |
mutex_init(&rdev->gem.mutex); |
mutex_init(&rdev->pm.mutex); |
mutex_init(&rdev->gpu_clock_mutex); |
mutex_init(&rdev->srbm_mutex); |
// init_rwsem(&rdev->pm.mclk_lock); |
// init_rwsem(&rdev->exclusive_lock); |
init_waitqueue_head(&rdev->irq.vblank_queue); |
1014,20 → 1250,17 |
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. |
1076,8 → 1309,24 |
/* Registers mapping */ |
/* TODO: block userspace mapping of io register */ |
spin_lock_init(&rdev->mmio_idx_lock); |
spin_lock_init(&rdev->smc_idx_lock); |
spin_lock_init(&rdev->pll_idx_lock); |
spin_lock_init(&rdev->mc_idx_lock); |
spin_lock_init(&rdev->pcie_idx_lock); |
spin_lock_init(&rdev->pciep_idx_lock); |
spin_lock_init(&rdev->pif_idx_lock); |
spin_lock_init(&rdev->cg_idx_lock); |
spin_lock_init(&rdev->uvd_idx_lock); |
spin_lock_init(&rdev->rcu_idx_lock); |
spin_lock_init(&rdev->didt_idx_lock); |
spin_lock_init(&rdev->end_idx_lock); |
if (rdev->family >= CHIP_BONAIRE) { |
rdev->rmmio_base = pci_resource_start(rdev->pdev, 5); |
rdev->rmmio_size = pci_resource_len(rdev->pdev, 5); |
} else { |
rdev->rmmio_base = pci_resource_start(rdev->pdev, 2); |
rdev->rmmio_size = pci_resource_len(rdev->pdev, 2); |
} |
rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size); |
if (rdev->rmmio == NULL) { |
return -ENOMEM; |
1085,6 → 1334,10 |
DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base); |
DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size); |
/* doorbell bar mapping */ |
if (rdev->family >= CHIP_BONAIRE) |
radeon_doorbell_init(rdev); |
/* io port mapping */ |
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { |
if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) { |
1096,15 → 1349,20 |
if (rdev->rio_mem == NULL) |
DRM_ERROR("Unable to find PCI I/O BAR\n"); |
if (rdev->flags & RADEON_IS_PX) |
radeon_device_handle_px_quirks(rdev); |
if (rdev->flags & RADEON_IS_PX) |
runtime = true; |
r = radeon_init(rdev); |
if (r) |
return r; |
// r = radeon_ib_ring_tests(rdev); |
// if (r) |
// DRM_ERROR("ib ring test failed (%d).\n", r); |
r = radeon_ib_ring_tests(rdev); |
if (r) |
DRM_ERROR("ib ring test failed (%d).\n", r); |
if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) { |
/* Acceleration not working on AGP card try again |
* with fallback to PCI or PCIE GART |
1116,14 → 1374,24 |
if (r) |
return r; |
} |
// if (radeon_testing) { |
// radeon_test_moves(rdev); |
// } |
// if ((radeon_testing & 2)) { |
// radeon_test_syncing(rdev); |
// } |
if ((radeon_testing & 1)) { |
if (rdev->accel_working) |
radeon_test_moves(rdev); |
else |
DRM_INFO("radeon: acceleration disabled, skipping move tests\n"); |
} |
if ((radeon_testing & 2)) { |
if (rdev->accel_working) |
radeon_test_syncing(rdev); |
else |
DRM_INFO("radeon: acceleration disabled, skipping sync tests\n"); |
} |
if (radeon_benchmarking) { |
if (rdev->accel_working) |
radeon_benchmark(rdev, radeon_benchmarking); |
else |
DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n"); |
} |
return 0; |
} |
1147,6 → 1415,8 |
int resched; |
// down_write(&rdev->exclusive_lock); |
rdev->needs_reset = false; |
radeon_save_bios_scratch_regs(rdev); |
/* block TTM */ |
// resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); |
1245,6 → 1515,8 |
* otherwise it should provide enough functionalities |
* for shadowfb to run |
*/ |
main_device = dev; |
if( radeon_modeset ) |
{ |
r = radeon_modeset_init(rdev); |
1251,76 → 1523,16 |
if (r) { |
return r; |
} |
}; |
return 0; |
init_display_kms(dev, &usermode); |
} |
videomode_t usermode; |
int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent) |
{ |
static struct drm_device *dev; |
int ret; |
dev = kzalloc(sizeof(*dev), 0); |
if (!dev) |
return -ENOMEM; |
// ret = pci_enable_device(pdev); |
// if (ret) |
// goto err_g1; |
// pci_set_master(pdev); |
// if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) { |
// printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); |
// goto err_g2; |
// } |
dev->pdev = pdev; |
dev->pci_device = pdev->device; |
dev->pci_vendor = pdev->vendor; |
INIT_LIST_HEAD(&dev->filelist); |
INIT_LIST_HEAD(&dev->ctxlist); |
INIT_LIST_HEAD(&dev->vmalist); |
INIT_LIST_HEAD(&dev->maplist); |
spin_lock_init(&dev->count_lock); |
mutex_init(&dev->struct_mutex); |
mutex_init(&dev->ctxlist_mutex); |
ret = radeon_driver_load_kms(dev, ent->driver_data ); |
if (ret) |
goto err_g4; |
main_drm_device = dev; |
if( radeon_modeset ) |
init_display_kms(dev->dev_private, &usermode); |
else |
init_display(dev->dev_private, &usermode); |
init_display(rdev, &usermode); |
return 0; |
} |
err_g4: |
// drm_put_minor(&dev->primary); |
//err_g3: |
// if (drm_core_check_feature(dev, DRIVER_MODESET)) |
// drm_put_minor(&dev->control); |
//err_g2: |
// pci_disable_device(pdev); |
//err_g1: |
free(dev); |
LEAVE(); |
return ret; |
} |
resource_size_t drm_get_resource_start(struct drm_device *dev, unsigned int resource) |
{ |
return pci_resource_start(dev->pdev, resource); |
1365,181 → 1577,85 |
return rem; |
} |
static struct pci_device_id pciidlist[] = { |
radeon_PCI_IDS |
}; |
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(int irq, void *arg); |
#define CURRENT_API 0x0200 /* 2.00 */ |
#define COMPATIBLE_API 0x0100 /* 1.00 */ |
#define API_VERSION (COMPATIBLE_API << 16) | CURRENT_API |
static struct drm_driver kms_driver = { |
.driver_features = |
DRIVER_USE_AGP | |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | |
DRIVER_PRIME | DRIVER_RENDER, |
.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, |
// .get_vblank_counter = radeon_get_vblank_counter_kms, |
// .enable_vblank = radeon_enable_vblank_kms, |
// .disable_vblank = radeon_disable_vblank_kms, |
// .get_vblank_timestamp = radeon_get_vblank_timestamp_kms, |
// .get_scanout_position = radeon_get_crtc_scanoutpos, |
#if defined(CONFIG_DEBUG_FS) |
.debugfs_init = radeon_debugfs_init, |
.debugfs_cleanup = radeon_debugfs_cleanup, |
#endif |
.irq_preinstall = radeon_driver_irq_preinstall_kms, |
.irq_postinstall = radeon_driver_irq_postinstall_kms, |
.irq_uninstall = radeon_driver_irq_uninstall_kms, |
.irq_handler = radeon_driver_irq_handler_kms, |
// .ioctls = radeon_ioctls_kms, |
// .gem_free_object = radeon_gem_object_free, |
// .gem_open_object = radeon_gem_object_open, |
// .gem_close_object = radeon_gem_object_close, |
// .dumb_create = radeon_mode_dumb_create, |
// .dumb_map_offset = radeon_mode_dumb_mmap, |
// .dumb_destroy = drm_gem_dumb_destroy, |
// .fops = &radeon_driver_kms_fops, |
#define SRV_GETVERSION 0 |
#define SRV_ENUM_MODES 1 |
#define SRV_SET_MODE 2 |
#define SRV_GET_CAPS 3 |
// .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
// .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
// .gem_prime_export = drm_gem_prime_export, |
// .gem_prime_import = drm_gem_prime_import, |
// .gem_prime_pin = radeon_gem_prime_pin, |
// .gem_prime_unpin = radeon_gem_prime_unpin, |
// .gem_prime_get_sg_table = radeon_gem_prime_get_sg_table, |
// .gem_prime_import_sg_table = radeon_gem_prime_import_sg_table, |
// .gem_prime_vmap = radeon_gem_prime_vmap, |
// .gem_prime_vunmap = radeon_gem_prime_vunmap, |
#define SRV_CREATE_SURFACE 10 |
#define SRV_DESTROY_SURFACE 11 |
#define SRV_LOCK_SURFACE 12 |
#define SRV_UNLOCK_SURFACE 13 |
#define SRV_RESIZE_SURFACE 14 |
#define SRV_BLIT_BITMAP 15 |
#define SRV_BLIT_TEXTURE 16 |
#define SRV_BLIT_VIDEO 17 |
}; |
int r600_video_blit(uint64_t src_offset, int x, int y, |
int w, int h, int pitch); |
#define check_input(size) \ |
if( unlikely((inp==NULL)||(io->inp_size != (size))) ) \ |
break; |
#define check_output(size) \ |
if( unlikely((outp==NULL)||(io->out_size != (size))) ) \ |
break; |
int _stdcall display_handler(ioctl_t *io) |
int ati_init(void) |
{ |
int retval = -1; |
u32_t *inp; |
u32_t *outp; |
inp = io->input; |
outp = io->output; |
switch(io->io_code) |
{ |
case SRV_GETVERSION: |
check_output(4); |
*outp = API_VERSION; |
retval = 0; |
break; |
case SRV_ENUM_MODES: |
dbgprintf("SRV_ENUM_MODES inp %x inp_size %x out_size %x\n", |
inp, io->inp_size, io->out_size ); |
check_output(4); |
if( radeon_modeset) |
retval = get_modes((videomode_t*)inp, outp); |
break; |
case SRV_SET_MODE: |
dbgprintf("SRV_SET_MODE inp %x inp_size %x\n", |
inp, io->inp_size); |
check_input(sizeof(videomode_t)); |
if( radeon_modeset ) |
retval = set_user_mode((videomode_t*)inp); |
break; |
/* |
case SRV_GET_CAPS: |
retval = get_driver_caps((hwcaps_t*)inp); |
break; |
case SRV_CREATE_SURFACE: |
// check_input(8); |
retval = create_surface(main_drm_device, (struct io_call_10*)inp); |
break; |
case SRV_LOCK_SURFACE: |
retval = lock_surface((struct io_call_12*)inp); |
break; |
case SRV_BLIT_BITMAP: |
srv_blit_bitmap( inp[0], inp[1], inp[2], |
inp[3], inp[4], inp[5], inp[6]); |
*/ |
}; |
return retval; |
} |
static char log[256]; |
static pci_dev_t device; |
u32_t drvEntry(int action, char *cmdline) |
{ |
struct radeon_device *rdev = NULL; |
const struct pci_device_id *ent; |
int err; |
u32_t retval = 0; |
if(action != 1) |
return 0; |
if( GetService("DISPLAY") != 0 ) |
return 0; |
if( cmdline && *cmdline ) |
parse_cmdline(cmdline, &usermode, log, &radeon_modeset); |
if(!dbg_open(log)) |
{ |
strcpy(log, "/TMP1/1/ati.log"); |
if(!dbg_open(log)) |
{ |
printf("Can't open %s\nExit\n", log); |
return 0; |
}; |
} |
dbgprintf("Radeon v3.10 preview-1 cmdline %s\n", cmdline); |
cpu_detect(); |
enum_pci_devices(); |
ent = find_pci_device(&device, pciidlist); |
if( unlikely(ent == NULL) ) |
{ |
dbgprintf("device not found\n"); |
return 0; |
return -ENODEV; |
}; |
dbgprintf("device %x:%x\n", device.pci_dev.vendor, |
drm_core_init(); |
DRM_INFO("device %x:%x\n", device.pci_dev.vendor, |
device.pci_dev.device); |
drm_global_init(); |
kms_driver.driver_features |= DRIVER_MODESET; |
err = drm_get_dev(&device.pci_dev, ent); |
err = drm_get_pci_dev(&device.pci_dev, ent, &kms_driver); |
rdev = rdisplay->ddev->dev_private; |
err = RegService("DISPLAY", display_handler); |
if( err != 0) |
dbgprintf("Set DISPLAY handler\n"); |
return err; |
}; |
} |
#define PCI_CLASS_REVISION 0x08 |
#define PCI_CLASS_DISPLAY_VGA 0x0300 |
int pci_scan_filter(u32_t id, u32_t busnr, u32_t devfn) |
{ |
u16_t vendor, device; |
u32_t class; |
int ret = 0; |
vendor = id & 0xffff; |
device = (id >> 16) & 0xffff; |
if(vendor == 0x1002) |
{ |
class = PciRead32(busnr, devfn, PCI_CLASS_REVISION); |
class >>= 16; |
if( class == PCI_CLASS_DISPLAY_VGA) |
ret = 1; |
} |
return ret; |
} |
/drivers/video/drm/radeon/radeon_display.c |
---|
33,6 → 33,23 |
#include <drm/drm_crtc_helper.h> |
#include <drm/drm_edid.h> |
/* Greatest common divisor */ |
unsigned long gcd(unsigned long a, unsigned long b) |
{ |
unsigned long r; |
if (a < b) |
swap(a, b); |
if (!b) |
return a; |
while ((r = a % b) != 0) { |
a = b; |
b = r; |
} |
return b; |
} |
static void avivo_crtc_load_lut(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
63,7 → 80,8 |
(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) |
153,8 → 171,14 |
NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS))); |
/* XXX match this to the depth of the crtc fmt block, move to modeset? */ |
WREG32(0x6940 + radeon_crtc->crtc_offset, 0); |
if (ASIC_IS_DCE8(rdev)) { |
/* XXX this only needs to be programmed once per crtc at startup, |
* not sure where the best place for it is |
*/ |
WREG32(CIK_ALPHA_CONTROL + radeon_crtc->crtc_offset, |
CIK_CURSOR_ALPHA_BLND_ENA); |
} |
} |
static void legacy_crtc_load_lut(struct drm_crtc *crtc) |
{ |
243,11 → 267,51 |
kfree(radeon_crtc); |
} |
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 = 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 = NULL, |
.cursor_move = NULL, |
.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 = NULL, |
}; |
268,6 → 332,16 |
radeon_crtc->crtc_id = index; |
rdev->mode_info.crtcs[index] = radeon_crtc; |
if (rdev->family >= CHIP_BONAIRE) { |
radeon_crtc->max_cursor_width = CIK_CURSOR_WIDTH; |
radeon_crtc->max_cursor_height = CIK_CURSOR_HEIGHT; |
} else { |
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; |
radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); |
286,7 → 360,7 |
radeon_legacy_init_crtc(dev, radeon_crtc); |
} |
static const char *encoder_names[37] = { |
static const char *encoder_names[38] = { |
"NONE", |
"INTERNAL_LVDS", |
"INTERNAL_TMDS1", |
323,7 → 397,8 |
"INTERNAL_UNIPHY2", |
"NUTMEG", |
"TRAVIS", |
"INTERNAL_VCE" |
"INTERNAL_VCE", |
"INTERNAL_UNIPHY3", |
}; |
static const char *hpd_names[6] = { |
348,7 → 423,7 |
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) { |
438,175 → 513,227 |
return ret; |
} |
int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) |
/* avivo */ |
/** |
* 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) |
{ |
struct drm_device *dev = radeon_connector->base.dev; |
struct radeon_device *rdev = dev->dev_private; |
int ret = 0; |
unsigned tmp; |
/* on hw with routers, select right port */ |
if (radeon_connector->router.ddc_valid) |
radeon_router_select_ddc_port(radeon_connector); |
/* reduce the numbers to a simpler ratio */ |
tmp = gcd(*nom, *den); |
*nom /= tmp; |
*den /= tmp; |
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) |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&dig->dp_i2c_bus->adapter); |
} 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) |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&dig->dp_i2c_bus->adapter); |
else if (radeon_connector->ddc_bus && !radeon_connector->edid) |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->adapter); |
} else { |
if (radeon_connector->ddc_bus && !radeon_connector->edid) |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->adapter); |
/* make sure nominator is large enough */ |
if (*nom < nom_min) { |
tmp = DIV_ROUND_UP(nom_min, *nom); |
*nom *= tmp; |
*den *= tmp; |
} |
if (!radeon_connector->edid) { |
if (rdev->is_atom_bios) { |
/* some laptops provide a hardcoded edid in rom for LCDs */ |
if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) || |
(radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP))) |
radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); |
} else |
/* some servers provide a hardcoded edid in rom for KVMs */ |
radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); |
/* make sure the denominator is large enough */ |
if (*den < den_min) { |
tmp = DIV_ROUND_UP(den_min, *den); |
*nom *= tmp; |
*den *= tmp; |
} |
if (radeon_connector->edid) { |
drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); |
ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); |
return ret; |
} |
drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); |
return 0; |
} |
/* 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) |
/** |
* 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 tmp = post_div * ref_div; |
/* limit reference * post divider to a maximum */ |
ref_div_max = max(min(100 / post_div, ref_div_max), 1u); |
tmp *= target_clock; |
*fb_div = tmp / pll->reference_freq; |
*frac_fb_div = tmp % pll->reference_freq; |
/* 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 (*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; |
/* 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; |
} |
} |
static u32 avivo_get_post_div(struct radeon_pll *pll, |
u32 target_clock) |
/** |
* 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, |
u32 *fb_div_p, |
u32 *frac_fb_div_p, |
u32 *ref_div_p, |
u32 *post_div_p) |
{ |
u32 vco, post_div, tmp; |
unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? |
freq : freq / 10; |
if (pll->flags & RADEON_PLL_USE_POST_DIV) |
return pll->post_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; |
if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { |
if (pll->flags & RADEON_PLL_IS_LCD) |
vco = pll->lcd_pll_out_min; |
/* 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) { |
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 |
vco = pll->pll_out_min; |
} else { |
if (pll->flags & RADEON_PLL_IS_LCD) |
vco = pll->lcd_pll_out_max; |
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 |
vco = pll->pll_out_max; |
} |
ref_div_max = pll->max_ref_div; |
post_div = vco / target_clock; |
tmp = vco % target_clock; |
/* 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_PREFER_MINM_OVER_MAXP) { |
if (tmp) |
post_div++; |
if (pll->flags & RADEON_PLL_IS_LCD) { |
vco_min = pll->lcd_pll_out_min; |
vco_max = pll->lcd_pll_out_max; |
} else { |
if (!tmp) |
post_div--; |
vco_min = pll->pll_out_min; |
vco_max = pll->pll_out_max; |
} |
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; |
if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { |
vco_min *= 10; |
vco_max *= 10; |
} |
return post_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; |
} |
#define MAX_TOLERANCE 10 |
/* represent the searched ratio as fractional number */ |
nom = target_clock; |
den = pll->reference_freq; |
void radeon_compute_pll_avivo(struct radeon_pll *pll, |
u32 freq, |
u32 *dot_clock_p, |
u32 *fb_div_p, |
u32 *frac_fb_div_p, |
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; |
/* reduce the numbers to a simpler ratio */ |
avivo_reduce_ratio(&nom, &den, fb_div_min, post_div_min); |
if (pll->flags & RADEON_PLL_USE_REF_DIV) |
ref_div = pll->reference_div; |
/* 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; |
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++; |
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; |
} |
if (frac_fb_div >= 10) { |
fb_div++; |
frac_fb_div = 0; |
} |
} 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; |
post_div = post_div_best; |
if (tmp > (10000 + MAX_TOLERANCE)) |
ref_div++; |
else if (tmp >= (10000 - MAX_TOLERANCE)) |
break; |
else |
ref_div++; |
/* 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; |
} |
} |
*dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) / |
/* 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_p * 10) + |
(pll->reference_freq * *frac_fb_div_p)) / |
(ref_div * post_div * 10); |
*fb_div_p = fb_div; |
*frac_fb_div_p = frac_fb_div; |
*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 */ |
809,6 → 936,9 |
{ |
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); |
if (radeon_fb->obj) { |
drm_gem_object_unreference_unlocked(radeon_fb->obj); |
} |
drm_framebuffer_cleanup(fb); |
kfree(radeon_fb); |
} |
874,6 → 1004,18 |
{ UNDERSCAN_AUTO, "auto" }, |
}; |
static struct drm_prop_enum_list radeon_audio_enum_list[] = |
{ { RADEON_AUDIO_DISABLE, "off" }, |
{ RADEON_AUDIO_ENABLE, "on" }, |
{ 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; |
924,6 → 1066,18 |
if (!rdev->mode_info.underscan_vborder_property) |
return -ENOMEM; |
sz = ARRAY_SIZE(radeon_audio_enum_list); |
rdev->mode_info.audio_property = |
drm_property_create_enum(rdev->ddev, 0, |
"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; |
} |
957,43 → 1111,43 |
for (i = 0; i < RADEON_MAX_AFMT_BLOCKS; i++) |
rdev->mode_info.afmt[i] = NULL; |
if (ASIC_IS_DCE6(rdev)) { |
/* todo */ |
if (ASIC_IS_NODCE(rdev)) { |
/* nothing to do */ |
} else if (ASIC_IS_DCE4(rdev)) { |
static uint32_t eg_offsets[] = { |
EVERGREEN_CRTC0_REGISTER_OFFSET, |
EVERGREEN_CRTC1_REGISTER_OFFSET, |
EVERGREEN_CRTC2_REGISTER_OFFSET, |
EVERGREEN_CRTC3_REGISTER_OFFSET, |
EVERGREEN_CRTC4_REGISTER_OFFSET, |
EVERGREEN_CRTC5_REGISTER_OFFSET, |
0x13830 - 0x7030, |
}; |
int num_afmt; |
/* DCE8 has 7 audio blocks tied to DIG encoders */ |
/* DCE6 has 6 audio blocks tied to DIG encoders */ |
/* DCE4/5 has 6 audio blocks tied to DIG encoders */ |
/* DCE4.1 has 2 audio blocks tied to DIG encoders */ |
rdev->mode_info.afmt[0] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
if (rdev->mode_info.afmt[0]) { |
rdev->mode_info.afmt[0]->offset = EVERGREEN_CRTC0_REGISTER_OFFSET; |
rdev->mode_info.afmt[0]->id = 0; |
if (ASIC_IS_DCE8(rdev)) |
num_afmt = 7; |
else if (ASIC_IS_DCE6(rdev)) |
num_afmt = 6; |
else if (ASIC_IS_DCE5(rdev)) |
num_afmt = 6; |
else if (ASIC_IS_DCE41(rdev)) |
num_afmt = 2; |
else /* DCE4 */ |
num_afmt = 6; |
BUG_ON(num_afmt > ARRAY_SIZE(eg_offsets)); |
for (i = 0; i < num_afmt; i++) { |
rdev->mode_info.afmt[i] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
if (rdev->mode_info.afmt[i]) { |
rdev->mode_info.afmt[i]->offset = eg_offsets[i]; |
rdev->mode_info.afmt[i]->id = i; |
} |
rdev->mode_info.afmt[1] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
if (rdev->mode_info.afmt[1]) { |
rdev->mode_info.afmt[1]->offset = EVERGREEN_CRTC1_REGISTER_OFFSET; |
rdev->mode_info.afmt[1]->id = 1; |
} |
if (!ASIC_IS_DCE41(rdev)) { |
rdev->mode_info.afmt[2] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
if (rdev->mode_info.afmt[2]) { |
rdev->mode_info.afmt[2]->offset = EVERGREEN_CRTC2_REGISTER_OFFSET; |
rdev->mode_info.afmt[2]->id = 2; |
} |
rdev->mode_info.afmt[3] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
if (rdev->mode_info.afmt[3]) { |
rdev->mode_info.afmt[3]->offset = EVERGREEN_CRTC3_REGISTER_OFFSET; |
rdev->mode_info.afmt[3]->id = 3; |
} |
rdev->mode_info.afmt[4] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
if (rdev->mode_info.afmt[4]) { |
rdev->mode_info.afmt[4]->offset = EVERGREEN_CRTC4_REGISTER_OFFSET; |
rdev->mode_info.afmt[4]->id = 4; |
} |
rdev->mode_info.afmt[5] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
if (rdev->mode_info.afmt[5]) { |
rdev->mode_info.afmt[5]->offset = EVERGREEN_CRTC5_REGISTER_OFFSET; |
rdev->mode_info.afmt[5]->id = 5; |
} |
} |
} else if (ASIC_IS_DCE3(rdev)) { |
/* DCE3.x has 2 audio blocks tied to DIG encoders */ |
rdev->mode_info.afmt[0] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
1039,6 → 1193,8 |
int i; |
int ret; |
ENTER(); |
drm_mode_config_init(rdev->ddev); |
rdev->mode_info.mode_config_initialized = true; |
1095,14 → 1251,12 |
// radeon_hpd_init(rdev); |
/* setup afmt */ |
// radeon_afmt_init(rdev); |
radeon_afmt_init(rdev); |
/* Initialize power management */ |
// radeon_pm_init(rdev); |
radeon_fbdev_init(rdev); |
// drm_kms_helper_poll_init(rdev->ddev); |
LEAVE(); |
return 0; |
} |
1181,7 → 1335,7 |
(!(mode->flags & DRM_MODE_FLAG_INTERLACE)) && |
((radeon_encoder->underscan_type == UNDERSCAN_ON) || |
((radeon_encoder->underscan_type == UNDERSCAN_AUTO) && |
drm_detect_hdmi_monitor(radeon_connector->edid) && |
drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && |
is_hdtv_mode(mode)))) { |
if (radeon_encoder->underscan_hborder != 0) |
radeon_crtc->h_border = radeon_encoder->underscan_hborder; |
1227,12 → 1381,18 |
} |
/* |
* 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 |
1248,7 → 1408,8 |
* 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, void *stime, void *etime) |
{ |
u32 stat_crtc = 0, vbl = 0, position = 0; |
int vbl_start, vbl_end, vtotal, ret = 0; |
1378,5 → 1539,27 |
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; |
} |
/drivers/video/drm/radeon/radeon_encoders.c |
---|
343,7 → 343,7 |
case DRM_MODE_CONNECTOR_HDMIB: |
if (radeon_connector->use_digital) { |
/* HDMI 1.3 supports up to 340 Mhz over single link */ |
if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { |
if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
if (pixel_clock > 340000) |
return true; |
else |
365,7 → 365,7 |
return false; |
else { |
/* HDMI 1.3 supports up to 340 Mhz over single link */ |
if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { |
if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
if (pixel_clock > 340000) |
return true; |
else |
/drivers/video/drm/radeon/radeon_family.h |
---|
93,6 → 93,11 |
CHIP_VERDE, |
CHIP_OLAND, |
CHIP_HAINAN, |
CHIP_BONAIRE, |
CHIP_KAVERI, |
CHIP_KABINI, |
CHIP_HAWAII, |
CHIP_MULLINS, |
CHIP_LAST, |
}; |
111,6 → 116,7 |
RADEON_NEW_MEMMAP = 0x00400000UL, |
RADEON_IS_PCI = 0x00800000UL, |
RADEON_IS_IGPGART = 0x01000000UL, |
RADEON_IS_PX = 0x02000000UL, |
}; |
#endif |
/drivers/video/drm/radeon/radeon_fb.c |
---|
35,11 → 35,9 |
#include <drm/drm_fb_helper.h> |
struct drm_framebuffer *main_fb; |
struct drm_gem_object *main_fb_obj; |
int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, |
struct drm_mode_fb_cmd2 *mode_cmd, |
struct drm_gem_object **gobj_p); |
/* object hierarchy - |
this contains a helper + a radeon fb |
the helper contains a pointer to radeon framebuffer baseclass. |
88,10 → 86,105 |
return aligned; |
} |
static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) |
{ |
struct radeon_bo *rbo = gem_to_radeon_bo(gobj); |
int ret; |
static int radeonfb_create(struct radeon_fbdev *rfbdev, |
ret = radeon_bo_reserve(rbo, false); |
if (likely(ret == 0)) { |
radeon_bo_kunmap(rbo); |
radeon_bo_unpin(rbo); |
radeon_bo_unreserve(rbo); |
} |
drm_gem_object_unreference_unlocked(gobj); |
} |
static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, |
struct drm_mode_fb_cmd2 *mode_cmd, |
struct drm_gem_object **gobj_p) |
{ |
struct radeon_device *rdev = rfbdev->rdev; |
struct drm_gem_object *gobj = NULL; |
struct radeon_bo *rbo = NULL; |
bool fb_tiled = false; /* useful for testing */ |
u32 tiling_flags = 0; |
int ret; |
int aligned_size, size; |
int height = mode_cmd->height; |
u32 bpp, depth; |
drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); |
/* need to align pitch with crtc limits */ |
mode_cmd->pitches[0] = radeon_align_pitch(rdev, mode_cmd->width, bpp, |
fb_tiled) * ((bpp + 1) / 8); |
if (rdev->family >= CHIP_R600) |
height = ALIGN(mode_cmd->height, 8); |
size = mode_cmd->pitches[0] * height; |
aligned_size = ALIGN(size, PAGE_SIZE); |
rbo = rdev->stollen_vga_memory; |
gobj = &rbo->gem_base; |
mutex_lock(&rdev->gem.mutex); |
list_add_tail(&rbo->list, &rdev->gem.objects); |
mutex_unlock(&rdev->gem.mutex); |
rbo = gem_to_radeon_bo(gobj); |
if (fb_tiled) |
tiling_flags = RADEON_TILING_MACRO; |
#ifdef __BIG_ENDIAN |
switch (bpp) { |
case 32: |
tiling_flags |= RADEON_TILING_SWAP_32BIT; |
break; |
case 16: |
tiling_flags |= RADEON_TILING_SWAP_16BIT; |
default: |
break; |
} |
#endif |
// if (tiling_flags) { |
// ret = radeon_bo_set_tiling_flags(rbo, |
// tiling_flags | RADEON_TILING_SURFACE, |
// mode_cmd->pitches[0]); |
// if (ret) |
// dev_err(rdev->dev, "FB failed to set tiling flags\n"); |
// } |
ret = radeon_bo_reserve(rbo, false); |
if (unlikely(ret != 0)) |
goto out_unref; |
/* Only 27 bit offset for legacy CRTC */ |
ret = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM, |
ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, |
NULL); |
if (ret) { |
radeon_bo_unreserve(rbo); |
goto out_unref; |
} |
radeon_bo_unreserve(rbo); |
if (ret) { |
goto out_unref; |
} |
*gobj_p = gobj; |
return 0; |
out_unref: |
radeonfb_destroy_pinned_object(gobj); |
*gobj_p = NULL; |
return ret; |
} |
static int radeonfb_create(struct drm_fb_helper *helper, |
struct drm_fb_helper_surface_size *sizes) |
{ |
struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper; |
struct radeon_device *rdev = rfbdev->rdev; |
struct fb_info *info; |
struct drm_framebuffer *fb = NULL; |
102,8 → 195,6 |
int ret; |
unsigned long tmp; |
ENTER(); |
mode_cmd.width = sizes->surface_width; |
mode_cmd.height = sizes->surface_height; |
125,7 → 216,6 |
/* okay we have an object now allocate the framebuffer */ |
info = framebuffer_alloc(0, device); |
if (info == NULL) { |
dbgprintf("framebuffer_alloc\n"); |
ret = -ENOMEM; |
goto out_unref; |
} |
134,7 → 224,7 |
ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); |
if (ret) { |
DRM_ERROR("failed to initalise framebuffer %d\n", ret); |
DRM_ERROR("failed to initialize framebuffer %d\n", ret); |
goto out_unref; |
} |
172,10 → 262,7 |
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ |
// if (info->screen_base == NULL) { |
// ret = -ENOSPC; |
// goto out_unref; |
// } |
DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); |
DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); |
DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo)); |
182,9 → 269,9 |
DRM_INFO("fb depth is %d\n", fb->depth); |
DRM_INFO(" pitch is %d\n", fb->pitches[0]); |
main_fb = fb; |
main_fb_obj = gobj; |
LEAVE(); |
return 0; |
out_unref: |
197,21 → 284,7 |
return ret; |
} |
static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper, |
struct drm_fb_helper_surface_size *sizes) |
{ |
struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper; |
int new_fb = 0; |
int ret; |
if (!helper->fb) { |
ret = radeonfb_create(rfbdev, sizes); |
if (ret) |
return ret; |
new_fb = 1; |
} |
return new_fb; |
} |
static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) |
{ |
struct fb_info *info; |
233,20 → 306,17 |
return 0; |
} |
static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { |
static const struct drm_fb_helper_funcs radeon_fb_helper_funcs = { |
.gamma_set = radeon_crtc_fb_gamma_set, |
.gamma_get = radeon_crtc_fb_gamma_get, |
.fb_probe = radeon_fb_find_or_create_single, |
.fb_probe = radeonfb_create, |
}; |
extern struct radeon_fbdev *kos_rfbdev; |
int radeon_fbdev_init(struct radeon_device *rdev) |
{ |
struct radeon_fbdev *rfbdev; |
int bpp_sel = 32; |
int ret; |
ENTER(); |
/* select 8 bpp console on RN50 or 16MB cards */ |
259,8 → 329,10 |
rfbdev->rdev = rdev; |
rdev->mode_info.rfbdev = rfbdev; |
rfbdev->helper.funcs = &radeon_fb_helper_funcs; |
drm_fb_helper_prepare(rdev->ddev, &rfbdev->helper, |
&radeon_fb_helper_funcs); |
ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper, |
rdev->num_crtc, |
RADEONFB_CONN_LIMIT); |
270,10 → 342,11 |
} |
drm_fb_helper_single_add_all_connectors(&rfbdev->helper); |
drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); |
kos_rfbdev = rfbdev; |
/* disable all the possible outputs/crtcs before entering KMS mode */ |
drm_helper_disable_unused_functions(rdev->ddev); |
drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); |
LEAVE(); |
return 0; |
/drivers/video/drm/radeon/radeon_fence.c |
---|
37,6 → 37,7 |
#include <drm/drmP.h> |
#include "radeon_reg.h" |
#include "radeon.h" |
#include "radeon_trace.h" |
/* |
* Fences |
120,7 → 121,7 |
(*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; |
} |
189,11 → 190,9 |
} |
} while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq); |
if (wake) { |
rdev->fence_drv[ring].last_activity = GetTimerTicks(); |
if (wake) |
wake_up_all(&rdev->fence_queue); |
} |
} |
/** |
* radeon_fence_destroy - destroy a fence |
211,13 → 210,13 |
} |
/** |
* 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 |
262,115 → 261,124 |
} |
/** |
* 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 (target_seq > atomic64_read(&rdev->fence_drv[ring].last_seq)) { |
if (!rdev->ring[ring].ready) { |
return -EBUSY; |
} |
while (!radeon_fence_any_seq_signaled(rdev, target_seq)) { |
timeout = GetTimerTicks() - 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; |
} 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; |
/* 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); |
} |
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); |
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 { |
r = wait_event_timeout(rdev->fence_queue, |
(signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)), |
timeout); |
r = wait_event_timeout(rdev->fence_queue, ( |
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)) |
|| rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT); |
} |
radeon_irq_kms_sw_irq_put(rdev, ring); |
if (unlikely(r < 0)) { |
return r; |
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]); |
} |
// trace_radeon_fence_wait_end(rdev->ddev, seq); |
if (unlikely(r < 0)) |
return r; |
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)) { |
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); |
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); |
/* 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 = GetTimerTicks(); |
} |
/* mark the ring as not ready any more */ |
rdev->ring[ring].ready = false; |
if (lock_ring) { |
mutex_unlock(&rdev->ring_lock); |
} |
/* 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; |
} |
387,6 → 395,7 |
*/ |
int radeon_fence_wait(struct radeon_fence *fence, bool intr) |
{ |
uint64_t seq[RADEON_NUM_RINGS] = {}; |
int r; |
if (fence == NULL) { |
394,147 → 403,15 |
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; |
seq[fence->ring] = fence->seq; |
if (seq[fence->ring] == 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 = GetTimerTicks() - 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)) { |
r = radeon_fence_wait_seq(fence->rdev, seq, intr); |
if (r) |
return r; |
} |
// trace_radeon_fence_wait_end(rdev->ddev, seq); |
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 = GetTimerTicks(); |
} |
/* 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; |
} |
556,7 → 433,7 |
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) { |
566,15 → 443,19 |
continue; |
} |
if (fences[i]->seq == RADEON_FENCE_SIGNALED_SEQ) { |
/* something was allready signaled */ |
seq[i] = fences[i]->seq; |
++num_rings; |
/* test if something was allready signaled */ |
if (seq[i] == RADEON_FENCE_SIGNALED_SEQ) |
return 0; |
} |
seq[i] = fences[i]->seq; |
} |
/* nothing to wait for ? */ |
if (num_rings == 0) |
return -ENOENT; |
r = radeon_fence_wait_any_seq(rdev, seq, intr); |
r = radeon_fence_wait_seq(rdev, seq, intr); |
if (r) { |
return r; |
} |
582,7 → 463,7 |
} |
/** |
* 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 |
591,21 → 472,21 |
* 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 |
614,16 → 495,20 |
* 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); |
} |
825,7 → 710,6 |
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 = GetTimerTicks(); |
rdev->fence_drv[ring].initialized = false; |
} |
871,7 → 755,7 |
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); |
918,6 → 802,8 |
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)); |
933,8 → 819,28 |
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 |
941,7 → 847,7 |
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 |
/drivers/video/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" |
static inline void * |
138,7 → 137,7 |
if (rdev->gart.robj == NULL) { |
r = radeon_bo_create(rdev, rdev->gart.table_size, |
PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, |
NULL, &rdev->gart.robj); |
0, NULL, &rdev->gart.robj); |
if (r) { |
return r; |
} |
216,7 → 215,6 |
if (rdev->gart.robj == NULL) { |
return; |
} |
radeon_gart_table_vram_unpin(rdev); |
radeon_bo_unref(&rdev->gart.robj); |
} |
254,7 → 252,8 |
page_base = rdev->gart.pages_addr[p]; |
for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { |
if (rdev->gart.ptr) { |
radeon_gart_set_page(rdev, t, page_base); |
radeon_gart_set_page(rdev, t, page_base, |
RADEON_GART_PAGE_DUMMY); |
} |
page_base += RADEON_GPU_PAGE_SIZE; |
} |
272,6 → 271,7 |
* @pages: number of pages to bind |
* @pagelist: pages to bind |
* @dma_addr: DMA addresses of pages |
* @flags: RADEON_GART_PAGE_* flags |
* |
* Binds the requested pages to the gart page table |
* (all asics). |
278,7 → 278,8 |
* Returns 0 for success, -EINVAL for failure. |
*/ |
int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, |
int pages, u32 *pagelist, dma_addr_t *dma_addr) |
int pages, struct page **pagelist, dma_addr_t *dma_addr, |
uint32_t flags) |
{ |
unsigned t; |
unsigned p; |
285,8 → 286,6 |
uint64_t page_base; |
int i, j; |
// dbgprintf("offset %x pages %d list %x\n", |
// offset, pages, pagelist); |
if (!rdev->gart.ready) { |
WARN(1, "trying to bind memory to uninitialized GART !\n"); |
return -EINVAL; |
295,12 → 294,12 |
p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); |
for (i = 0; i < pages; i++, p++) { |
rdev->gart.pages_addr[p] = pagelist[i] & ~4095; |
rdev->gart.pages_addr[p] = dma_addr[i]; |
rdev->gart.pages[p] = pagelist[i]; |
if (rdev->gart.ptr) { |
page_base = rdev->gart.pages_addr[p]; |
for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { |
radeon_gart_set_page(rdev, t, page_base); |
radeon_gart_set_page(rdev, t, page_base, flags); |
page_base += RADEON_GPU_PAGE_SIZE; |
} |
} |
311,33 → 310,6 |
} |
/** |
* radeon_gart_restore - bind all pages in the gart page table |
* |
* @rdev: radeon_device pointer |
* |
* Binds all pages in the gart page table (all asics). |
* Used to rebuild the gart table on device startup or resume. |
*/ |
void radeon_gart_restore(struct radeon_device *rdev) |
{ |
int i, j, t; |
u64 page_base; |
if (!rdev->gart.ptr) { |
return; |
} |
for (i = 0, t = 0; i < rdev->gart.num_cpu_pages; i++) { |
page_base = rdev->gart.pages_addr[i]; |
for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { |
radeon_gart_set_page(rdev, t, page_base); |
page_base += RADEON_GPU_PAGE_SIZE; |
} |
} |
mb(); |
radeon_gart_tlb_flush(rdev); |
} |
/** |
* radeon_gart_init - init the driver info for managing the gart |
* |
* @rdev: radeon_device pointer |
402,894 → 374,6 |
vfree(rdev->gart.pages_addr); |
rdev->gart.pages = NULL; |
rdev->gart.pages_addr = NULL; |
} |
/* |
* 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_dummy_page_fini(rdev); |
} |
/** |
* 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_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_GPU_PAGE_ALIGN(radeon_vm_directory_size(rdev)); |
r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, |
&vm->page_directory, pd_size, |
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; |
} |
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); |
} |
/drivers/video/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); |
45,9 → 38,9 |
} |
} |
int radeon_gem_object_create(struct radeon_device *rdev, int size, |
int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size, |
int alignment, int initial_domain, |
bool discardable, bool kernel, |
u32 flags, bool kernel, |
struct drm_gem_object **obj) |
{ |
struct radeon_bo *robj; |
60,16 → 53,19 |
alignment = PAGE_SIZE; |
} |
/* maximun bo size is the minimun btw visible vram and gtt size */ |
max_size = min(rdev->mc.visible_vram_size, rdev->mc.gtt_size); |
/* Maximum bo size is the unpinned gtt size since we use the gtt to |
* handle vram to system pool migrations. |
*/ |
max_size = rdev->mc.gtt_size - rdev->gart_pin_size; |
if (size > max_size) { |
printk(KERN_WARNING "%s:%d alloc size %dMb bigger than %ldMb limit\n", |
__func__, __LINE__, size >> 20, max_size >> 20); |
DRM_DEBUG("Allocation size %ldMb bigger than %ldMb limit\n", |
size >> 20, max_size >> 20); |
return -ENOMEM; |
} |
retry: |
r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, NULL, &robj); |
r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, |
flags, NULL, &robj); |
if (r) { |
if (r != -ERESTARTSYS) { |
if (initial_domain == RADEON_GEM_DOMAIN_VRAM) { |
76,7 → 72,7 |
initial_domain |= RADEON_GEM_DOMAIN_GTT; |
goto retry; |
} |
DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n", |
DRM_ERROR("Failed to allocate GEM object (%ld, %d, %u, %d)\n", |
size, initial_domain, alignment, r); |
} |
return r; |
90,33 → 86,7 |
return 0; |
} |
int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain, |
uint64_t *gpu_addr) |
{ |
struct radeon_bo *robj = gem_to_radeon_bo(obj); |
int r; |
r = radeon_bo_reserve(robj, false); |
if (unlikely(r != 0)) |
return r; |
r = radeon_bo_pin(robj, pin_domain, gpu_addr); |
radeon_bo_unreserve(robj); |
return r; |
} |
void radeon_gem_object_unpin(struct drm_gem_object *obj) |
{ |
struct radeon_bo *robj = gem_to_radeon_bo(obj); |
int r; |
r = radeon_bo_reserve(robj, false); |
if (likely(r == 0)) { |
radeon_bo_unpin(robj); |
radeon_bo_unreserve(robj); |
} |
} |
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; |
167,18 → 137,15 |
struct radeon_device *rdev = dev->dev_private; |
struct drm_radeon_gem_info *args = data; |
struct ttm_mem_type_manager *man; |
unsigned i; |
man = &rdev->mman.bdev.man[TTM_PL_VRAM]; |
args->vram_size = rdev->mc.real_vram_size; |
args->vram_visible = (u64)man->size << PAGE_SHIFT; |
if (rdev->stollen_vga_memory) |
args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory); |
args->vram_visible -= radeon_fbdev_total_size(rdev); |
args->gart_size = rdev->mc.gtt_size - 4096 - RADEON_IB_POOL_SIZE*64*1024; |
for(i = 0; i < RADEON_NUM_RINGS; ++i) |
args->gart_size -= rdev->ring[i].ring_size; |
args->vram_visible -= rdev->vram_pin_size; |
args->gart_size = rdev->mc.gtt_size; |
args->gart_size -= rdev->gart_pin_size; |
return 0; |
} |
211,7 → 178,7 |
/* create a gem object to contain this object in */ |
args->size = roundup(args->size, PAGE_SIZE); |
r = radeon_gem_object_create(rdev, args->size, args->alignment, |
args->initial_domain, false, |
args->initial_domain, args->flags, |
false, &gobj); |
if (r) { |
up_read(&rdev->exclusive_lock); |
303,18 → 270,7 |
} |
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; |
328,6 → 284,7 |
struct drm_gem_object *gobj; |
struct radeon_bo *robj; |
int r; |
uint32_t cur_placement = 0; |
gobj = drm_gem_object_lookup(dev, filp, args->handle); |
if (gobj == NULL) { |
334,10 → 291,11 |
return -ENOENT; |
} |
robj = gem_to_radeon_bo(gobj); |
r = radeon_bo_wait(robj, NULL, false); |
/* callback hw specific functions if any */ |
if (rdev->asic->ioctl_wait_idle) |
robj->rdev->asic->ioctl_wait_idle(rdev, robj); |
r = radeon_bo_wait(robj, &cur_placement, false); |
/* Flush HDP cache via MMIO if necessary */ |
if (rdev->asic->mmio_hdp_flush && |
radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM) |
robj->rdev->asic->mmio_hdp_flush(rdev); |
drm_gem_object_unreference_unlocked(gobj); |
r = radeon_gem_handle_lockup(rdev, r); |
return r; |
/drivers/video/drm/radeon/radeon_i2c.c |
---|
64,8 → 64,7 |
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 |
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 |
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 |
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 |
break; |
} |
mutex_unlock(&i2c->mutex); |
return ret; |
} |
919,6 → 926,7 |
i2c->adapter.class = I2C_CLASS_DDC; |
i2c->dev = dev; |
i2c_set_adapdata(&i2c->adapter, i2c); |
mutex_init(&i2c->mutex); |
if (rec->mm_i2c || |
(rec->hw_capable && |
radeon_hw_i2c && |
949,16 → 957,16 |
/* 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); |
973,45 → 981,13 |
} |
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->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); |
} |
1018,6 → 994,9 |
/* 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 |
/drivers/video/drm/radeon/radeon_ib.c |
---|
0,0 → 1,320 |
/* |
* 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 |
* Christian König |
*/ |
#include <drm/drmP.h> |
#include "radeon.h" |
/* |
* IB |
* IBs (Indirect Buffers) and areas of GPU accessible memory where |
* commands are stored. You can put a pointer to the IB in the |
* command ring and the hw will fetch the commands from the IB |
* and execute them. Generally userspace acceleration drivers |
* produce command buffers which are send to the kernel and |
* put in IBs for execution by the requested ring. |
*/ |
static int radeon_debugfs_sa_init(struct radeon_device *rdev); |
/** |
* radeon_ib_get - request an IB (Indirect Buffer) |
* |
* @rdev: radeon_device pointer |
* @ring: ring index the IB is associated with |
* @ib: IB object returned |
* @size: requested IB size |
* |
* Request an IB (all asics). IBs are allocated using the |
* suballocator. |
* Returns 0 on success, error on failure. |
*/ |
int radeon_ib_get(struct radeon_device *rdev, int ring, |
struct radeon_ib *ib, struct radeon_vm *vm, |
unsigned size) |
{ |
int r; |
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; |
} |
r = radeon_semaphore_create(rdev, &ib->semaphore); |
if (r) { |
return r; |
} |
ib->ring = ring; |
ib->fence = NULL; |
ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo); |
ib->vm = vm; |
if (vm) { |
/* ib pool is bound at RADEON_VA_IB_OFFSET in virtual address |
* space and soffset is the offset inside the pool bo |
*/ |
ib->gpu_addr = ib->sa_bo->soffset + RADEON_VA_IB_OFFSET; |
} else { |
ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo); |
} |
ib->is_const_ib = false; |
return 0; |
} |
/** |
* radeon_ib_free - free an IB (Indirect Buffer) |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to free |
* |
* Free an IB (all asics). |
*/ |
void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
radeon_semaphore_free(rdev, &ib->semaphore, ib->fence); |
radeon_sa_bo_free(rdev, &ib->sa_bo, ib->fence); |
radeon_fence_unref(&ib->fence); |
} |
/** |
* radeon_ib_schedule - schedule an IB (Indirect Buffer) on the ring |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to schedule |
* @const_ib: Const IB to schedule (SI only) |
* @hdp_flush: Whether or not to perform an HDP cache flush |
* |
* Schedule an IB on the associated ring (all asics). |
* Returns 0 on success, error on failure. |
* |
* On SI, there are two parallel engines fed from the primary ring, |
* the CE (Constant Engine) and the DE (Drawing Engine). Since |
* resource descriptors have moved to memory, the CE allows you to |
* prime the caches while the DE is updating register state so that |
* the resource descriptors will be already in cache when the draw is |
* processed. To accomplish this, the userspace driver submits two |
* IBs, one for the CE and one for the DE. If there is a CE IB (called |
* a CONST_IB), it will be put on the ring prior to the DE IB. Prior |
* to SI there was just a DE IB. |
*/ |
int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, |
struct radeon_ib *const_ib, bool hdp_flush) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
int r = 0; |
if (!ib->length_dw || !ring->ready) { |
/* TODO: Nothings in the ib we should report. */ |
dev_err(rdev->dev, "couldn't schedule ib\n"); |
return -EINVAL; |
} |
/* 64 dwords should be enough for fence too */ |
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; |
} |
/* 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); |
} |
/* 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); |
} |
radeon_ring_ib_execute(rdev, ib->ring, ib); |
r = radeon_fence_emit(rdev, &ib->fence, ib->ring); |
if (r) { |
dev_err(rdev->dev, "failed to emit fence for new IB (%d)\n", r); |
radeon_ring_unlock_undo(rdev, ring); |
return r; |
} |
if (const_ib) { |
const_ib->fence = radeon_fence_ref(ib->fence); |
} |
if (ib->vm) |
radeon_vm_fence(rdev, ib->vm, ib->fence); |
radeon_ring_unlock_commit(rdev, ring, hdp_flush); |
return 0; |
} |
/** |
* radeon_ib_pool_init - Init the IB (Indirect Buffer) pool |
* |
* @rdev: radeon_device pointer |
* |
* Initialize the suballocator to manage a pool of memory |
* for use as IBs (all asics). |
* Returns 0 on success, error on failure. |
*/ |
int radeon_ib_pool_init(struct radeon_device *rdev) |
{ |
int r; |
if (rdev->ib_pool_ready) { |
return 0; |
} |
if (rdev->family >= CHIP_BONAIRE) { |
r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo, |
RADEON_IB_POOL_SIZE*64*1024, |
RADEON_GPU_PAGE_SIZE, |
RADEON_GEM_DOMAIN_GTT, |
RADEON_GEM_GTT_WC); |
} else { |
/* Before CIK, it's better to stick to cacheable GTT due |
* to the command stream checking |
*/ |
r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo, |
RADEON_IB_POOL_SIZE*64*1024, |
RADEON_GPU_PAGE_SIZE, |
RADEON_GEM_DOMAIN_GTT, 0); |
} |
if (r) { |
return r; |
} |
r = radeon_sa_bo_manager_start(rdev, &rdev->ring_tmp_bo); |
if (r) { |
return r; |
} |
rdev->ib_pool_ready = true; |
if (radeon_debugfs_sa_init(rdev)) { |
dev_err(rdev->dev, "failed to register debugfs file for SA\n"); |
} |
return 0; |
} |
/** |
* radeon_ib_pool_fini - Free the IB (Indirect Buffer) pool |
* |
* @rdev: radeon_device pointer |
* |
* Tear down the suballocator managing the pool of memory |
* for use as IBs (all asics). |
*/ |
void radeon_ib_pool_fini(struct radeon_device *rdev) |
{ |
if (rdev->ib_pool_ready) { |
radeon_sa_bo_manager_suspend(rdev, &rdev->ring_tmp_bo); |
radeon_sa_bo_manager_fini(rdev, &rdev->ring_tmp_bo); |
rdev->ib_pool_ready = false; |
} |
} |
/** |
* radeon_ib_ring_tests - test IBs on the rings |
* |
* @rdev: radeon_device pointer |
* |
* Test an IB (Indirect Buffer) on each ring. |
* If the test fails, disable the ring. |
* Returns 0 on success, error if the primary GFX ring |
* IB test fails. |
*/ |
int radeon_ib_ring_tests(struct radeon_device *rdev) |
{ |
unsigned i; |
int r; |
for (i = 0; i < RADEON_NUM_RINGS; ++i) { |
struct radeon_ring *ring = &rdev->ring[i]; |
if (!ring->ready) |
continue; |
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 */ |
DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r); |
rdev->accel_working = false; |
return r; |
} else { |
/* still not good, but we can live with it */ |
DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r); |
} |
} |
} |
return 0; |
} |
/* |
* Debugfs info |
*/ |
#if defined(CONFIG_DEBUG_FS) |
static int radeon_debugfs_sa_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; |
radeon_sa_bo_dump_debug_info(&rdev->ring_tmp_bo, m); |
return 0; |
} |
static struct drm_info_list radeon_debugfs_sa_list[] = { |
{"radeon_sa_info", &radeon_debugfs_sa_info, 0, NULL}, |
}; |
#endif |
static int radeon_debugfs_sa_init(struct radeon_device *rdev) |
{ |
#if defined(CONFIG_DEBUG_FS) |
return radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1); |
#else |
return 0; |
#endif |
} |
/drivers/video/drm/radeon/radeon_irq_kms.c |
---|
41,13 → 41,13 |
/** |
* 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; |
73,6 → 73,7 |
/* Disable *all* interrupts */ |
for (i = 0; i < RADEON_NUM_RINGS; i++) |
atomic_set(&rdev->irq.ring_int[i], 0); |
rdev->irq.dpm_thermal = false; |
for (i = 0; i < RADEON_MAX_HPD_PINS; i++) |
rdev->irq.hpd[i] = false; |
for (i = 0; i < RADEON_MAX_CRTCS; i++) { |
120,6 → 121,7 |
/* Disable *all* interrupts */ |
for (i = 0; i < RADEON_NUM_RINGS; i++) |
atomic_set(&rdev->irq.ring_int[i], 0); |
rdev->irq.dpm_thermal = false; |
for (i = 0; i < RADEON_MAX_HPD_PINS; i++) |
rdev->irq.hpd[i] = false; |
for (i = 0; i < RADEON_MAX_CRTCS; i++) { |
143,23 → 145,20 |
*/ |
int radeon_irq_kms_init(struct radeon_device *rdev) |
{ |
int irq_line; |
int r = 0; |
ENTER(); |
spin_lock_init(&rdev->irq.lock); |
/* enable msi */ |
rdev->msi_enabled = 0; |
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; |
FAIL(); |
return r; |
} |
DRM_INFO("radeon: irq initialized.\n"); |
return 0; |
} |
180,7 → 179,6 |
// if (rdev->msi_enabled) |
// pci_disable_msi(rdev->pdev); |
} |
// flush_work(&rdev->hotplug_work); |
} |
/** |
244,6 → 242,9 |
unsigned long irqflags; |
int i; |
if (!rdev->ddev->irq_enabled) |
return; |
spin_lock_irqsave(&rdev->irq.lock, irqflags); |
for (i = 0; i < RADEON_MAX_HPD_PINS; ++i) |
rdev->irq.hpd[i] |= !!(hpd_mask & (1 << i)); |
264,6 → 265,9 |
unsigned long irqflags; |
int i; |
if (!rdev->ddev->irq_enabled) |
return; |
spin_lock_irqsave(&rdev->irq.lock, irqflags); |
for (i = 0; i < RADEON_MAX_HPD_PINS; ++i) |
rdev->irq.hpd[i] &= !(hpd_mask & (1 << i)); |
271,59 → 275,3 |
spin_unlock_irqrestore(&rdev->irq.lock, irqflags); |
} |
static struct drm_driver drm_driver = { |
.irq_preinstall = radeon_driver_irq_preinstall_kms, |
.irq_postinstall = radeon_driver_irq_postinstall_kms, |
.irq_handler = radeon_driver_irq_handler_kms |
}; |
static struct drm_driver *driver = &drm_driver; |
int drm_irq_install(struct drm_device *dev) |
{ |
unsigned long sh_flags = 0; |
int irq_line; |
int ret = 0; |
char *irqname; |
mutex_lock(&dev->struct_mutex); |
/* Driver must have been initialized */ |
if (!dev->dev_private) { |
mutex_unlock(&dev->struct_mutex); |
return -EINVAL; |
} |
if (dev->irq_enabled) { |
mutex_unlock(&dev->struct_mutex); |
return -EBUSY; |
} |
dev->irq_enabled = 1; |
mutex_unlock(&dev->struct_mutex); |
irq_line = drm_dev_to_irq(dev); |
DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); |
/* Before installing handler */ |
if (driver->irq_preinstall) |
driver->irq_preinstall(dev); |
ret = AttachIntHandler(irq_line, driver->irq_handler, (u32)dev); |
/* After installing handler */ |
if (driver->irq_postinstall) |
ret = driver->irq_postinstall(dev); |
if (ret < 0) { |
DRM_ERROR(__FUNCTION__); |
} |
u16_t cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4); |
cmd&= ~(1<<10); |
PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd); |
return ret; |
} |
/drivers/video/drm/radeon/radeon_legacy_crtc.c |
---|
385,7 → 385,7 |
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 |
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 |
/* 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 |
&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 |
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 |
} |
} |
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_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 |
.prepare = radeon_crtc_prepare, |
.commit = radeon_crtc_commit, |
.load_lut = radeon_crtc_load_lut, |
.disable = radeon_crtc_disable |
}; |
/drivers/video/drm/radeon/radeon_legacy_encoders.c |
---|
392,7 → 392,7 |
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"); |
/drivers/video/drm/radeon/radeon_mode.h |
---|
46,6 → 46,10 |
#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_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 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 */ |
225,6 → 229,7 |
int offset; |
bool last_buffer_filled_status; |
int id; |
struct r600_audio_pin *pin; |
}; |
struct radeon_mode_info { |
232,8 → 237,8 |
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[6]; |
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 */ |
246,6 → 251,10 |
struct drm_property *underscan_property; |
struct drm_property *underscan_hborder_property; |
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; |
286,6 → 295,7 |
struct radeon_atom_ss { |
uint16_t percentage; |
uint16_t percentage_divider; |
uint8_t type; |
uint16_t step; |
uint8_t delay; |
296,6 → 306,12 |
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; |
307,6 → 323,8 |
uint64_t cursor_addr; |
int cursor_width; |
int cursor_height; |
int max_cursor_width; |
int max_cursor_height; |
uint32_t legacy_display_base_addr; |
uint32_t legacy_cursor_offset; |
enum radeon_rmx_type rmx_type; |
316,7 → 334,10 |
fixed20_12 hsc; |
struct drm_display_mode native_mode; |
int pll_id; |
int deferred_flip_completion; |
/* page flipping */ |
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; |
327,6 → 348,11 |
u32 pll_flags; |
struct drm_encoder *encoder; |
struct drm_connector *connector; |
/* for dpm */ |
u32 line_time; |
u32 wm_low; |
u32 wm_high; |
struct drm_display_mode hw_mode; |
}; |
struct radeon_encoder_primary_dac { |
424,7 → 450,6 |
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; |
461,6 → 486,17 |
u8 cd_mux_state; |
}; |
enum radeon_connector_audio { |
RADEON_AUDIO_DISABLE = 0, |
RADEON_AUDIO_ENABLE = 1, |
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; |
479,6 → 515,9 |
struct radeon_hpd hpd; |
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 { |
510,13 → 549,133 |
bool enable_dithen; |
u32 vco_mode; |
u32 real_clock; |
/* added for CI */ |
u32 post_divider; |
u32 flags; |
}; |
struct atom_mpll_param { |
union { |
struct { |
#ifdef __BIG_ENDIAN |
u32 reserved : 8; |
u32 clkfrac : 12; |
u32 clkf : 12; |
#else |
u32 clkf : 12; |
u32 clkfrac : 12; |
u32 reserved : 8; |
#endif |
}; |
u32 fb_div; |
}; |
u32 post_div; |
u32 bwcntl; |
u32 dll_speed; |
u32 vco_mode; |
u32 yclk_sel; |
u32 qdr; |
u32 half_rate; |
}; |
#define MEM_TYPE_GDDR5 0x50 |
#define MEM_TYPE_GDDR4 0x40 |
#define MEM_TYPE_GDDR3 0x30 |
#define MEM_TYPE_DDR2 0x20 |
#define MEM_TYPE_GDDR1 0x10 |
#define MEM_TYPE_DDR3 0xb0 |
#define MEM_TYPE_MASK 0xf0 |
struct atom_memory_info { |
u8 mem_vendor; |
u8 mem_type; |
}; |
#define MAX_AC_TIMING_ENTRIES 16 |
struct atom_memory_clock_range_table |
{ |
u8 num_entries; |
u8 rsv[3]; |
u32 mclk[MAX_AC_TIMING_ENTRIES]; |
}; |
#define VBIOS_MC_REGISTER_ARRAY_SIZE 32 |
#define VBIOS_MAX_AC_TIMING_ENTRIES 20 |
struct atom_mc_reg_entry { |
u32 mclk_max; |
u32 mc_data[VBIOS_MC_REGISTER_ARRAY_SIZE]; |
}; |
struct atom_mc_register_address { |
u16 s1; |
u8 pre_reg_data; |
}; |
struct atom_mc_reg_table { |
u8 last; |
u8 num_entries; |
struct atom_mc_reg_entry mc_reg_table_entry[VBIOS_MAX_AC_TIMING_ENTRIES]; |
struct atom_mc_register_address mc_reg_address[VBIOS_MC_REGISTER_ARRAY_SIZE]; |
}; |
#define MAX_VOLTAGE_ENTRIES 32 |
struct atom_voltage_table_entry |
{ |
u16 value; |
u32 smio_low; |
}; |
struct atom_voltage_table |
{ |
u32 count; |
u32 mask_low; |
u32 phase_delay; |
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 |
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 * |
526,10 → 685,11 |
extern u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder); |
extern u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector); |
extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector); |
extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector); |
extern int radeon_get_monitor_bpc(struct drm_connector *connector); |
extern struct edid *radeon_connector_edid(struct drm_connector *connector); |
extern void radeon_connector_hotplug(struct drm_connector *connector); |
extern int radeon_dp_mode_valid_helper(struct drm_connector *connector, |
struct drm_display_mode *mode); |
542,6 → 702,9 |
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); |
550,8 → 713,7 |
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); |
562,9 → 724,6 |
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); |
580,7 → 739,6 |
extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); |
extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); |
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux); |
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); |
extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); |
652,7 → 810,9 |
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, void *stime, |
void *etime); |
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); |
extern struct edid * |
744,6 → 904,12 |
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); |
753,6 → 919,7 |
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); |
/drivers/video/drm/radeon/radeon_object.c |
---|
0,0 → 1,689 |
/* |
* Copyright 2009 Jerome Glisse. |
* 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: |
* Jerome Glisse <glisse@freedesktop.org> |
* Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> |
* Dave Airlie |
*/ |
#include <linux/list.h> |
#include <linux/slab.h> |
#include <drm/drmP.h> |
#include <drm/radeon_drm.h> |
#include "radeon.h" |
#include "radeon_trace.h" |
int radeon_ttm_init(struct radeon_device *rdev); |
void radeon_ttm_fini(struct radeon_device *rdev); |
static void radeon_bo_clear_surface_reg(struct radeon_bo *bo); |
/* |
* To exclude mutual BO access we rely on bo_reserve exclusion, as all |
* function are calling it. |
*/ |
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) |
__atomic_add_fetch(&rdev->gtt_usage.counter, size,__ATOMIC_RELAXED); |
else |
__atomic_sub_fetch(&rdev->gtt_usage.counter, size,__ATOMIC_RELAXED); |
break; |
case TTM_PL_VRAM: |
if (sign > 0) |
__atomic_add_fetch(&rdev->vram_usage.counter, size,__ATOMIC_RELAXED); |
else |
__atomic_sub_fetch(&rdev->vram_usage.counter, size,__ATOMIC_RELAXED ); |
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); |
radeon_bo_clear_surface_reg(bo); |
WARN_ON(!list_empty(&bo->va)); |
drm_gem_object_release(&bo->gem_base); |
kfree(bo); |
} |
bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo) |
{ |
if (bo->destroy == &radeon_ttm_bo_destroy) |
return true; |
return false; |
} |
void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) |
{ |
u32 c = 0, i; |
rbo->placement.fpfn = 0; |
rbo->placement.lpfn = 0; |
rbo->placement.placement = rbo->placements; |
rbo->placement.busy_placement = rbo->placements; |
if (domain & RADEON_GEM_DOMAIN_VRAM) |
rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | |
TTM_PL_FLAG_VRAM; |
if (domain & RADEON_GEM_DOMAIN_GTT) { |
if (rbo->flags & RADEON_GEM_GTT_UC) { |
rbo->placements[c++] = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_TT; |
} else if ((rbo->flags & RADEON_GEM_GTT_WC) || |
(rbo->rdev->flags & RADEON_IS_AGP)) { |
rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | |
TTM_PL_FLAG_TT; |
} else { |
rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT; |
} |
} |
if (domain & RADEON_GEM_DOMAIN_CPU) { |
if (rbo->flags & RADEON_GEM_GTT_UC) { |
rbo->placements[c++] = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_SYSTEM; |
} else if ((rbo->flags & RADEON_GEM_GTT_WC) || |
rbo->rdev->flags & RADEON_IS_AGP) { |
rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | |
TTM_PL_FLAG_SYSTEM; |
} else { |
rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM; |
} |
} |
if (!c) |
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, |
unsigned long size, int byte_align, bool kernel, u32 domain, |
u32 flags, struct sg_table *sg, struct radeon_bo **bo_ptr) |
{ |
struct radeon_bo *bo; |
enum ttm_bo_type type; |
unsigned long page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT; |
size_t acc_size; |
int r; |
size = ALIGN(size, PAGE_SIZE); |
if (kernel) { |
type = ttm_bo_type_kernel; |
} else if (sg) { |
type = ttm_bo_type_sg; |
} else { |
type = ttm_bo_type_device; |
} |
*bo_ptr = NULL; |
acc_size = ttm_bo_dma_acc_size(&rdev->mman.bdev, size, |
sizeof(struct radeon_bo)); |
bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL); |
if (bo == NULL) |
return -ENOMEM; |
r = drm_gem_object_init(rdev->ddev, &bo->gem_base, size); |
if (unlikely(r)) { |
kfree(bo); |
return r; |
} |
bo->rdev = 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); |
bo->flags = flags; |
/* PCI GART is always snooped */ |
if (!(rdev->flags & RADEON_IS_PCIE)) |
bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); |
// printf("%s rdev->flags %x bo->flags %x\n", |
// __FUNCTION__, bo->flags); |
if(flags & RADEON_GEM_GTT_WC) |
bo->flags&= ~RADEON_GEM_GTT_WC; |
radeon_ttm_placement_from_domain(bo, domain); |
/* Kernel allocation are uninterruptible */ |
// down_read(&rdev->pm.mclk_lock); |
r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, |
&bo->placement, page_align, !kernel, NULL, |
acc_size, sg, &radeon_ttm_bo_destroy); |
// up_read(&rdev->pm.mclk_lock); |
if (unlikely(r != 0)) { |
return r; |
} |
*bo_ptr = bo; |
trace_radeon_bo_create(bo); |
return 0; |
} |
int radeon_bo_kmap(struct radeon_bo *bo, void **ptr) |
{ |
bool is_iomem; |
int r; |
if (bo->kptr) { |
if (ptr) { |
*ptr = bo->kptr; |
} |
return 0; |
} |
r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, &bo->kmap); |
if (r) { |
return r; |
} |
bo->kptr = ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); |
if (ptr) { |
*ptr = bo->kptr; |
} |
radeon_bo_check_tiling(bo, 0, 0); |
return 0; |
} |
void radeon_bo_kunmap(struct radeon_bo *bo) |
{ |
if (bo->kptr == NULL) |
return; |
bo->kptr = NULL; |
radeon_bo_check_tiling(bo, 0, 0); |
ttm_bo_kunmap(&bo->kmap); |
} |
struct radeon_bo *radeon_bo_ref(struct radeon_bo *bo) |
{ |
if (bo == NULL) |
return NULL; |
ttm_bo_reference(&bo->tbo); |
return bo; |
} |
void radeon_bo_unref(struct radeon_bo **bo) |
{ |
struct ttm_buffer_object *tbo; |
struct radeon_device *rdev; |
if ((*bo) == NULL) |
return; |
rdev = (*bo)->rdev; |
tbo = &((*bo)->tbo); |
ttm_bo_unref(&tbo); |
if (tbo == NULL) |
*bo = NULL; |
} |
int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, |
u64 *gpu_addr) |
{ |
int r, i; |
if (bo->pin_count) { |
bo->pin_count++; |
if (gpu_addr) |
*gpu_addr = radeon_bo_gpu_offset(bo); |
if (max_offset != 0) { |
u64 domain_start; |
if (domain == RADEON_GEM_DOMAIN_VRAM) |
domain_start = bo->rdev->mc.vram_start; |
else |
domain_start = bo->rdev->mc.gtt_start; |
WARN_ON_ONCE(max_offset < |
(radeon_bo_gpu_offset(bo) - domain_start)); |
} |
return 0; |
} |
radeon_ttm_placement_from_domain(bo, domain); |
if (domain == RADEON_GEM_DOMAIN_VRAM) { |
/* force to pin into visible video ram */ |
bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; |
} |
if (max_offset) { |
u64 lpfn = max_offset >> PAGE_SHIFT; |
if (!bo->placement.lpfn) |
bo->placement.lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT; |
if (lpfn < bo->placement.lpfn) |
bo->placement.lpfn = lpfn; |
} |
for (i = 0; i < bo->placement.num_placement; i++) |
bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; |
r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); |
if (likely(r == 0)) { |
bo->pin_count = 1; |
if (gpu_addr != NULL) |
*gpu_addr = radeon_bo_gpu_offset(bo); |
if (domain == RADEON_GEM_DOMAIN_VRAM) |
bo->rdev->vram_pin_size += radeon_bo_size(bo); |
else |
bo->rdev->gart_pin_size += radeon_bo_size(bo); |
} else { |
dev_err(bo->rdev->dev, "%p pin failed\n", bo); |
} |
return r; |
} |
int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) |
{ |
return radeon_bo_pin_restricted(bo, domain, 0, gpu_addr); |
} |
int radeon_bo_unpin(struct radeon_bo *bo) |
{ |
int r, i; |
if (!bo->pin_count) { |
dev_warn(bo->rdev->dev, "%p unpin not necessary\n", bo); |
return 0; |
} |
bo->pin_count--; |
if (bo->pin_count) |
return 0; |
for (i = 0; i < bo->placement.num_placement; i++) |
bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; |
r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); |
if (likely(r == 0)) { |
if (bo->tbo.mem.mem_type == TTM_PL_VRAM) |
bo->rdev->vram_pin_size -= radeon_bo_size(bo); |
else |
bo->rdev->gart_pin_size -= radeon_bo_size(bo); |
} else { |
dev_err(bo->rdev->dev, "%p validate failed for unpin\n", bo); |
} |
return r; |
} |
int radeon_bo_init(struct radeon_device *rdev) |
{ |
/* Add an MTRR for the VRAM */ |
DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n", |
rdev->mc.mc_vram_size >> 20, |
(unsigned long long)rdev->mc.aper_size >> 20); |
DRM_INFO("RAM width %dbits %cDR\n", |
rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S'); |
return radeon_ttm_init(rdev); |
} |
void radeon_bo_fini(struct radeon_device *rdev) |
{ |
// radeon_ttm_fini(rdev); |
// arch_phys_wc_del(rdev->mc.vram_mtrr); |
} |
/* Returns how many bytes TTM can move per IB. |
*/ |
static u64 radeon_bo_get_threshold_for_moves(struct radeon_device *rdev) |
{ |
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 radeon_device *rdev, |
struct ww_acquire_ctx *ticket, |
struct list_head *head, int ring) |
{ |
struct radeon_cs_reloc *lobj; |
struct radeon_bo *bo; |
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->robj; |
if (!bo->pin_count) { |
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); |
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->allowed_domains) { |
domain = lobj->allowed_domains; |
goto retry; |
} |
ttm_eu_backoff_reservation(ticket, head); |
return r; |
} |
} |
lobj->gpu_offset = radeon_bo_gpu_offset(bo); |
lobj->tiling_flags = bo->tiling_flags; |
} |
return 0; |
} |
int radeon_bo_get_surface_reg(struct radeon_bo *bo) |
{ |
struct radeon_device *rdev = bo->rdev; |
struct radeon_surface_reg *reg; |
struct radeon_bo *old_object; |
int steal; |
int i; |
lockdep_assert_held(&bo->tbo.resv->lock.base); |
if (!bo->tiling_flags) |
return 0; |
if (bo->surface_reg >= 0) { |
reg = &rdev->surface_regs[bo->surface_reg]; |
i = bo->surface_reg; |
goto out; |
} |
steal = -1; |
for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) { |
reg = &rdev->surface_regs[i]; |
if (!reg->bo) |
break; |
old_object = reg->bo; |
if (old_object->pin_count == 0) |
steal = i; |
} |
/* if we are all out */ |
if (i == RADEON_GEM_MAX_SURFACES) { |
if (steal == -1) |
return -ENOMEM; |
/* find someone with a surface reg and nuke their BO */ |
reg = &rdev->surface_regs[steal]; |
old_object = reg->bo; |
/* blow away the mapping */ |
DRM_DEBUG("stealing surface reg %d from %p\n", steal, old_object); |
ttm_bo_unmap_virtual(&old_object->tbo); |
old_object->surface_reg = -1; |
i = steal; |
} |
bo->surface_reg = i; |
reg->bo = bo; |
out: |
radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch, |
bo->tbo.mem.start << PAGE_SHIFT, |
bo->tbo.num_pages << PAGE_SHIFT); |
return 0; |
} |
static void radeon_bo_clear_surface_reg(struct radeon_bo *bo) |
{ |
struct radeon_device *rdev = bo->rdev; |
struct radeon_surface_reg *reg; |
if (bo->surface_reg == -1) |
return; |
reg = &rdev->surface_regs[bo->surface_reg]; |
radeon_clear_surface_reg(rdev, bo->surface_reg); |
reg->bo = NULL; |
bo->surface_reg = -1; |
} |
int radeon_bo_set_tiling_flags(struct radeon_bo *bo, |
uint32_t tiling_flags, uint32_t pitch) |
{ |
struct radeon_device *rdev = bo->rdev; |
int r; |
if (rdev->family >= CHIP_CEDAR) { |
unsigned bankw, bankh, mtaspect, tilesplit, stilesplit; |
bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK; |
bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK; |
mtaspect = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK; |
tilesplit = (tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK; |
stilesplit = (tiling_flags >> RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK; |
switch (bankw) { |
case 0: |
case 1: |
case 2: |
case 4: |
case 8: |
break; |
default: |
return -EINVAL; |
} |
switch (bankh) { |
case 0: |
case 1: |
case 2: |
case 4: |
case 8: |
break; |
default: |
return -EINVAL; |
} |
switch (mtaspect) { |
case 0: |
case 1: |
case 2: |
case 4: |
case 8: |
break; |
default: |
return -EINVAL; |
} |
if (tilesplit > 6) { |
return -EINVAL; |
} |
if (stilesplit > 6) { |
return -EINVAL; |
} |
} |
r = radeon_bo_reserve(bo, false); |
if (unlikely(r != 0)) |
return r; |
bo->tiling_flags = tiling_flags; |
bo->pitch = pitch; |
radeon_bo_unreserve(bo); |
return 0; |
} |
void radeon_bo_get_tiling_flags(struct radeon_bo *bo, |
uint32_t *tiling_flags, |
uint32_t *pitch) |
{ |
lockdep_assert_held(&bo->tbo.resv->lock.base); |
if (tiling_flags) |
*tiling_flags = bo->tiling_flags; |
if (pitch) |
*pitch = bo->pitch; |
} |
int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, |
bool force_drop) |
{ |
if (!force_drop) |
lockdep_assert_held(&bo->tbo.resv->lock.base); |
if (!(bo->tiling_flags & RADEON_TILING_SURFACE)) |
return 0; |
if (force_drop) { |
radeon_bo_clear_surface_reg(bo); |
return 0; |
} |
if (bo->tbo.mem.mem_type != TTM_PL_VRAM) { |
if (!has_moved) |
return 0; |
if (bo->surface_reg >= 0) |
radeon_bo_clear_surface_reg(bo); |
return 0; |
} |
if ((bo->surface_reg >= 0) && !has_moved) |
return 0; |
return radeon_bo_get_surface_reg(bo); |
} |
void radeon_bo_move_notify(struct ttm_buffer_object *bo, |
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_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait) |
{ |
int r; |
r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, NULL); |
if (unlikely(r != 0)) |
return r; |
spin_lock(&bo->tbo.bdev->fence_lock); |
if (mem_type) |
*mem_type = bo->tbo.mem.mem_type; |
if (bo->tbo.sync_obj) |
r = ttm_bo_wait(&bo->tbo, true, true, no_wait); |
spin_unlock(&bo->tbo.bdev->fence_lock); |
ttm_bo_unreserve(&bo->tbo); |
return r; |
} |
/drivers/video/drm/radeon/radeon_object.h |
---|
31,8 → 31,6 |
#include <drm/radeon_drm.h> |
#include "radeon.h" |
struct sg_table; |
/** |
* radeon_mem_type_to_domain - return domain corresponding to mem_type |
* @mem_type: ttm memory type |
54,11 → 52,31 |
return 0; |
} |
int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr); |
/** |
* radeon_bo_reserve - reserve bo |
* @bo: bo structure |
* @no_intr: don't return -ERESTARTSYS on pending signal |
* |
* Returns: |
* -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by |
* a signal. Release all buffer reservations and return to user-space. |
*/ |
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, NULL); |
if (unlikely(r != 0)) { |
if (r != -ERESTARTSYS) |
dev_err(bo->rdev->dev, "%p reserve failed\n", bo); |
return r; |
} |
return 0; |
} |
static inline void radeon_bo_unreserve(struct radeon_bo *bo) |
{ |
// ttm_bo_unreserve(&bo->tbo); |
ttm_bo_unreserve(&bo->tbo); |
} |
/** |
80,15 → 98,6 |
return bo->tbo.num_pages << PAGE_SHIFT; |
} |
static inline bool radeon_bo_is_reserved(struct radeon_bo *bo) |
{ |
#ifdef __TTM__ |
return ttm_bo_is_reserved(&bo->tbo); |
#else |
return !!atomic_read(&bo->tbo.reserved); |
#endif |
} |
static inline unsigned radeon_bo_ngpu_pages(struct radeon_bo *bo) |
{ |
return (bo->tbo.num_pages << PAGE_SHIFT) / RADEON_GPU_PAGE_SIZE; |
104,13 → 113,10 |
* @bo: radeon object for which we query the offset |
* |
* Returns mmap offset of the object. |
* |
* Note: addr_space_offset is constant after ttm bo init thus isn't protected |
* by any lock. |
*/ |
static inline u64 radeon_bo_mmap_offset(struct radeon_bo *bo) |
{ |
return bo->tbo.addr_space_offset; |
return drm_vma_node_offset_addr(&bo->tbo.vma_node); |
} |
extern int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, |
118,11 → 124,12 |
extern int radeon_bo_create(struct radeon_device *rdev, |
unsigned long size, int byte_align, |
bool kernel, u32 domain, |
bool kernel, u32 domain, u32 flags, |
struct sg_table *sg, |
struct radeon_bo **bo_ptr); |
extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr); |
extern void radeon_bo_kunmap(struct radeon_bo *bo); |
extern struct radeon_bo *radeon_bo_ref(struct radeon_bo *bo); |
extern void radeon_bo_unref(struct radeon_bo **bo); |
extern int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr); |
extern int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, |
132,9 → 139,9 |
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 list_head *head, int ring); |
extern int radeon_bo_list_validate(struct radeon_device *rdev, |
struct ww_acquire_ctx *ticket, |
struct list_head *head, int ring); |
extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, |
struct vm_area_struct *vma); |
extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, |
144,7 → 151,7 |
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); |
164,7 → 171,8 |
extern int radeon_sa_bo_manager_init(struct radeon_device *rdev, |
struct radeon_sa_manager *sa_manager, |
unsigned size, u32 domain); |
unsigned size, u32 align, u32 domain, |
u32 flags); |
extern void radeon_sa_bo_manager_fini(struct radeon_device *rdev, |
struct radeon_sa_manager *sa_manager); |
extern int radeon_sa_bo_manager_start(struct radeon_device *rdev, |
174,7 → 182,7 |
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); |
/drivers/video/drm/radeon/radeon_pm.c |
---|
65,7 → 65,18 |
void radeon_pm_acpi_event_handler(struct radeon_device *rdev) |
{ |
if (rdev->pm.pm_method == PM_METHOD_PROFILE) { |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { |
mutex_lock(&rdev->pm.mutex); |
if (power_supply_is_system_supplied() > 0) |
rdev->pm.dpm.ac_power = true; |
else |
rdev->pm.dpm.ac_power = false; |
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) { |
mutex_lock(&rdev->pm.mutex); |
radeon_pm_update_profile(rdev); |
134,7 → 145,11 |
if (list_empty(&rdev->gem.objects)) |
return; |
list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) { |
if (bo->tbo.mem.mem_type == TTM_PL_VRAM) |
ttm_bo_unmap_virtual(&bo->tbo); |
} |
} |
static void radeon_sync_with_vblank(struct radeon_device *rdev) |
{ |
245,7 → 260,7 |
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); |
327,7 → 342,7 |
struct device_attribute *attr, |
char *buf) |
{ |
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
struct drm_device *ddev = dev_get_drvdata(dev); |
struct radeon_device *rdev = ddev->dev_private; |
int cp = rdev->pm.profile; |
343,9 → 358,14 |
const char *buf, |
size_t count) |
{ |
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(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) |
377,12 → 397,13 |
struct device_attribute *attr, |
char *buf) |
{ |
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); |
struct drm_device *ddev = dev_get_drvdata(dev); |
struct radeon_device *rdev = ddev->dev_private; |
int pm = rdev->pm.pm_method; |
return snprintf(buf, PAGE_SIZE, "%s\n", |
(pm == PM_METHOD_DYNPM) ? "dynpm" : "profile"); |
(pm == PM_METHOD_DYNPM) ? "dynpm" : |
(pm == PM_METHOD_PROFILE) ? "profile" : "dpm"); |
} |
static ssize_t radeon_set_pm_method(struct device *dev, |
390,10 → 411,22 |
const char *buf, |
size_t count) |
{ |
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(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; |
goto fail; |
} |
if (strncmp("dynpm", buf, strlen("dynpm")) == 0) { |
mutex_lock(&rdev->pm.mutex); |
rdev->pm.pm_method = PM_METHOD_DYNPM; |
417,65 → 450,542 |
return count; |
} |
//static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); |
//static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); |
static ssize_t radeon_get_dpm_state(struct device *dev, |
struct device_attribute *attr, |
char *buf) |
{ |
struct drm_device *ddev = dev_get_drvdata(dev); |
struct radeon_device *rdev = ddev->dev_private; |
enum radeon_pm_state_type pm = rdev->pm.dpm.user_state; |
return snprintf(buf, PAGE_SIZE, "%s\n", |
(pm == POWER_STATE_TYPE_BATTERY) ? "battery" : |
(pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance"); |
} |
static ssize_t radeon_set_dpm_state(struct device *dev, |
struct device_attribute *attr, |
const char *buf, |
size_t count) |
{ |
struct drm_device *ddev = dev_get_drvdata(dev); |
struct radeon_device *rdev = ddev->dev_private; |
mutex_lock(&rdev->pm.mutex); |
if (strncmp("battery", buf, strlen("battery")) == 0) |
rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY; |
else if (strncmp("balanced", buf, strlen("balanced")) == 0) |
rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED; |
else if (strncmp("performance", buf, strlen("performance")) == 0) |
rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE; |
else { |
mutex_unlock(&rdev->pm.mutex); |
count = -EINVAL; |
goto fail; |
} |
mutex_unlock(&rdev->pm.mutex); |
/* Can't set dpm state when the card is off */ |
if (!(rdev->flags & RADEON_IS_PX) || |
(ddev->switch_power_state == DRM_SWITCH_POWER_ON)) |
radeon_pm_compute_clocks(rdev); |
fail: |
return count; |
} |
static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev, |
struct device_attribute *attr, |
char *buf) |
{ |
struct drm_device *ddev = dev_get_drvdata(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"); |
} |
static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev, |
struct device_attribute *attr, |
const char *buf, |
size_t count) |
{ |
struct drm_device *ddev = dev_get_drvdata(dev); |
struct radeon_device *rdev = ddev->dev_private; |
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; |
} else if (strncmp("high", buf, strlen("high")) == 0) { |
level = RADEON_DPM_FORCED_LEVEL_HIGH; |
} else if (strncmp("auto", buf, strlen("auto")) == 0) { |
level = RADEON_DPM_FORCED_LEVEL_AUTO; |
} else { |
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; |
} |
fail: |
mutex_unlock(&rdev->pm.mutex); |
return count; |
} |
static ssize_t radeon_hwmon_show_temp(struct device *dev, |
struct device_attribute *attr, |
char *buf) |
{ |
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(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 |
temp = 0; |
return snprintf(buf, PAGE_SIZE, "%d\n", temp); |
} |
static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev, |
struct device_attribute *attr, |
char *buf) |
{ |
struct radeon_device *rdev = dev_get_drvdata(dev); |
// int hyst = to_sensor_dev_attr(attr)->index; |
int temp; |
// if (hyst) |
// temp = rdev->pm.dpm.thermal.min_temp; |
// else |
temp = rdev->pm.dpm.thermal.max_temp; |
return snprintf(buf, PAGE_SIZE, "%d\n", temp); |
} |
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, |
NULL |
}; |
static int radeon_hwmon_init(struct radeon_device *rdev) |
{ |
int err = 0; |
switch (rdev->pm.int_thermal_type) { |
case THERMAL_TYPE_RV6XX: |
temp = rv6xx_get_temp(rdev); |
break; |
case THERMAL_TYPE_RV770: |
temp = rv770_get_temp(rdev); |
break; |
case THERMAL_TYPE_EVERGREEN: |
case THERMAL_TYPE_NI: |
temp = evergreen_get_temp(rdev); |
break; |
case THERMAL_TYPE_SUMO: |
temp = sumo_get_temp(rdev); |
break; |
case THERMAL_TYPE_SI: |
temp = si_get_temp(rdev); |
case THERMAL_TYPE_CI: |
case THERMAL_TYPE_KV: |
if (rdev->asic->pm.get_temperature == NULL) |
return err; |
break; |
default: |
temp = 0; |
break; |
} |
return snprintf(buf, PAGE_SIZE, "%d\n", temp); |
return err; |
} |
static ssize_t radeon_hwmon_show_name(struct device *dev, |
struct device_attribute *attr, |
char *buf) |
static void radeon_hwmon_fini(struct radeon_device *rdev) |
{ |
return sprintf(buf, "radeon\n"); |
// if (rdev->pm.int_hwmon_dev) |
// hwmon_device_unregister(rdev->pm.int_hwmon_dev); |
} |
static int radeon_hwmon_init(struct radeon_device *rdev) |
static void radeon_dpm_thermal_work_handler(struct work_struct *work) |
{ |
int err = 0; |
struct radeon_device *rdev = |
container_of(work, struct radeon_device, |
pm.dpm.thermal.work); |
/* switch to the thermal state */ |
enum radeon_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL; |
rdev->pm.int_hwmon_dev = NULL; |
if (!rdev->pm.dpm_enabled) |
return; |
return err; |
if (rdev->asic->pm.get_temperature) { |
int temp = radeon_get_temperature(rdev); |
if (temp < rdev->pm.dpm.thermal.min_temp) |
/* switch back the user state */ |
dpm_state = rdev->pm.dpm.user_state; |
} else { |
if (rdev->pm.dpm.thermal.high_to_low) |
/* switch back the user state */ |
dpm_state = rdev->pm.dpm.user_state; |
} |
mutex_lock(&rdev->pm.mutex); |
if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL) |
rdev->pm.dpm.thermal_active = true; |
else |
rdev->pm.dpm.thermal_active = false; |
rdev->pm.dpm.state = dpm_state; |
mutex_unlock(&rdev->pm.mutex); |
static void radeon_hwmon_fini(struct radeon_device *rdev) |
radeon_pm_compute_clocks(rdev); |
} |
static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, |
enum radeon_pm_state_type dpm_state) |
{ |
int i; |
struct radeon_ps *ps; |
u32 ui_class; |
bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ? |
true : false; |
/* check if the vblank period is too short to adjust the mclk */ |
if (single_display && rdev->asic->dpm.vblank_too_short) { |
if (radeon_dpm_vblank_too_short(rdev)) |
single_display = false; |
} |
void radeon_pm_suspend(struct radeon_device *rdev) |
/* certain older asics have a separare 3D performance state, |
* so try that first if the user selected performance |
*/ |
if (dpm_state == POWER_STATE_TYPE_PERFORMANCE) |
dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; |
/* balanced states don't exist at the moment */ |
if (dpm_state == POWER_STATE_TYPE_BALANCED) |
dpm_state = POWER_STATE_TYPE_PERFORMANCE; |
restart_search: |
/* Pick the best power state based on current conditions */ |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
ps = &rdev->pm.dpm.ps[i]; |
ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK; |
switch (dpm_state) { |
/* user states */ |
case POWER_STATE_TYPE_BATTERY: |
if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) { |
if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { |
if (single_display) |
return ps; |
} else |
return ps; |
} |
break; |
case POWER_STATE_TYPE_BALANCED: |
if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) { |
if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { |
if (single_display) |
return ps; |
} else |
return ps; |
} |
break; |
case POWER_STATE_TYPE_PERFORMANCE: |
if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { |
if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { |
if (single_display) |
return ps; |
} else |
return ps; |
} |
break; |
/* internal states */ |
case POWER_STATE_TYPE_INTERNAL_UVD: |
if (rdev->pm.dpm.uvd_ps) |
return rdev->pm.dpm.uvd_ps; |
else |
break; |
case POWER_STATE_TYPE_INTERNAL_UVD_SD: |
if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) |
return ps; |
break; |
case POWER_STATE_TYPE_INTERNAL_UVD_HD: |
if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) |
return ps; |
break; |
case POWER_STATE_TYPE_INTERNAL_UVD_HD2: |
if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) |
return ps; |
break; |
case POWER_STATE_TYPE_INTERNAL_UVD_MVC: |
if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) |
return ps; |
break; |
case POWER_STATE_TYPE_INTERNAL_BOOT: |
return rdev->pm.dpm.boot_ps; |
case POWER_STATE_TYPE_INTERNAL_THERMAL: |
if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) |
return ps; |
break; |
case POWER_STATE_TYPE_INTERNAL_ACPI: |
if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) |
return ps; |
break; |
case POWER_STATE_TYPE_INTERNAL_ULV: |
if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) |
return ps; |
break; |
case POWER_STATE_TYPE_INTERNAL_3DPERF: |
if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) |
return ps; |
break; |
default: |
break; |
} |
} |
/* use a fallback state if we didn't match */ |
switch (dpm_state) { |
case POWER_STATE_TYPE_INTERNAL_UVD_SD: |
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; |
goto restart_search; |
case POWER_STATE_TYPE_INTERNAL_UVD_HD: |
case POWER_STATE_TYPE_INTERNAL_UVD_HD2: |
case POWER_STATE_TYPE_INTERNAL_UVD_MVC: |
if (rdev->pm.dpm.uvd_ps) { |
return rdev->pm.dpm.uvd_ps; |
} else { |
dpm_state = POWER_STATE_TYPE_PERFORMANCE; |
goto restart_search; |
} |
case POWER_STATE_TYPE_INTERNAL_THERMAL: |
dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI; |
goto restart_search; |
case POWER_STATE_TYPE_INTERNAL_ACPI: |
dpm_state = POWER_STATE_TYPE_BATTERY; |
goto restart_search; |
case POWER_STATE_TYPE_BATTERY: |
case POWER_STATE_TYPE_BALANCED: |
case POWER_STATE_TYPE_INTERNAL_3DPERF: |
dpm_state = POWER_STATE_TYPE_PERFORMANCE; |
goto restart_search; |
default: |
break; |
} |
return NULL; |
} |
static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev) |
{ |
int i; |
struct radeon_ps *ps; |
enum radeon_pm_state_type dpm_state; |
int ret; |
/* if dpm init failed */ |
if (!rdev->pm.dpm_enabled) |
return; |
if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) { |
/* add other state override checks here */ |
if ((!rdev->pm.dpm.thermal_active) && |
(!rdev->pm.dpm.uvd_active)) |
rdev->pm.dpm.state = rdev->pm.dpm.user_state; |
} |
dpm_state = rdev->pm.dpm.state; |
ps = radeon_dpm_pick_power_state(rdev, dpm_state); |
if (ps) |
rdev->pm.dpm.requested_ps = ps; |
else |
return; |
/* 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. |
*/ |
if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) { |
/* update display watermarks based on new power state */ |
radeon_bandwidth_update(rdev); |
/* update displays */ |
radeon_dpm_display_configuration_changed(rdev); |
rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; |
rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; |
} |
return; |
} else { |
/* for BTC+ if the num crtcs hasn't changed and state is the same, |
* nothing to do, if the num crtcs is > 1 and state is the same, |
* update display configuration. |
*/ |
if (rdev->pm.dpm.new_active_crtcs == |
rdev->pm.dpm.current_active_crtcs) { |
return; |
} else { |
if ((rdev->pm.dpm.current_active_crtc_count > 1) && |
(rdev->pm.dpm.new_active_crtc_count > 1)) { |
/* update display watermarks based on new power state */ |
radeon_bandwidth_update(rdev); |
/* update displays */ |
radeon_dpm_display_configuration_changed(rdev); |
rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; |
rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; |
return; |
} |
} |
} |
} |
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; |
/* update display watermarks based on new power state */ |
radeon_bandwidth_update(rdev); |
/* update displays */ |
radeon_dpm_display_configuration_changed(rdev); |
rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; |
rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; |
/* wait for the rings to drain */ |
for (i = 0; i < RADEON_NUM_RINGS; i++) { |
struct radeon_ring *ring = &rdev->ring[i]; |
if (ring->ready) |
radeon_fence_wait_empty(rdev, i); |
} |
/* program the new power state */ |
radeon_dpm_set_power_state(rdev); |
/* update current power state */ |
rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps; |
radeon_dpm_post_set_power_state(rdev); |
if (rdev->asic->dpm.force_performance_level) { |
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); |
/* 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: |
mutex_unlock(&rdev->ring_lock); |
// up_write(&rdev->pm.mclk_lock); |
mutex_unlock(&rdev->ddev->struct_mutex); |
} |
void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable) |
{ |
enum radeon_pm_state_type dpm_state; |
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); |
} else { |
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)) |
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; |
else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 1)) |
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; |
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); |
} else { |
mutex_lock(&rdev->pm.mutex); |
rdev->pm.dpm.uvd_active = false; |
mutex_unlock(&rdev->pm.mutex); |
} |
radeon_pm_compute_clocks(rdev); |
} |
} |
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); |
if (rdev->pm.pm_method == PM_METHOD_DYNPM) { |
if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) |
rdev->pm.dynpm_state = DYNPM_STATE_SUSPENDED; |
482,11 → 992,44 |
} |
mutex_unlock(&rdev->pm.mutex); |
// cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); |
} |
void radeon_pm_resume(struct radeon_device *rdev) |
static void radeon_pm_suspend_dpm(struct radeon_device *rdev) |
{ |
mutex_lock(&rdev->pm.mutex); |
/* disable dpm */ |
radeon_dpm_disable(rdev); |
/* reset the power state */ |
rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; |
rdev->pm.dpm_enabled = false; |
mutex_unlock(&rdev->pm.mutex); |
} |
void radeon_pm_suspend(struct radeon_device *rdev) |
{ |
if (rdev->pm.pm_method == PM_METHOD_DPM) |
radeon_pm_suspend_dpm(rdev); |
else |
radeon_pm_suspend_old(rdev); |
} |
static void radeon_pm_resume_old(struct radeon_device *rdev) |
{ |
/* set up the default clocks if the MC ucode is loaded */ |
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); |
} |
/* asic init will reset the default power state */ |
mutex_lock(&rdev->pm.mutex); |
rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; |
493,8 → 1036,10 |
rdev->pm.current_clock_mode_index = 0; |
rdev->pm.current_sclk = rdev->pm.default_sclk; |
rdev->pm.current_mclk = rdev->pm.default_mclk; |
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; |
505,12 → 1050,51 |
radeon_pm_compute_clocks(rdev); |
} |
int radeon_pm_init(struct radeon_device *rdev) |
static void radeon_pm_resume_dpm(struct radeon_device *rdev) |
{ |
int ret; |
/* default to profile method */ |
rdev->pm.pm_method = PM_METHOD_PROFILE; |
/* asic init will reset to the boot state */ |
mutex_lock(&rdev->pm.mutex); |
rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; |
radeon_dpm_setup_asic(rdev); |
ret = radeon_dpm_enable(rdev); |
mutex_unlock(&rdev->pm.mutex); |
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); |
} |
} |
void radeon_pm_resume(struct radeon_device *rdev) |
{ |
if (rdev->pm.pm_method == PM_METHOD_DPM) |
radeon_pm_resume_dpm(rdev); |
else |
radeon_pm_resume_old(rdev); |
} |
static int radeon_pm_init_old(struct radeon_device *rdev) |
{ |
int ret; |
rdev->pm.profile = PM_PROFILE_DEFAULT; |
rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; |
rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; |
529,7 → 1113,22 |
radeon_combios_get_power_modes(rdev); |
radeon_pm_print_states(rdev); |
radeon_pm_init_profile(rdev); |
/* set up the default clocks if the MC ucode is loaded */ |
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); |
} |
} |
/* set up the internal thermal sensor if applicable */ |
ret = radeon_hwmon_init(rdev); |
536,8 → 1135,12 |
if (ret) |
return ret; |
// INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); |
if (rdev->pm.num_power_states > 1) { |
/* where's the best place to put these? */ |
DRM_INFO("radeon: power management initialized\n"); |
} |
544,8 → 1147,165 |
return 0; |
} |
void radeon_pm_fini(struct radeon_device *rdev) |
static void radeon_dpm_print_power_states(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
printk("== power state %d ==\n", i); |
radeon_dpm_print_power_state(rdev, &rdev->pm.dpm.ps[i]); |
} |
} |
static int radeon_pm_init_dpm(struct radeon_device *rdev) |
{ |
int ret; |
/* default to balanced state */ |
rdev->pm.dpm.state = POWER_STATE_TYPE_BALANCED; |
rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED; |
rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO; |
rdev->pm.default_sclk = rdev->clock.default_sclk; |
rdev->pm.default_mclk = rdev->clock.default_mclk; |
rdev->pm.current_sclk = rdev->clock.default_sclk; |
rdev->pm.current_mclk = rdev->clock.default_mclk; |
rdev->pm.int_thermal_type = THERMAL_TYPE_NONE; |
if (rdev->bios && rdev->is_atom_bios) |
radeon_atombios_get_power_modes(rdev); |
else |
return -EINVAL; |
/* set up the internal thermal sensor if applicable */ |
ret = radeon_hwmon_init(rdev); |
if (ret) |
return ret; |
INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler); |
mutex_lock(&rdev->pm.mutex); |
radeon_dpm_init(rdev); |
rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; |
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) |
goto dpm_failed; |
rdev->pm.dpm_enabled = true; |
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) |
{ |
/* enable dpm on rv6xx+ */ |
switch (rdev->family) { |
case CHIP_RV610: |
case CHIP_RV630: |
case CHIP_RV620: |
case CHIP_RV635: |
case CHIP_RV670: |
case CHIP_RS780: |
case CHIP_RS880: |
case CHIP_RV770: |
/* 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: |
case CHIP_CEDAR: |
case CHIP_REDWOOD: |
case CHIP_JUNIPER: |
case CHIP_CYPRESS: |
case CHIP_HEMLOCK: |
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: |
case CHIP_VERDE: |
case CHIP_OLAND: |
case CHIP_HAINAN: |
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; |
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 == 0) |
rdev->pm.pm_method = PM_METHOD_PROFILE; |
else |
rdev->pm.pm_method = PM_METHOD_DPM; |
break; |
default: |
/* default to profile method */ |
rdev->pm.pm_method = PM_METHOD_PROFILE; |
break; |
} |
if (rdev->pm.pm_method == PM_METHOD_DPM) |
return radeon_pm_init_dpm(rdev); |
else |
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) { |
mutex_lock(&rdev->pm.mutex); |
if (rdev->pm.pm_method == PM_METHOD_PROFILE) { |
565,10 → 1325,32 |
} |
radeon_hwmon_fini(rdev); |
kfree(rdev->pm.power_state); |
} |
void radeon_pm_compute_clocks(struct radeon_device *rdev) |
static void radeon_pm_fini_dpm(struct radeon_device *rdev) |
{ |
if (rdev->pm.num_power_states > 1) { |
mutex_lock(&rdev->pm.mutex); |
radeon_dpm_disable(rdev); |
mutex_unlock(&rdev->pm.mutex); |
} |
radeon_dpm_fini(rdev); |
radeon_hwmon_fini(rdev); |
kfree(rdev->pm.power_state); |
} |
void radeon_pm_fini(struct radeon_device *rdev) |
{ |
if (rdev->pm.pm_method == PM_METHOD_DPM) |
radeon_pm_fini_dpm(rdev); |
else |
radeon_pm_fini_old(rdev); |
} |
static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) |
{ |
struct drm_device *ddev = rdev->ddev; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
580,6 → 1362,7 |
rdev->pm.active_crtcs = 0; |
rdev->pm.active_crtc_count = 0; |
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); |
588,6 → 1371,7 |
rdev->pm.active_crtc_count++; |
} |
} |
} |
if (rdev->pm.pm_method == PM_METHOD_PROFILE) { |
radeon_pm_update_profile(rdev); |
638,6 → 1422,51 |
mutex_unlock(&rdev->pm.mutex); |
} |
static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev) |
{ |
struct drm_device *ddev = rdev->ddev; |
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; |
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++; |
} |
} |
} |
/* update battery/ac status */ |
if (power_supply_is_system_supplied() > 0) |
rdev->pm.dpm.ac_power = true; |
else |
rdev->pm.dpm.ac_power = false; |
radeon_dpm_change_power_state_locked(rdev); |
mutex_unlock(&rdev->pm.mutex); |
} |
void radeon_pm_compute_clocks(struct radeon_device *rdev) |
{ |
if (rdev->pm.pm_method == PM_METHOD_DPM) |
radeon_pm_compute_clocks_dpm(rdev); |
else |
radeon_pm_compute_clocks_old(rdev); |
} |
static bool radeon_pm_in_vbl(struct radeon_device *rdev) |
{ |
int crtc, vpos, hpos, vbl_status; |
648,7 → 1477,7 |
*/ |
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; |
680,7 → 1509,19 |
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->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); |
else |
seq_printf(m, "Debugfs support not implemented for this asic\n"); |
mutex_unlock(&rdev->pm.mutex); |
} else { |
seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk); |
/* radeon_get_engine_clock is not reliable on APUs so just print the current clock */ |
if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP)) |
694,6 → 1535,7 |
seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc); |
if (rdev->asic->pm.get_pcie_lanes) |
seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev)); |
} |
return 0; |
} |
/drivers/video/drm/radeon/radeon_reg.h |
---|
57,6 → 57,7 |
#include "evergreen_reg.h" |
#include "ni_reg.h" |
#include "si_reg.h" |
#include "cik_reg.h" |
#define RADEON_MC_AGP_LOCATION 0x014c |
#define RADEON_MC_AGP_START_MASK 0x0000FFFF |
/drivers/video/drm/radeon/radeon_ring.c |
---|
24,281 → 24,12 |
* Authors: Dave Airlie |
* Alex Deucher |
* Jerome Glisse |
* Christian Konig |
* Christian König |
*/ |
#include <linux/seq_file.h> |
#include <linux/slab.h> |
#include <drm/drmP.h> |
#include <drm/radeon_drm.h> |
#include "radeon_reg.h" |
#include "radeon.h" |
#include "atom.h" |
/* |
* IB |
* IBs (Indirect Buffers) and areas of GPU accessible memory where |
* commands are stored. You can put a pointer to the IB in the |
* command ring and the hw will fetch the commands from the IB |
* and execute them. Generally userspace acceleration drivers |
* produce command buffers which are send to the kernel and |
* put in IBs for execution by the requested ring. |
*/ |
static int radeon_debugfs_sa_init(struct radeon_device *rdev); |
/** |
* radeon_ib_get - request an IB (Indirect Buffer) |
* |
* @rdev: radeon_device pointer |
* @ring: ring index the IB is associated with |
* @ib: IB object returned |
* @size: requested IB size |
* |
* Request an IB (all asics). IBs are allocated using the |
* suballocator. |
* Returns 0 on success, error on failure. |
*/ |
int radeon_ib_get(struct radeon_device *rdev, int ring, |
struct radeon_ib *ib, struct radeon_vm *vm, |
unsigned size) |
{ |
int i, r; |
r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256, true); |
if (r) { |
dev_err(rdev->dev, "failed to get a new IB (%d)\n", r); |
return r; |
} |
r = radeon_semaphore_create(rdev, &ib->semaphore); |
if (r) { |
return r; |
} |
ib->ring = ring; |
ib->fence = NULL; |
ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo); |
ib->vm = vm; |
if (vm) { |
/* ib pool is bound at RADEON_VA_IB_OFFSET in virtual address |
* space and soffset is the offset inside the pool bo |
*/ |
ib->gpu_addr = ib->sa_bo->soffset + RADEON_VA_IB_OFFSET; |
} else { |
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; |
} |
/** |
* radeon_ib_free - free an IB (Indirect Buffer) |
* |
* @rdev: radeon_device pointer |
* @ib: IB object to free |
* |
* Free an IB (all asics). |
*/ |
void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
radeon_semaphore_free(rdev, &ib->semaphore, ib->fence); |
radeon_sa_bo_free(rdev, &ib->sa_bo, ib->fence); |
radeon_fence_unref(&ib->fence); |
} |
/** |
* 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 |
* @ib: IB object to schedule |
* @const_ib: Const IB to schedule (SI only) |
* |
* Schedule an IB on the associated ring (all asics). |
* Returns 0 on success, error on failure. |
* |
* On SI, there are two parallel engines fed from the primary ring, |
* the CE (Constant Engine) and the DE (Drawing Engine). Since |
* resource descriptors have moved to memory, the CE allows you to |
* prime the caches while the DE is updating register state so that |
* the resource descriptors will be already in cache when the draw is |
* processed. To accomplish this, the userspace driver submits two |
* IBs, one for the CE and one for the DE. If there is a CE IB (called |
* a CONST_IB), it will be put on the ring prior to the DE IB. Prior |
* to SI there was just a DE IB. |
*/ |
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; |
if (!ib->length_dw || !ring->ready) { |
/* TODO: Nothings in the ib we should report. */ |
dev_err(rdev->dev, "couldn't schedule ib\n"); |
return -EINVAL; |
} |
/* 64 dwords should be enough for fence too */ |
r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_RINGS * 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); |
} |
/* 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); |
} |
if (const_ib) { |
radeon_ring_ib_execute(rdev, const_ib->ring, const_ib); |
radeon_semaphore_free(rdev, &const_ib->semaphore, NULL); |
} |
radeon_ring_ib_execute(rdev, ib->ring, ib); |
r = radeon_fence_emit(rdev, &ib->fence, ib->ring); |
if (r) { |
dev_err(rdev->dev, "failed to emit fence for new IB (%d)\n", r); |
radeon_ring_unlock_undo(rdev, ring); |
return r; |
} |
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); |
} |
radeon_ring_unlock_commit(rdev, ring); |
return 0; |
} |
/** |
* radeon_ib_pool_init - Init the IB (Indirect Buffer) pool |
* |
* @rdev: radeon_device pointer |
* |
* Initialize the suballocator to manage a pool of memory |
* for use as IBs (all asics). |
* Returns 0 on success, error on failure. |
*/ |
int radeon_ib_pool_init(struct radeon_device *rdev) |
{ |
int r; |
if (rdev->ib_pool_ready) { |
return 0; |
} |
r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo, |
RADEON_IB_POOL_SIZE*64*1024, |
RADEON_GEM_DOMAIN_GTT); |
if (r) { |
return r; |
} |
r = radeon_sa_bo_manager_start(rdev, &rdev->ring_tmp_bo); |
if (r) { |
return r; |
} |
rdev->ib_pool_ready = true; |
if (radeon_debugfs_sa_init(rdev)) { |
dev_err(rdev->dev, "failed to register debugfs file for SA\n"); |
} |
return 0; |
} |
/** |
* radeon_ib_pool_fini - Free the IB (Indirect Buffer) pool |
* |
* @rdev: radeon_device pointer |
* |
* Tear down the suballocator managing the pool of memory |
* for use as IBs (all asics). |
*/ |
void radeon_ib_pool_fini(struct radeon_device *rdev) |
{ |
if (rdev->ib_pool_ready) { |
radeon_sa_bo_manager_suspend(rdev, &rdev->ring_tmp_bo); |
radeon_sa_bo_manager_fini(rdev, &rdev->ring_tmp_bo); |
rdev->ib_pool_ready = false; |
} |
} |
/** |
* radeon_ib_ring_tests - test IBs on the rings |
* |
* @rdev: radeon_device pointer |
* |
* Test an IB (Indirect Buffer) on each ring. |
* If the test fails, disable the ring. |
* Returns 0 on success, error if the primary GFX ring |
* IB test fails. |
*/ |
int radeon_ib_ring_tests(struct radeon_device *rdev) |
{ |
unsigned i; |
int r; |
for (i = 0; i < RADEON_NUM_RINGS; ++i) { |
struct radeon_ring *ring = &rdev->ring[i]; |
if (!ring->ready) |
continue; |
r = radeon_ib_test(rdev, i, ring); |
if (r) { |
ring->ready = false; |
if (i == RADEON_RING_TYPE_GFX_INDEX) { |
/* oh, oh, that's really bad */ |
DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r); |
rdev->accel_working = false; |
return r; |
} else { |
/* still not good, but we can live with it */ |
DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r); |
} |
} |
} |
return 0; |
} |
/* |
* Rings |
* Most engines on the GPU are fed via ring buffers. Ring |
* buffers are areas of GPU accessible memory that the host |
367,19 → 98,17 |
*/ |
void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
u32 rptr; |
uint32_t rptr = radeon_ring_get_rptr(rdev, ring); |
if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX]) |
rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); |
else |
rptr = RREG32(ring->rptr_reg); |
ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift; |
/* 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); |
} |
} |
403,12 → 132,6 |
/* 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); |
415,7 → 138,7 |
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; |
} |
454,19 → 177,30 |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* @hdp_flush: Whether or not to perform an HDP cache flush |
* |
* Update the wptr (write pointer) to tell the GPU to |
* execute new commands on the ring buffer (all asics). |
*/ |
void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring) |
void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring, |
bool hdp_flush) |
{ |
/* If we are emitting the HDP flush via the ring buffer, we need to |
* do it before padding. |
*/ |
if (hdp_flush && rdev->asic->ring[ring->idx]->hdp_flush) |
rdev->asic->ring[ring->idx]->hdp_flush(rdev, ring); |
/* We pad to match fetch size */ |
while (ring->wptr & ring->align_mask) { |
radeon_ring_write(ring, ring->nop); |
} |
DRM_MEMORYBARRIER(); |
WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask); |
(void)RREG32(ring->wptr_reg); |
mb(); |
/* If we are emitting the HDP flush via MMIO, we need to do it after |
* all CPU writes to VRAM finished. |
*/ |
if (hdp_flush && rdev->asic->mmio_hdp_flush) |
rdev->asic->mmio_hdp_flush(rdev); |
radeon_ring_set_wptr(rdev, ring); |
} |
/** |
475,12 → 209,14 |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* @hdp_flush: Whether or not to perform an HDP cache flush |
* |
* Call radeon_ring_commit() then unlock the ring (all asics). |
*/ |
void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring) |
void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring, |
bool hdp_flush) |
{ |
radeon_ring_commit(rdev, ring); |
radeon_ring_commit(rdev, ring, hdp_flush); |
mutex_unlock(&rdev->ring_lock); |
} |
510,29 → 246,6 |
} |
/** |
* 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 |
539,10 → 252,11 |
* |
* 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 = GetTimerTicks(); |
atomic_set(&ring->last_rptr, radeon_ring_get_rptr(rdev, ring)); |
atomic64_set(&ring->last_activity, jiffies_64); |
} |
/** |
550,42 → 264,23 |
* @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; |
uint32_t rptr = radeon_ring_get_rptr(rdev, ring); |
uint64_t last = atomic64_read(&ring->last_activity); |
uint64_t elapsed; |
cjiffies = GetTimerTicks(); |
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; |
} |
rptr = RREG32(ring->rptr_reg); |
ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift; |
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 ... */ |
681,7 → 376,7 |
radeon_ring_write(ring, data[i]); |
} |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
kfree(data); |
return 0; |
} |
693,10 → 388,6 |
* @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 |
* @ptr_reg_shift: bit offset of the rptr/wptr values |
* @ptr_reg_mask: bit mask of the rptr/wptr values |
* @nop: nop packet for this ring |
* |
* Initialize the driver information for the selected ring (all asics). |
703,22 → 394,17 |
* 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 ptr_reg_shift, u32 ptr_reg_mask, 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->ptr_reg_shift = ptr_reg_shift; |
ring->ptr_reg_mask = ptr_reg_mask; |
ring->nop = nop; |
/* Allocate ring buffer */ |
if (ring->ring_obj == NULL) { |
r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_GTT, |
RADEON_GEM_DOMAIN_GTT, 0, |
NULL, &ring->ring_obj); |
if (r) { |
dev_err(rdev->dev, "(%d) ring create failed\n", r); |
752,7 → 438,7 |
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; |
} |
799,31 → 485,51 |
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 = RREG32(ring->wptr_reg) >> ring->ptr_reg_shift; |
seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp); |
tmp = RREG32(ring->rptr_reg) >> ring->ptr_reg_shift; |
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; |
i = (rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask; |
for (j = 0; j <= (count + 32); j++) { |
seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]); |
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; |
835,6 → 541,8 |
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}, |
843,24 → 551,10 |
{"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) |
{ |
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; |
radeon_sa_bo_dump_debug_info(&rdev->ring_tmp_bo, m); |
return 0; |
} |
static struct drm_info_list radeon_debugfs_sa_list[] = { |
{"radeon_sa_info", &radeon_debugfs_sa_info, 0, NULL}, |
}; |
#endif |
static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring) |
882,12 → 576,3 |
#endif |
return 0; |
} |
static int radeon_debugfs_sa_init(struct radeon_device *rdev) |
{ |
#if defined(CONFIG_DEBUG_FS) |
return radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1); |
#else |
return 0; |
#endif |
} |
/drivers/video/drm/radeon/radeon_sa.c |
---|
49,7 → 49,7 |
int radeon_sa_bo_manager_init(struct radeon_device *rdev, |
struct radeon_sa_manager *sa_manager, |
unsigned size, u32 domain) |
unsigned size, u32 align, u32 domain, u32 flags) |
{ |
int i, r; |
57,6 → 57,7 |
sa_manager->bo = NULL; |
sa_manager->size = size; |
sa_manager->domain = domain; |
sa_manager->align = align; |
sa_manager->hole = &sa_manager->olist; |
INIT_LIST_HEAD(&sa_manager->olist); |
for (i = 0; i < RADEON_NUM_RINGS; ++i) { |
63,8 → 64,8 |
INIT_LIST_HEAD(&sa_manager->flist[i]); |
} |
r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true, |
domain, NULL, &sa_manager->bo); |
r = radeon_bo_create(rdev, size, align, true, |
domain, flags, NULL, &sa_manager->bo); |
if (r) { |
dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r); |
return r; |
311,13 → 312,13 |
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]; |
int i, r; |
BUG_ON(align > RADEON_GPU_PAGE_SIZE); |
BUG_ON(align > sa_manager->align); |
BUG_ON(size > sa_manager->size); |
*sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL); |
352,14 → 353,11 |
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) { |
// r = wait_event_interruptible_locked( |
// sa_manager->wq, |
// radeon_sa_event(sa_manager, size, align) |
// ); |
} else if (r == -ENOENT) { |
r = -ENOMEM; |
if (r == -ENOENT) { |
r = wait_event_interruptible( |
sa_manager->wq, |
radeon_sa_event(sa_manager, size, align) |
); |
} |
} while (!r); |
401,13 → 399,15 |
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); |
/drivers/video/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,56 → 50,141 |
} |
(*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) |
{ |
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; |
radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, false); |
/* 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) |
{ |
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; |
radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, true); |
/* 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]; |
/* check if we really need to sync */ |
if (!radeon_fence_need_sync(fence, ring)) |
continue; |
/* prevent GPU deadlocks */ |
if (!rdev->ring[signaler].ready) { |
dev_err(rdev->dev, "Trying to sync to a disabled ring!"); |
if (!rdev->ring[i].ready) { |
dev_err(rdev->dev, "Syncing to a disabled ring!"); |
return -EINVAL; |
} |
r = radeon_ring_alloc(rdev, &rdev->ring[signaler], 8); |
if (++count > RADEON_NUM_SYNCS) { |
/* not enough room, wait manually */ |
r = radeon_fence_wait(fence, false); |
if (r) |
return r; |
continue; |
} |
/* allocate enough space for sync command */ |
r = radeon_ring_alloc(rdev, &rdev->ring[i], 16); |
if (r) { |
return r; |
} |
radeon_semaphore_emit_signal(rdev, signaler, semaphore); |
radeon_ring_commit(rdev, &rdev->ring[signaler]); |
/* 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 */ |
radeon_semaphore_emit_wait(rdev, waiter, semaphore); |
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; |
} |
/* 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; |
radeon_ring_commit(rdev, &rdev->ring[i], false); |
radeon_fence_note_sync(fence, ring); |
semaphore->gpu_addr += 8; |
} |
return 0; |
} |
/drivers/video/drm/radeon/radeon_test.c |
---|
0,0 → 1,565 |
/* |
* Copyright 2009 VMware, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Michel Dänzer |
*/ |
#include <drm/drmP.h> |
#include <drm/radeon_drm.h> |
#include "radeon_reg.h" |
#include "radeon.h" |
#define RADEON_TEST_COPY_BLIT 1 |
#define RADEON_TEST_COPY_DMA 0 |
/* Test BO GTT->VRAM and VRAM->GTT GPU copies across the whole GTT aperture */ |
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 n, size; |
int i, r, ring; |
switch (flag) { |
case RADEON_TEST_COPY_DMA: |
ring = radeon_copy_dma_ring_index(rdev); |
break; |
case RADEON_TEST_COPY_BLIT: |
ring = radeon_copy_blit_ring_index(rdev); |
break; |
default: |
DRM_ERROR("Unknown copy method\n"); |
return; |
} |
size = 1024 * 1024; |
/* Number of tests = |
* (Total GTT - IB pool - writeback page - ring buffers) / test size |
*/ |
n = rdev->mc.gtt_size - rdev->gart_pin_size; |
n /= size; |
gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL); |
if (!gtt_obj) { |
DRM_ERROR("Failed to allocate %d pointers\n", n); |
r = 1; |
goto out_cleanup; |
} |
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, |
0, NULL, &vram_obj); |
if (r) { |
DRM_ERROR("Failed to create VRAM object\n"); |
goto out_cleanup; |
} |
r = radeon_bo_reserve(vram_obj, false); |
if (unlikely(r != 0)) |
goto out_unref; |
r = radeon_bo_pin(vram_obj, RADEON_GEM_DOMAIN_VRAM, &vram_addr); |
if (r) { |
DRM_ERROR("Failed to pin VRAM object\n"); |
goto out_unres; |
} |
for (i = 0; i < n; i++) { |
void *gtt_map, *vram_map; |
void **gtt_start, **gtt_end; |
void **vram_start, **vram_end; |
struct radeon_fence *fence = NULL; |
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_GTT, 0, NULL, gtt_obj + i); |
if (r) { |
DRM_ERROR("Failed to create GTT object %d\n", i); |
goto out_lclean; |
} |
r = radeon_bo_reserve(gtt_obj[i], false); |
if (unlikely(r != 0)) |
goto out_lclean_unref; |
r = radeon_bo_pin(gtt_obj[i], RADEON_GEM_DOMAIN_GTT, >t_addr); |
if (r) { |
DRM_ERROR("Failed to pin GTT object %d\n", i); |
goto out_lclean_unres; |
} |
r = radeon_bo_kmap(gtt_obj[i], >t_map); |
if (r) { |
DRM_ERROR("Failed to map GTT object %d\n", i); |
goto out_lclean_unpin; |
} |
for (gtt_start = gtt_map, gtt_end = gtt_map + size; |
gtt_start < gtt_end; |
gtt_start++) |
*gtt_start = gtt_start; |
radeon_bo_kunmap(gtt_obj[i]); |
if (ring == R600_RING_TYPE_DMA_INDEX) |
r = radeon_copy_dma(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence); |
else |
r = radeon_copy_blit(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence); |
if (r) { |
DRM_ERROR("Failed GTT->VRAM copy %d\n", i); |
goto out_lclean_unpin; |
} |
r = radeon_fence_wait(fence, false); |
if (r) { |
DRM_ERROR("Failed to wait for GTT->VRAM fence %d\n", i); |
goto out_lclean_unpin; |
} |
radeon_fence_unref(&fence); |
r = radeon_bo_kmap(vram_obj, &vram_map); |
if (r) { |
DRM_ERROR("Failed to map VRAM object after copy %d\n", i); |
goto out_lclean_unpin; |
} |
for (gtt_start = gtt_map, gtt_end = gtt_map + size, |
vram_start = vram_map, vram_end = vram_map + size; |
vram_start < vram_end; |
gtt_start++, vram_start++) { |
if (*vram_start != gtt_start) { |
DRM_ERROR("Incorrect GTT->VRAM copy %d: Got 0x%p, " |
"expected 0x%p (GTT/VRAM offset " |
"0x%16llx/0x%16llx)\n", |
i, *vram_start, gtt_start, |
(unsigned long long) |
(gtt_addr - rdev->mc.gtt_start + |
(void*)gtt_start - gtt_map), |
(unsigned long long) |
(vram_addr - rdev->mc.vram_start + |
(void*)gtt_start - gtt_map)); |
radeon_bo_kunmap(vram_obj); |
goto out_lclean_unpin; |
} |
*vram_start = vram_start; |
} |
radeon_bo_kunmap(vram_obj); |
if (ring == R600_RING_TYPE_DMA_INDEX) |
r = radeon_copy_dma(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence); |
else |
r = radeon_copy_blit(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence); |
if (r) { |
DRM_ERROR("Failed VRAM->GTT copy %d\n", i); |
goto out_lclean_unpin; |
} |
r = radeon_fence_wait(fence, false); |
if (r) { |
DRM_ERROR("Failed to wait for VRAM->GTT fence %d\n", i); |
goto out_lclean_unpin; |
} |
radeon_fence_unref(&fence); |
r = radeon_bo_kmap(gtt_obj[i], >t_map); |
if (r) { |
DRM_ERROR("Failed to map GTT object after copy %d\n", i); |
goto out_lclean_unpin; |
} |
for (gtt_start = gtt_map, gtt_end = gtt_map + size, |
vram_start = vram_map, vram_end = vram_map + size; |
gtt_start < gtt_end; |
gtt_start++, vram_start++) { |
if (*gtt_start != vram_start) { |
DRM_ERROR("Incorrect VRAM->GTT copy %d: Got 0x%p, " |
"expected 0x%p (VRAM/GTT offset " |
"0x%16llx/0x%16llx)\n", |
i, *gtt_start, vram_start, |
(unsigned long long) |
(vram_addr - rdev->mc.vram_start + |
(void*)vram_start - vram_map), |
(unsigned long long) |
(gtt_addr - rdev->mc.gtt_start + |
(void*)vram_start - vram_map)); |
radeon_bo_kunmap(gtt_obj[i]); |
goto out_lclean_unpin; |
} |
} |
radeon_bo_kunmap(gtt_obj[i]); |
DRM_INFO("Tested GTT->VRAM and VRAM->GTT copy for GTT offset 0x%llx\n", |
gtt_addr - rdev->mc.gtt_start); |
continue; |
out_lclean_unpin: |
radeon_bo_unpin(gtt_obj[i]); |
out_lclean_unres: |
radeon_bo_unreserve(gtt_obj[i]); |
out_lclean_unref: |
radeon_bo_unref(>t_obj[i]); |
out_lclean: |
for (--i; i >= 0; --i) { |
radeon_bo_unpin(gtt_obj[i]); |
radeon_bo_unreserve(gtt_obj[i]); |
radeon_bo_unref(>t_obj[i]); |
} |
if (fence) |
radeon_fence_unref(&fence); |
break; |
} |
radeon_bo_unpin(vram_obj); |
out_unres: |
radeon_bo_unreserve(vram_obj); |
out_unref: |
radeon_bo_unref(&vram_obj); |
out_cleanup: |
kfree(gtt_obj); |
if (r) { |
printk(KERN_WARNING "Error while testing BO move.\n"); |
} |
} |
void radeon_test_moves(struct radeon_device *rdev) |
{ |
if (rdev->asic->copy.dma) |
radeon_do_test_moves(rdev, RADEON_TEST_COPY_DMA); |
if (rdev->asic->copy.blit) |
radeon_do_test_moves(rdev, RADEON_TEST_COPY_BLIT); |
} |
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) { |
#if 0 |
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, handle, fence); |
if (r) { |
DRM_ERROR("Failed to get dummy destroy msg\n"); |
return r; |
} |
#endif |
} else if (ring->idx == TN_RING_TYPE_VCE1_INDEX || |
ring->idx == TN_RING_TYPE_VCE2_INDEX) { |
#if 0 |
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; |
} |
#endif |
} else { |
r = radeon_ring_lock(rdev, ring, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring A %d\n", ring->idx); |
return r; |
} |
radeon_fence_emit(rdev, fence, ring->idx); |
radeon_ring_unlock_commit(rdev, ring, false); |
} |
return 0; |
} |
void radeon_test_ring_sync(struct radeon_device *rdev, |
struct radeon_ring *ringA, |
struct radeon_ring *ringB) |
{ |
struct radeon_fence *fence1 = NULL, *fence2 = NULL; |
struct radeon_semaphore *semaphore = NULL; |
int r; |
r = radeon_semaphore_create(rdev, &semaphore); |
if (r) { |
DRM_ERROR("Failed to create semaphore\n"); |
goto out_cleanup; |
} |
r = radeon_ring_lock(rdev, ringA, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring A %d\n", ringA->idx); |
goto out_cleanup; |
} |
radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); |
radeon_ring_unlock_commit(rdev, ringA, false); |
r = radeon_test_create_and_emit_fence(rdev, ringA, &fence1); |
if (r) |
goto out_cleanup; |
r = radeon_ring_lock(rdev, ringA, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring A %d\n", ringA->idx); |
goto out_cleanup; |
} |
radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); |
radeon_ring_unlock_commit(rdev, ringA, false); |
r = radeon_test_create_and_emit_fence(rdev, ringA, &fence2); |
if (r) |
goto out_cleanup; |
mdelay(1000); |
if (radeon_fence_signaled(fence1)) { |
DRM_ERROR("Fence 1 signaled without waiting for semaphore.\n"); |
goto out_cleanup; |
} |
r = radeon_ring_lock(rdev, ringB, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring B %p\n", ringB); |
goto out_cleanup; |
} |
radeon_semaphore_emit_signal(rdev, ringB->idx, semaphore); |
radeon_ring_unlock_commit(rdev, ringB, false); |
r = radeon_fence_wait(fence1, false); |
if (r) { |
DRM_ERROR("Failed to wait for sync fence 1\n"); |
goto out_cleanup; |
} |
mdelay(1000); |
if (radeon_fence_signaled(fence2)) { |
DRM_ERROR("Fence 2 signaled without waiting for semaphore.\n"); |
goto out_cleanup; |
} |
r = radeon_ring_lock(rdev, ringB, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring B %p\n", ringB); |
goto out_cleanup; |
} |
radeon_semaphore_emit_signal(rdev, ringB->idx, semaphore); |
radeon_ring_unlock_commit(rdev, ringB, false); |
r = radeon_fence_wait(fence2, false); |
if (r) { |
DRM_ERROR("Failed to wait for sync fence 1\n"); |
goto out_cleanup; |
} |
out_cleanup: |
radeon_semaphore_free(rdev, &semaphore, NULL); |
if (fence1) |
radeon_fence_unref(&fence1); |
if (fence2) |
radeon_fence_unref(&fence2); |
if (r) |
printk(KERN_WARNING "Error while testing ring sync (%d).\n", r); |
} |
static void radeon_test_ring_sync2(struct radeon_device *rdev, |
struct radeon_ring *ringA, |
struct radeon_ring *ringB, |
struct radeon_ring *ringC) |
{ |
struct radeon_fence *fenceA = NULL, *fenceB = NULL; |
struct radeon_semaphore *semaphore = NULL; |
bool sigA, sigB; |
int i, r; |
r = radeon_semaphore_create(rdev, &semaphore); |
if (r) { |
DRM_ERROR("Failed to create semaphore\n"); |
goto out_cleanup; |
} |
r = radeon_ring_lock(rdev, ringA, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring A %d\n", ringA->idx); |
goto out_cleanup; |
} |
radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); |
radeon_ring_unlock_commit(rdev, ringA, false); |
r = radeon_test_create_and_emit_fence(rdev, ringA, &fenceA); |
if (r) |
goto out_cleanup; |
r = radeon_ring_lock(rdev, ringB, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring B %d\n", ringB->idx); |
goto out_cleanup; |
} |
radeon_semaphore_emit_wait(rdev, ringB->idx, semaphore); |
radeon_ring_unlock_commit(rdev, ringB, false); |
r = radeon_test_create_and_emit_fence(rdev, ringB, &fenceB); |
if (r) |
goto out_cleanup; |
mdelay(1000); |
if (radeon_fence_signaled(fenceA)) { |
DRM_ERROR("Fence A signaled without waiting for semaphore.\n"); |
goto out_cleanup; |
} |
if (radeon_fence_signaled(fenceB)) { |
DRM_ERROR("Fence B signaled without waiting for semaphore.\n"); |
goto out_cleanup; |
} |
r = radeon_ring_lock(rdev, ringC, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring B %p\n", ringC); |
goto out_cleanup; |
} |
radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore); |
radeon_ring_unlock_commit(rdev, ringC, false); |
for (i = 0; i < 30; ++i) { |
mdelay(100); |
sigA = radeon_fence_signaled(fenceA); |
sigB = radeon_fence_signaled(fenceB); |
if (sigA || sigB) |
break; |
} |
if (!sigA && !sigB) { |
DRM_ERROR("Neither fence A nor B has been signaled\n"); |
goto out_cleanup; |
} else if (sigA && sigB) { |
DRM_ERROR("Both fence A and B has been signaled\n"); |
goto out_cleanup; |
} |
DRM_INFO("Fence %c was first signaled\n", sigA ? 'A' : 'B'); |
r = radeon_ring_lock(rdev, ringC, 64); |
if (r) { |
DRM_ERROR("Failed to lock ring B %p\n", ringC); |
goto out_cleanup; |
} |
radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore); |
radeon_ring_unlock_commit(rdev, ringC, false); |
mdelay(1000); |
r = radeon_fence_wait(fenceA, false); |
if (r) { |
DRM_ERROR("Failed to wait for sync fence A\n"); |
goto out_cleanup; |
} |
r = radeon_fence_wait(fenceB, false); |
if (r) { |
DRM_ERROR("Failed to wait for sync fence B\n"); |
goto out_cleanup; |
} |
out_cleanup: |
radeon_semaphore_free(rdev, &semaphore, NULL); |
if (fenceA) |
radeon_fence_unref(&fenceA); |
if (fenceB) |
radeon_fence_unref(&fenceB); |
if (r) |
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; |
for (i = 1; i < RADEON_NUM_RINGS; ++i) { |
struct radeon_ring *ringA = &rdev->ring[i]; |
if (!ringA->ready) |
continue; |
for (j = 0; j < i; ++j) { |
struct radeon_ring *ringB = &rdev->ring[j]; |
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); |
DRM_INFO("Testing syncing between rings %d and %d...\n", j, i); |
radeon_test_ring_sync(rdev, ringB, ringA); |
for (k = 0; k < j; ++k) { |
struct radeon_ring *ringC = &rdev->ring[k]; |
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); |
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, k, j); |
radeon_test_ring_sync2(rdev, ringA, ringC, ringB); |
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", j, i, k); |
radeon_test_ring_sync2(rdev, ringB, ringA, ringC); |
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", j, k, i); |
radeon_test_ring_sync2(rdev, ringB, ringC, ringA); |
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", k, i, j); |
radeon_test_ring_sync2(rdev, ringC, ringA, ringB); |
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", k, j, i); |
radeon_test_ring_sync2(rdev, ringC, ringB, ringA); |
} |
} |
} |
} |
/drivers/video/drm/radeon/radeon_trace.h |
---|
3,80 → 3,19 |
#include <linux/stringify.h> |
#include <linux/types.h> |
#include <linux/tracepoint.h> |
#include <drm/drmP.h> |
#undef TRACE_SYSTEM |
#define TRACE_SYSTEM radeon |
#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) |
#define TRACE_INCLUDE_FILE radeon_trace |
TRACE_EVENT(radeon_bo_create, |
TP_PROTO(struct radeon_bo *bo), |
TP_ARGS(bo), |
TP_STRUCT__entry( |
__field(struct radeon_bo *, bo) |
__field(u32, pages) |
), |
#define trace_radeon_vm_set_page(pe, addr, count, incr, flags) |
#define trace_radeon_fence_emit(ddev, ring, seq) |
#define trace_radeon_fence_wait_begin(ddev, i, target_seq) |
#define trace_radeon_fence_wait_end(ddev, i, target_seq) |
#define trace_radeon_semaphore_signale(ridx, semaphore) |
#define trace_radeon_semaphore_wait(ridx, semaphore) |
#define trace_radeon_vm_grab_id(id, ring) |
#define trace_radeon_vm_bo_update(bo_va) |
#define trace_radeon_bo_create(bo) |
#define trace_radeon_cs(parser) |
#define trace_radeon_vm_flush(pd_addr, ring, id) |
TP_fast_assign( |
__entry->bo = bo; |
__entry->pages = bo->tbo.num_pages; |
), |
TP_printk("bo=%p, pages=%u", __entry->bo, __entry->pages) |
); |
DECLARE_EVENT_CLASS(radeon_fence_request, |
TP_PROTO(struct drm_device *dev, u32 seqno), |
TP_ARGS(dev, seqno), |
TP_STRUCT__entry( |
__field(u32, dev) |
__field(u32, seqno) |
), |
TP_fast_assign( |
__entry->dev = dev->primary->index; |
__entry->seqno = seqno; |
), |
TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno) |
); |
DEFINE_EVENT(radeon_fence_request, radeon_fence_emit, |
TP_PROTO(struct drm_device *dev, u32 seqno), |
TP_ARGS(dev, seqno) |
); |
DEFINE_EVENT(radeon_fence_request, radeon_fence_retire, |
TP_PROTO(struct drm_device *dev, u32 seqno), |
TP_ARGS(dev, seqno) |
); |
DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_begin, |
TP_PROTO(struct drm_device *dev, u32 seqno), |
TP_ARGS(dev, seqno) |
); |
DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_end, |
TP_PROTO(struct drm_device *dev, u32 seqno), |
TP_ARGS(dev, seqno) |
); |
#endif |
/* This part must be outside protection */ |
#undef TRACE_INCLUDE_PATH |
#define TRACE_INCLUDE_PATH . |
#include <trace/define_trace.h> |
/drivers/video/drm/radeon/radeon_ttm.c |
---|
44,6 → 44,7 |
#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) |
{ |
74,8 → 75,6 |
struct drm_global_reference *global_ref; |
int r; |
ENTER(); |
rdev->mman.mem_global_referenced = false; |
global_ref = &rdev->mman.mem_global_ref; |
global_ref->global_type = DRM_GLOBAL_TTM_MEM; |
104,14 → 103,10 |
} |
rdev->mman.mem_global_referenced = true; |
LEAVE(); |
return 0; |
} |
static int radeon_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) |
{ |
return 0; |
122,8 → 117,6 |
{ |
struct radeon_device *rdev; |
ENTER(); |
rdev = radeon_get_rdev(bdev); |
switch (type) { |
141,7 → 134,7 |
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; |
167,9 → 160,6 |
DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); |
return -EINVAL; |
} |
LEAVE(); |
return 0; |
} |
218,6 → 208,265 |
new_mem->mm_node = NULL; |
} |
static int radeon_move_blit(struct ttm_buffer_object *bo, |
bool evict, bool no_wait_gpu, |
struct ttm_mem_reg *new_mem, |
struct ttm_mem_reg *old_mem) |
{ |
struct radeon_device *rdev; |
uint64_t old_start, new_start; |
struct radeon_fence *fence; |
int r, ridx; |
rdev = radeon_get_rdev(bo->bdev); |
ridx = radeon_copy_ring_index(rdev); |
old_start = old_mem->start << PAGE_SHIFT; |
new_start = new_mem->start << PAGE_SHIFT; |
switch (old_mem->mem_type) { |
case TTM_PL_VRAM: |
old_start += rdev->mc.vram_start; |
break; |
case TTM_PL_TT: |
old_start += rdev->mc.gtt_start; |
break; |
default: |
DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); |
return -EINVAL; |
} |
switch (new_mem->mem_type) { |
case TTM_PL_VRAM: |
new_start += rdev->mc.vram_start; |
break; |
case TTM_PL_TT: |
new_start += rdev->mc.gtt_start; |
break; |
default: |
DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); |
return -EINVAL; |
} |
if (!rdev->ring[ridx].ready) { |
DRM_ERROR("Trying to move memory with ring turned off.\n"); |
return -EINVAL; |
} |
BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0); |
/* sync other rings */ |
fence = bo->sync_obj; |
r = radeon_copy(rdev, old_start, new_start, |
new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE), /* GPU pages */ |
&fence); |
/* FIXME: handle copy error */ |
r = ttm_bo_move_accel_cleanup(bo, (void *)fence, |
evict, no_wait_gpu, new_mem); |
radeon_fence_unref(&fence); |
return r; |
} |
static int radeon_move_vram_ram(struct ttm_buffer_object *bo, |
bool evict, bool interruptible, |
bool no_wait_gpu, |
struct ttm_mem_reg *new_mem) |
{ |
struct radeon_device *rdev; |
struct ttm_mem_reg *old_mem = &bo->mem; |
struct ttm_mem_reg tmp_mem; |
u32 placements; |
struct ttm_placement placement; |
int r; |
rdev = radeon_get_rdev(bo->bdev); |
tmp_mem = *new_mem; |
tmp_mem.mm_node = NULL; |
placement.fpfn = 0; |
placement.lpfn = 0; |
placement.num_placement = 1; |
placement.placement = &placements; |
placement.num_busy_placement = 1; |
placement.busy_placement = &placements; |
placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; |
r = ttm_bo_mem_space(bo, &placement, &tmp_mem, |
interruptible, no_wait_gpu); |
if (unlikely(r)) { |
return r; |
} |
r = ttm_tt_set_placement_caching(bo->ttm, tmp_mem.placement); |
if (unlikely(r)) { |
goto out_cleanup; |
} |
r = ttm_tt_bind(bo->ttm, &tmp_mem); |
if (unlikely(r)) { |
goto out_cleanup; |
} |
r = radeon_move_blit(bo, true, no_wait_gpu, &tmp_mem, old_mem); |
if (unlikely(r)) { |
goto out_cleanup; |
} |
r = ttm_bo_move_ttm(bo, true, no_wait_gpu, new_mem); |
out_cleanup: |
ttm_bo_mem_put(bo, &tmp_mem); |
return r; |
} |
static int radeon_move_ram_vram(struct ttm_buffer_object *bo, |
bool evict, bool interruptible, |
bool no_wait_gpu, |
struct ttm_mem_reg *new_mem) |
{ |
struct radeon_device *rdev; |
struct ttm_mem_reg *old_mem = &bo->mem; |
struct ttm_mem_reg tmp_mem; |
struct ttm_placement placement; |
u32 placements; |
int r; |
rdev = radeon_get_rdev(bo->bdev); |
tmp_mem = *new_mem; |
tmp_mem.mm_node = NULL; |
placement.fpfn = 0; |
placement.lpfn = 0; |
placement.num_placement = 1; |
placement.placement = &placements; |
placement.num_busy_placement = 1; |
placement.busy_placement = &placements; |
placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; |
r = ttm_bo_mem_space(bo, &placement, &tmp_mem, |
interruptible, no_wait_gpu); |
if (unlikely(r)) { |
return r; |
} |
r = ttm_bo_move_ttm(bo, true, no_wait_gpu, &tmp_mem); |
if (unlikely(r)) { |
goto out_cleanup; |
} |
r = radeon_move_blit(bo, true, no_wait_gpu, new_mem, old_mem); |
if (unlikely(r)) { |
goto out_cleanup; |
} |
out_cleanup: |
ttm_bo_mem_put(bo, &tmp_mem); |
return r; |
} |
static int radeon_bo_move(struct ttm_buffer_object *bo, |
bool evict, bool interruptible, |
bool no_wait_gpu, |
struct ttm_mem_reg *new_mem) |
{ |
struct radeon_device *rdev; |
struct ttm_mem_reg *old_mem = &bo->mem; |
int r; |
rdev = radeon_get_rdev(bo->bdev); |
if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { |
radeon_move_null(bo, new_mem); |
return 0; |
} |
if ((old_mem->mem_type == TTM_PL_TT && |
new_mem->mem_type == TTM_PL_SYSTEM) || |
(old_mem->mem_type == TTM_PL_SYSTEM && |
new_mem->mem_type == TTM_PL_TT)) { |
/* bind is enough */ |
radeon_move_null(bo, new_mem); |
return 0; |
} |
if (!rdev->ring[radeon_copy_ring_index(rdev)].ready || |
rdev->asic->copy.copy == NULL) { |
/* use memcpy */ |
goto memcpy; |
} |
if (old_mem->mem_type == TTM_PL_VRAM && |
new_mem->mem_type == TTM_PL_SYSTEM) { |
r = radeon_move_vram_ram(bo, evict, interruptible, |
no_wait_gpu, new_mem); |
} else if (old_mem->mem_type == TTM_PL_SYSTEM && |
new_mem->mem_type == TTM_PL_VRAM) { |
r = radeon_move_ram_vram(bo, evict, interruptible, |
no_wait_gpu, new_mem); |
} else { |
r = radeon_move_blit(bo, evict, no_wait_gpu, new_mem, old_mem); |
} |
if (r) { |
memcpy: |
r = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); |
if (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) |
{ |
struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; |
struct radeon_device *rdev = radeon_get_rdev(bdev); |
mem->bus.addr = NULL; |
mem->bus.offset = 0; |
mem->bus.size = mem->num_pages << PAGE_SHIFT; |
mem->bus.base = 0; |
mem->bus.is_iomem = false; |
if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) |
return -EINVAL; |
switch (mem->mem_type) { |
case TTM_PL_SYSTEM: |
/* system memory */ |
return 0; |
case TTM_PL_TT: |
#if __OS_HAS_AGP |
if (rdev->flags & RADEON_IS_AGP) { |
/* RADEON_IS_AGP is set only if AGP is active */ |
mem->bus.offset = mem->start << PAGE_SHIFT; |
mem->bus.base = rdev->mc.agp_base; |
mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture; |
} |
#endif |
break; |
case TTM_PL_VRAM: |
mem->bus.offset = mem->start << PAGE_SHIFT; |
/* check if it's visible */ |
if ((mem->bus.offset + mem->bus.size) > rdev->mc.visible_vram_size) |
return -EINVAL; |
mem->bus.base = rdev->mc.aper_base; |
mem->bus.is_iomem = true; |
#ifdef __alpha__ |
/* |
* Alpha: use bus.addr to hold the ioremap() return, |
* so we can modify bus.base below. |
*/ |
if (mem->placement & TTM_PL_FLAG_WC) |
mem->bus.addr = |
ioremap_wc(mem->bus.base + mem->bus.offset, |
mem->bus.size); |
else |
mem->bus.addr = |
ioremap_nocache(mem->bus.base + mem->bus.offset, |
mem->bus.size); |
/* |
* Alpha: Use just the bus offset plus |
* the hose/domain memory base for bus.base. |
* It then can be used to build PTEs for VRAM |
* access, as done in ttm_bo_vm_fault(). |
*/ |
mem->bus.base = (mem->bus.base & 0x0ffffffffUL) + |
rdev->ddev->hose->dense_mem_base; |
#endif |
break; |
default: |
return -EINVAL; |
} |
return 0; |
} |
static void radeon_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) |
{ |
} |
260,6 → 509,8 |
struct ttm_mem_reg *bo_mem) |
{ |
struct radeon_ttm_tt *gtt = (void*)ttm; |
uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ | |
RADEON_GART_PAGE_WRITE; |
int r; |
gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT); |
267,8 → 518,10 |
WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", |
ttm->num_pages, bo_mem, ttm); |
} |
r = radeon_gart_bind(gtt->rdev, gtt->offset, |
ttm->num_pages, ttm->pages, gtt->ttm.dma_address); |
if (ttm->caching_state == tt_cached) |
flags |= RADEON_GART_PAGE_SNOOP; |
r = radeon_gart_bind(gtt->rdev, gtt->offset, ttm->num_pages, |
ttm->pages, gtt->ttm.dma_address, flags); |
if (r) { |
DRM_ERROR("failed to bind %lu pages at 0x%08X\n", |
ttm->num_pages, (unsigned)gtt->offset); |
289,7 → 542,7 |
{ |
struct radeon_ttm_tt *gtt = (void *)ttm; |
ttm_dma_tt_fini(>t->ttm); |
// ttm_dma_tt_fini(>t->ttm); |
kfree(gtt); |
} |
327,24 → 580,98 |
return >t->ttm.ttm; |
} |
static int radeon_ttm_tt_populate(struct ttm_tt *ttm) |
{ |
struct radeon_device *rdev; |
struct radeon_ttm_tt *gtt = (void *)ttm; |
unsigned i; |
int r; |
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); |
if (ttm->state != tt_unpopulated) |
return 0; |
if (slave && ttm->sg) { |
drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, |
gtt->ttm.dma_address, ttm->num_pages); |
ttm->state = tt_unbound; |
return 0; |
} |
rdev = radeon_get_rdev(ttm->bdev); |
#if __OS_HAS_AGP |
if (rdev->flags & RADEON_IS_AGP) { |
return ttm_agp_tt_populate(ttm); |
} |
#endif |
#ifdef CONFIG_SWIOTLB |
if (swiotlb_nr_tbl()) { |
return ttm_dma_populate(>t->ttm, rdev->dev); |
} |
#endif |
r = ttm_pool_populate(ttm); |
if (r) { |
return r; |
} |
for (i = 0; i < ttm->num_pages; i++) { |
gtt->ttm.dma_address[i] = pci_map_page(rdev->pdev, ttm->pages[i], |
0, PAGE_SIZE, |
PCI_DMA_BIDIRECTIONAL); |
} |
return 0; |
} |
static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm) |
{ |
struct radeon_device *rdev; |
struct radeon_ttm_tt *gtt = (void *)ttm; |
unsigned i; |
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); |
if (slave) |
return; |
rdev = radeon_get_rdev(ttm->bdev); |
#if __OS_HAS_AGP |
if (rdev->flags & RADEON_IS_AGP) { |
ttm_agp_tt_unpopulate(ttm); |
return; |
} |
#endif |
#ifdef CONFIG_SWIOTLB |
if (swiotlb_nr_tbl()) { |
ttm_dma_unpopulate(>t->ttm, rdev->dev); |
return; |
} |
#endif |
ttm_pool_unpopulate(ttm); |
} |
static struct ttm_bo_driver radeon_bo_driver = { |
.ttm_tt_create = &radeon_ttm_tt_create, |
// .ttm_tt_populate = &radeon_ttm_tt_populate, |
// .ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate, |
// .invalidate_caches = &radeon_invalidate_caches, |
.ttm_tt_populate = &radeon_ttm_tt_populate, |
.ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate, |
.invalidate_caches = &radeon_invalidate_caches, |
.init_mem_type = &radeon_init_mem_type, |
// .evict_flags = &radeon_evict_flags, |
// .move = &radeon_bo_move, |
// .verify_access = &radeon_verify_access, |
// .sync_obj_signaled = &radeon_sync_obj_signaled, |
// .sync_obj_wait = &radeon_sync_obj_wait, |
// .sync_obj_flush = &radeon_sync_obj_flush, |
// .sync_obj_unref = &radeon_sync_obj_unref, |
// .sync_obj_ref = &radeon_sync_obj_ref, |
// .move_notify = &radeon_bo_move_notify, |
.evict_flags = &radeon_evict_flags, |
.move = &radeon_bo_move, |
.verify_access = &radeon_verify_access, |
.sync_obj_signaled = &radeon_sync_obj_signaled, |
.sync_obj_wait = &radeon_sync_obj_wait, |
.sync_obj_flush = &radeon_sync_obj_flush, |
.sync_obj_unref = &radeon_sync_obj_unref, |
.sync_obj_ref = &radeon_sync_obj_ref, |
.move_notify = &radeon_bo_move_notify, |
// .fault_reserve_notify = &radeon_bo_fault_reserve_notify, |
// .io_mem_reserve = &radeon_ttm_io_mem_reserve, |
// .io_mem_free = &radeon_ttm_io_mem_free, |
.io_mem_reserve = &radeon_ttm_io_mem_reserve, |
.io_mem_free = &radeon_ttm_io_mem_free, |
}; |
int radeon_ttm_init(struct radeon_device *rdev) |
351,8 → 678,6 |
{ |
int r; |
ENTER(); |
r = radeon_ttm_global_init(rdev); |
if (r) { |
return r; |
360,7 → 685,9 |
/* 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, |
NULL, |
DRM_FILE_PAGE_OFFSET, |
rdev->need_dma32); |
if (r) { |
DRM_ERROR("failed initializing buffer object driver(%d).\n", r); |
373,25 → 700,26 |
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); |
// if (r) { |
// return r; |
// } |
// r = radeon_bo_reserve(rdev->stollen_vga_memory, false); |
// if (r) |
// return r; |
// r = radeon_bo_pin(rdev->stollen_vga_memory, RADEON_GEM_DOMAIN_VRAM, NULL); |
// radeon_bo_unreserve(rdev->stollen_vga_memory); |
// if (r) { |
// radeon_bo_unref(&rdev->stollen_vga_memory); |
// return r; |
// } |
r = radeon_bo_create(rdev, 16*1024*1024, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, 0, |
NULL, &rdev->stollen_vga_memory); |
if (r) { |
return r; |
} |
r = radeon_bo_reserve(rdev->stollen_vga_memory, false); |
if (r) |
return r; |
r = radeon_bo_pin(rdev->stollen_vga_memory, RADEON_GEM_DOMAIN_VRAM, NULL); |
radeon_bo_unreserve(rdev->stollen_vga_memory); |
if (r) { |
radeon_bo_unref(&rdev->stollen_vga_memory); |
return r; |
} |
DRM_INFO("radeon: %uM of VRAM memory ready\n", |
(unsigned)rdev->mc.real_vram_size / (1024 * 1024)); |
(unsigned) (rdev->mc.real_vram_size / (1024 * 1024))); |
r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, |
rdev->mc.gtt_size >> PAGE_SHIFT); |
if (r) { |
400,10 → 728,7 |
} |
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; |
LEAVE(); |
return 0; |
} |
474,3 → 799,34 |
int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, |
dma_addr_t *addrs, int max_pages) |
{ |
unsigned count; |
struct scatterlist *sg; |
struct page *page; |
u32 len; |
int pg_index; |
dma_addr_t addr; |
pg_index = 0; |
for_each_sg(sgt->sgl, sg, sgt->nents, count) { |
len = sg->length; |
page = sg_page(sg); |
addr = sg_dma_address(sg); |
while (len > 0) { |
if (WARN_ON(pg_index >= max_pages)) |
return -1; |
pages[pg_index] = page; |
if (addrs) |
addrs[pg_index] = addr; |
page++; |
addr += PAGE_SIZE; |
len -= PAGE_SIZE; |
pg_index++; |
} |
} |
return 0; |
} |
/drivers/video/drm/radeon/radeon_ucode.c |
---|
0,0 → 1,167 |
/* |
* Copyright 2014 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include <linux/firmware.h> |
#include <linux/slab.h> |
#include <linux/module.h> |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "radeon_ucode.h" |
static void radeon_ucode_print_common_hdr(const struct common_firmware_header *hdr) |
{ |
DRM_DEBUG("size_bytes: %u\n", le32_to_cpu(hdr->size_bytes)); |
DRM_DEBUG("header_size_bytes: %u\n", le32_to_cpu(hdr->header_size_bytes)); |
DRM_DEBUG("header_version_major: %u\n", le16_to_cpu(hdr->header_version_major)); |
DRM_DEBUG("header_version_minor: %u\n", le16_to_cpu(hdr->header_version_minor)); |
DRM_DEBUG("ip_version_major: %u\n", le16_to_cpu(hdr->ip_version_major)); |
DRM_DEBUG("ip_version_minor: %u\n", le16_to_cpu(hdr->ip_version_minor)); |
DRM_DEBUG("ucode_version: 0x%08x\n", le32_to_cpu(hdr->ucode_version)); |
DRM_DEBUG("ucode_size_bytes: %u\n", le32_to_cpu(hdr->ucode_size_bytes)); |
DRM_DEBUG("ucode_array_offset_bytes: %u\n", |
le32_to_cpu(hdr->ucode_array_offset_bytes)); |
DRM_DEBUG("crc32: 0x%08x\n", le32_to_cpu(hdr->crc32)); |
} |
void radeon_ucode_print_mc_hdr(const struct common_firmware_header *hdr) |
{ |
uint16_t version_major = le16_to_cpu(hdr->header_version_major); |
uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); |
DRM_DEBUG("MC\n"); |
radeon_ucode_print_common_hdr(hdr); |
if (version_major == 1) { |
const struct mc_firmware_header_v1_0 *mc_hdr = |
container_of(hdr, struct mc_firmware_header_v1_0, header); |
DRM_DEBUG("io_debug_size_bytes: %u\n", |
le32_to_cpu(mc_hdr->io_debug_size_bytes)); |
DRM_DEBUG("io_debug_array_offset_bytes: %u\n", |
le32_to_cpu(mc_hdr->io_debug_array_offset_bytes)); |
} else { |
DRM_ERROR("Unknown MC ucode version: %u.%u\n", version_major, version_minor); |
} |
} |
void radeon_ucode_print_smc_hdr(const struct common_firmware_header *hdr) |
{ |
uint16_t version_major = le16_to_cpu(hdr->header_version_major); |
uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); |
DRM_DEBUG("SMC\n"); |
radeon_ucode_print_common_hdr(hdr); |
if (version_major == 1) { |
const struct smc_firmware_header_v1_0 *smc_hdr = |
container_of(hdr, struct smc_firmware_header_v1_0, header); |
DRM_DEBUG("ucode_start_addr: %u\n", le32_to_cpu(smc_hdr->ucode_start_addr)); |
} else { |
DRM_ERROR("Unknown SMC ucode version: %u.%u\n", version_major, version_minor); |
} |
} |
void radeon_ucode_print_gfx_hdr(const struct common_firmware_header *hdr) |
{ |
uint16_t version_major = le16_to_cpu(hdr->header_version_major); |
uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); |
DRM_DEBUG("GFX\n"); |
radeon_ucode_print_common_hdr(hdr); |
if (version_major == 1) { |
const struct gfx_firmware_header_v1_0 *gfx_hdr = |
container_of(hdr, struct gfx_firmware_header_v1_0, header); |
DRM_DEBUG("ucode_feature_version: %u\n", |
le32_to_cpu(gfx_hdr->ucode_feature_version)); |
DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(gfx_hdr->jt_offset)); |
DRM_DEBUG("jt_size: %u\n", le32_to_cpu(gfx_hdr->jt_size)); |
} else { |
DRM_ERROR("Unknown GFX ucode version: %u.%u\n", version_major, version_minor); |
} |
} |
void radeon_ucode_print_rlc_hdr(const struct common_firmware_header *hdr) |
{ |
uint16_t version_major = le16_to_cpu(hdr->header_version_major); |
uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); |
DRM_DEBUG("RLC\n"); |
radeon_ucode_print_common_hdr(hdr); |
if (version_major == 1) { |
const struct rlc_firmware_header_v1_0 *rlc_hdr = |
container_of(hdr, struct rlc_firmware_header_v1_0, header); |
DRM_DEBUG("ucode_feature_version: %u\n", |
le32_to_cpu(rlc_hdr->ucode_feature_version)); |
DRM_DEBUG("save_and_restore_offset: %u\n", |
le32_to_cpu(rlc_hdr->save_and_restore_offset)); |
DRM_DEBUG("clear_state_descriptor_offset: %u\n", |
le32_to_cpu(rlc_hdr->clear_state_descriptor_offset)); |
DRM_DEBUG("avail_scratch_ram_locations: %u\n", |
le32_to_cpu(rlc_hdr->avail_scratch_ram_locations)); |
DRM_DEBUG("master_pkt_description_offset: %u\n", |
le32_to_cpu(rlc_hdr->master_pkt_description_offset)); |
} else { |
DRM_ERROR("Unknown RLC ucode version: %u.%u\n", version_major, version_minor); |
} |
} |
void radeon_ucode_print_sdma_hdr(const struct common_firmware_header *hdr) |
{ |
uint16_t version_major = le16_to_cpu(hdr->header_version_major); |
uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); |
DRM_DEBUG("SDMA\n"); |
radeon_ucode_print_common_hdr(hdr); |
if (version_major == 1) { |
const struct sdma_firmware_header_v1_0 *sdma_hdr = |
container_of(hdr, struct sdma_firmware_header_v1_0, header); |
DRM_DEBUG("ucode_feature_version: %u\n", |
le32_to_cpu(sdma_hdr->ucode_feature_version)); |
DRM_DEBUG("ucode_change_version: %u\n", |
le32_to_cpu(sdma_hdr->ucode_change_version)); |
DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(sdma_hdr->jt_offset)); |
DRM_DEBUG("jt_size: %u\n", le32_to_cpu(sdma_hdr->jt_size)); |
} else { |
DRM_ERROR("Unknown SDMA ucode version: %u.%u\n", |
version_major, version_minor); |
} |
} |
int radeon_ucode_validate(const struct firmware *fw) |
{ |
const struct common_firmware_header *hdr = |
(const struct common_firmware_header *)fw->data; |
if (fw->size == le32_to_cpu(hdr->size_bytes)) |
return 0; |
return -EINVAL; |
} |
/drivers/video/drm/radeon/radeon_ucode.h |
---|
0,0 → 1,227 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __RADEON_UCODE_H__ |
#define __RADEON_UCODE_H__ |
/* CP */ |
#define R600_PFP_UCODE_SIZE 576 |
#define R600_PM4_UCODE_SIZE 1792 |
#define R700_PFP_UCODE_SIZE 848 |
#define R700_PM4_UCODE_SIZE 1360 |
#define EVERGREEN_PFP_UCODE_SIZE 1120 |
#define EVERGREEN_PM4_UCODE_SIZE 1376 |
#define CAYMAN_PFP_UCODE_SIZE 2176 |
#define CAYMAN_PM4_UCODE_SIZE 2176 |
#define SI_PFP_UCODE_SIZE 2144 |
#define SI_PM4_UCODE_SIZE 2144 |
#define SI_CE_UCODE_SIZE 2144 |
#define CIK_PFP_UCODE_SIZE 2144 |
#define CIK_ME_UCODE_SIZE 2144 |
#define CIK_CE_UCODE_SIZE 2144 |
/* MEC */ |
#define CIK_MEC_UCODE_SIZE 4192 |
/* RLC */ |
#define R600_RLC_UCODE_SIZE 768 |
#define R700_RLC_UCODE_SIZE 1024 |
#define EVERGREEN_RLC_UCODE_SIZE 768 |
#define CAYMAN_RLC_UCODE_SIZE 1024 |
#define ARUBA_RLC_UCODE_SIZE 1536 |
#define SI_RLC_UCODE_SIZE 2048 |
#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 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 |
#define CIK_SDMA_UCODE_VERSION 64 |
/* SMC */ |
#define RV770_SMC_UCODE_START 0x0100 |
#define RV770_SMC_UCODE_SIZE 0x410d |
#define RV770_SMC_INT_VECTOR_START 0xffc0 |
#define RV770_SMC_INT_VECTOR_SIZE 0x0040 |
#define RV730_SMC_UCODE_START 0x0100 |
#define RV730_SMC_UCODE_SIZE 0x412c |
#define RV730_SMC_INT_VECTOR_START 0xffc0 |
#define RV730_SMC_INT_VECTOR_SIZE 0x0040 |
#define RV710_SMC_UCODE_START 0x0100 |
#define RV710_SMC_UCODE_SIZE 0x3f1f |
#define RV710_SMC_INT_VECTOR_START 0xffc0 |
#define RV710_SMC_INT_VECTOR_SIZE 0x0040 |
#define RV740_SMC_UCODE_START 0x0100 |
#define RV740_SMC_UCODE_SIZE 0x41c5 |
#define RV740_SMC_INT_VECTOR_START 0xffc0 |
#define RV740_SMC_INT_VECTOR_SIZE 0x0040 |
#define CEDAR_SMC_UCODE_START 0x0100 |
#define CEDAR_SMC_UCODE_SIZE 0x5d50 |
#define CEDAR_SMC_INT_VECTOR_START 0xffc0 |
#define CEDAR_SMC_INT_VECTOR_SIZE 0x0040 |
#define REDWOOD_SMC_UCODE_START 0x0100 |
#define REDWOOD_SMC_UCODE_SIZE 0x5f0a |
#define REDWOOD_SMC_INT_VECTOR_START 0xffc0 |
#define REDWOOD_SMC_INT_VECTOR_SIZE 0x0040 |
#define JUNIPER_SMC_UCODE_START 0x0100 |
#define JUNIPER_SMC_UCODE_SIZE 0x5f1f |
#define JUNIPER_SMC_INT_VECTOR_START 0xffc0 |
#define JUNIPER_SMC_INT_VECTOR_SIZE 0x0040 |
#define CYPRESS_SMC_UCODE_START 0x0100 |
#define CYPRESS_SMC_UCODE_SIZE 0x61f7 |
#define CYPRESS_SMC_INT_VECTOR_START 0xffc0 |
#define CYPRESS_SMC_INT_VECTOR_SIZE 0x0040 |
#define BARTS_SMC_UCODE_START 0x0100 |
#define BARTS_SMC_UCODE_SIZE 0x6107 |
#define BARTS_SMC_INT_VECTOR_START 0xffc0 |
#define BARTS_SMC_INT_VECTOR_SIZE 0x0040 |
#define TURKS_SMC_UCODE_START 0x0100 |
#define TURKS_SMC_UCODE_SIZE 0x605b |
#define TURKS_SMC_INT_VECTOR_START 0xffc0 |
#define TURKS_SMC_INT_VECTOR_SIZE 0x0040 |
#define CAICOS_SMC_UCODE_START 0x0100 |
#define CAICOS_SMC_UCODE_SIZE 0x5fbd |
#define CAICOS_SMC_INT_VECTOR_START 0xffc0 |
#define CAICOS_SMC_INT_VECTOR_SIZE 0x0040 |
#define CAYMAN_SMC_UCODE_START 0x0100 |
#define CAYMAN_SMC_UCODE_SIZE 0x79ec |
#define CAYMAN_SMC_INT_VECTOR_START 0xffc0 |
#define CAYMAN_SMC_INT_VECTOR_SIZE 0x0040 |
#define TAHITI_SMC_UCODE_START 0x10000 |
#define TAHITI_SMC_UCODE_SIZE 0xf458 |
#define PITCAIRN_SMC_UCODE_START 0x10000 |
#define PITCAIRN_SMC_UCODE_SIZE 0xe9f4 |
#define VERDE_SMC_UCODE_START 0x10000 |
#define VERDE_SMC_UCODE_SIZE 0xebe4 |
#define OLAND_SMC_UCODE_START 0x10000 |
#define OLAND_SMC_UCODE_SIZE 0xe7b4 |
#define HAINAN_SMC_UCODE_START 0x10000 |
#define HAINAN_SMC_UCODE_SIZE 0xe67C |
#define BONAIRE_SMC_UCODE_START 0x20000 |
#define BONAIRE_SMC_UCODE_SIZE 0x1FDEC |
#define HAWAII_SMC_UCODE_START 0x20000 |
#define HAWAII_SMC_UCODE_SIZE 0x1FDEC |
struct common_firmware_header { |
uint32_t size_bytes; /* size of the entire header+image(s) in bytes */ |
uint32_t header_size_bytes; /* size of just the header in bytes */ |
uint16_t header_version_major; /* header version */ |
uint16_t header_version_minor; /* header version */ |
uint16_t ip_version_major; /* IP version */ |
uint16_t ip_version_minor; /* IP version */ |
uint32_t ucode_version; |
uint32_t ucode_size_bytes; /* size of ucode in bytes */ |
uint32_t ucode_array_offset_bytes; /* payload offset from the start of the header */ |
uint32_t crc32; /* crc32 checksum of the payload */ |
}; |
/* version_major=1, version_minor=0 */ |
struct mc_firmware_header_v1_0 { |
struct common_firmware_header header; |
uint32_t io_debug_size_bytes; /* size of debug array in dwords */ |
uint32_t io_debug_array_offset_bytes; /* payload offset from the start of the header */ |
}; |
/* version_major=1, version_minor=0 */ |
struct smc_firmware_header_v1_0 { |
struct common_firmware_header header; |
uint32_t ucode_start_addr; |
}; |
/* version_major=1, version_minor=0 */ |
struct gfx_firmware_header_v1_0 { |
struct common_firmware_header header; |
uint32_t ucode_feature_version; |
uint32_t jt_offset; /* jt location */ |
uint32_t jt_size; /* size of jt */ |
}; |
/* version_major=1, version_minor=0 */ |
struct rlc_firmware_header_v1_0 { |
struct common_firmware_header header; |
uint32_t ucode_feature_version; |
uint32_t save_and_restore_offset; |
uint32_t clear_state_descriptor_offset; |
uint32_t avail_scratch_ram_locations; |
uint32_t master_pkt_description_offset; |
}; |
/* version_major=1, version_minor=0 */ |
struct sdma_firmware_header_v1_0 { |
struct common_firmware_header header; |
uint32_t ucode_feature_version; |
uint32_t ucode_change_version; |
uint32_t jt_offset; /* jt location */ |
uint32_t jt_size; /* size of jt */ |
}; |
/* header is fixed size */ |
union radeon_firmware_header { |
struct common_firmware_header common; |
struct mc_firmware_header_v1_0 mc; |
struct smc_firmware_header_v1_0 smc; |
struct gfx_firmware_header_v1_0 gfx; |
struct rlc_firmware_header_v1_0 rlc; |
struct sdma_firmware_header_v1_0 sdma; |
uint8_t raw[0x100]; |
}; |
void radeon_ucode_print_mc_hdr(const struct common_firmware_header *hdr); |
void radeon_ucode_print_smc_hdr(const struct common_firmware_header *hdr); |
void radeon_ucode_print_gfx_hdr(const struct common_firmware_header *hdr); |
void radeon_ucode_print_rlc_hdr(const struct common_firmware_header *hdr); |
void radeon_ucode_print_sdma_hdr(const struct common_firmware_header *hdr); |
int radeon_ucode_validate(const struct firmware *fw); |
#endif |
/drivers/video/drm/radeon/radeon_uvd.c |
---|
0,0 → 1,964 |
/* |
* Copyright 2011 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 <deathsimple@vodafone.de> |
*/ |
#include <linux/firmware.h> |
#include <linux/module.h> |
#include <drm/drmP.h> |
#include <drm/drm.h> |
#include "radeon.h" |
#include "r600d.h" |
/* 1 second timeout */ |
#define UVD_IDLE_TIMEOUT_MS 1000 |
/* Firmware Names */ |
#define FIRMWARE_RV710 "radeon/RV710_uvd.bin" |
#define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" |
#define FIRMWARE_SUMO "radeon/SUMO_uvd.bin" |
#define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin" |
#define FIRMWARE_BONAIRE "radeon/BONAIRE_uvd.bin" |
MODULE_FIRMWARE(FIRMWARE_RV710); |
MODULE_FIRMWARE(FIRMWARE_CYPRESS); |
MODULE_FIRMWARE(FIRMWARE_SUMO); |
MODULE_FIRMWARE(FIRMWARE_TAHITI); |
MODULE_FIRMWARE(FIRMWARE_BONAIRE); |
static void radeon_uvd_idle_work_handler(struct work_struct *work); |
int radeon_uvd_init(struct radeon_device *rdev) |
{ |
unsigned long bo_size; |
const char *fw_name; |
int i, r; |
// INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); |
switch (rdev->family) { |
case CHIP_RV710: |
case CHIP_RV730: |
case CHIP_RV740: |
fw_name = FIRMWARE_RV710; |
break; |
case CHIP_CYPRESS: |
case CHIP_HEMLOCK: |
case CHIP_JUNIPER: |
case CHIP_REDWOOD: |
case CHIP_CEDAR: |
fw_name = FIRMWARE_CYPRESS; |
break; |
case CHIP_SUMO: |
case CHIP_SUMO2: |
case CHIP_PALM: |
case CHIP_CAYMAN: |
case CHIP_BARTS: |
case CHIP_TURKS: |
case CHIP_CAICOS: |
fw_name = FIRMWARE_SUMO; |
break; |
case CHIP_TAHITI: |
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; |
default: |
return -EINVAL; |
} |
r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); |
if (r) { |
dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", |
fw_name); |
return r; |
} |
bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + |
RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; |
r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->uvd.vcpu_bo); |
if (r) { |
dev_err(rdev->dev, "(%d) failed to allocate UVD bo\n", r); |
return r; |
} |
r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); |
if (r) { |
radeon_bo_unref(&rdev->uvd.vcpu_bo); |
dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); |
return r; |
} |
r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, |
&rdev->uvd.gpu_addr); |
if (r) { |
radeon_bo_unreserve(rdev->uvd.vcpu_bo); |
radeon_bo_unref(&rdev->uvd.vcpu_bo); |
dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); |
return r; |
} |
r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); |
if (r) { |
dev_err(rdev->dev, "(%d) UVD map failed\n", r); |
return r; |
} |
radeon_bo_unreserve(rdev->uvd.vcpu_bo); |
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { |
atomic_set(&rdev->uvd.handles[i], 0); |
rdev->uvd.filp[i] = NULL; |
rdev->uvd.img_size[i] = 0; |
} |
return 0; |
} |
void radeon_uvd_fini(struct radeon_device *rdev) |
{ |
int r; |
if (rdev->uvd.vcpu_bo == NULL) |
return; |
r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); |
if (!r) { |
radeon_bo_kunmap(rdev->uvd.vcpu_bo); |
radeon_bo_unpin(rdev->uvd.vcpu_bo); |
radeon_bo_unreserve(rdev->uvd.vcpu_bo); |
} |
radeon_bo_unref(&rdev->uvd.vcpu_bo); |
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]); |
release_firmware(rdev->uvd_fw); |
} |
int radeon_uvd_suspend(struct radeon_device *rdev) |
{ |
unsigned size; |
void *ptr; |
int i; |
if (rdev->uvd.vcpu_bo == NULL) |
return 0; |
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) |
if (atomic_read(&rdev->uvd.handles[i])) |
break; |
if (i == RADEON_MAX_UVD_HANDLES) |
return 0; |
size = radeon_bo_size(rdev->uvd.vcpu_bo); |
size -= rdev->uvd_fw->size; |
ptr = rdev->uvd.cpu_addr; |
ptr += rdev->uvd_fw->size; |
rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); |
memcpy(rdev->uvd.saved_bo, ptr, size); |
return 0; |
} |
int radeon_uvd_resume(struct radeon_device *rdev) |
{ |
unsigned size; |
void *ptr; |
if (rdev->uvd.vcpu_bo == NULL) |
return -EINVAL; |
memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size); |
size = radeon_bo_size(rdev->uvd.vcpu_bo); |
size -= rdev->uvd_fw->size; |
ptr = rdev->uvd.cpu_addr; |
ptr += rdev->uvd_fw->size; |
if (rdev->uvd.saved_bo != NULL) { |
memcpy(ptr, rdev->uvd.saved_bo, size); |
kfree(rdev->uvd.saved_bo); |
rdev->uvd.saved_bo = NULL; |
} else |
memset(ptr, 0, size); |
return 0; |
} |
void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo) |
{ |
rbo->placement.fpfn = 0 >> PAGE_SHIFT; |
rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; |
} |
void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) |
{ |
int i, r; |
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { |
uint32_t handle = atomic_read(&rdev->uvd.handles[i]); |
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) { |
DRM_ERROR("Error destroying UVD (%d)!\n", r); |
continue; |
} |
radeon_fence_wait(fence, false); |
radeon_fence_unref(&fence); |
rdev->uvd.filp[i] = NULL; |
atomic_set(&rdev->uvd.handles[i], 0); |
} |
} |
} |
static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) |
{ |
unsigned stream_type = msg[4]; |
unsigned width = msg[6]; |
unsigned height = msg[7]; |
unsigned dpb_size = msg[9]; |
unsigned pitch = msg[28]; |
unsigned width_in_mb = width / 16; |
unsigned height_in_mb = ALIGN(height / 16, 2); |
unsigned image_size, tmp, min_dpb_size; |
image_size = width * height; |
image_size += image_size / 2; |
image_size = ALIGN(image_size, 1024); |
switch (stream_type) { |
case 0: /* H264 */ |
/* reference picture buffer */ |
min_dpb_size = image_size * 17; |
/* macroblock context buffer */ |
min_dpb_size += width_in_mb * height_in_mb * 17 * 192; |
/* IT surface buffer */ |
min_dpb_size += width_in_mb * height_in_mb * 32; |
break; |
case 1: /* VC1 */ |
/* reference picture buffer */ |
min_dpb_size = image_size * 3; |
/* CONTEXT_BUFFER */ |
min_dpb_size += width_in_mb * height_in_mb * 128; |
/* IT surface buffer */ |
min_dpb_size += width_in_mb * 64; |
/* DB surface buffer */ |
min_dpb_size += width_in_mb * 128; |
/* BP */ |
tmp = max(width_in_mb, height_in_mb); |
min_dpb_size += ALIGN(tmp * 7 * 16, 64); |
break; |
case 3: /* MPEG2 */ |
/* reference picture buffer */ |
min_dpb_size = image_size * 3; |
break; |
case 4: /* MPEG4 */ |
/* reference picture buffer */ |
min_dpb_size = image_size * 3; |
/* CM */ |
min_dpb_size += width_in_mb * height_in_mb * 64; |
/* IT surface buffer */ |
min_dpb_size += ALIGN(width_in_mb * height_in_mb * 32, 64); |
break; |
default: |
DRM_ERROR("UVD codec not handled %d!\n", stream_type); |
return -EINVAL; |
} |
if (width > pitch) { |
DRM_ERROR("Invalid UVD decoding target pitch!\n"); |
return -EINVAL; |
} |
if (dpb_size < min_dpb_size) { |
DRM_ERROR("Invalid dpb_size in UVD message (%d / %d)!\n", |
dpb_size, min_dpb_size); |
return -EINVAL; |
} |
buf_sizes[0x1] = dpb_size; |
buf_sizes[0x2] = image_size; |
return 0; |
} |
static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, |
unsigned offset, unsigned buf_sizes[]) |
{ |
int32_t *msg, msg_type, handle; |
unsigned img_size = 0; |
void *ptr; |
int i, r; |
if (offset & 0x3F) { |
DRM_ERROR("UVD messages must be 64 byte aligned!\n"); |
return -EINVAL; |
} |
if (bo->tbo.sync_obj) { |
r = radeon_fence_wait(bo->tbo.sync_obj, false); |
if (r) { |
DRM_ERROR("Failed waiting for UVD message (%d)!\n", r); |
return r; |
} |
} |
r = radeon_bo_kmap(bo, &ptr); |
if (r) { |
DRM_ERROR("Failed mapping the UVD message (%d)!\n", r); |
return r; |
} |
msg = ptr + offset; |
msg_type = msg[1]; |
handle = msg[2]; |
if (handle == 0) { |
DRM_ERROR("Invalid UVD handle!\n"); |
return -EINVAL; |
} |
if (msg_type == 1) { |
/* it's a decode msg, calc buffer sizes */ |
r = radeon_uvd_cs_msg_decode(msg, buf_sizes); |
/* calc image size (width * height) */ |
img_size = msg[6] * msg[7]; |
radeon_bo_kunmap(bo); |
if (r) |
return r; |
} else if (msg_type == 2) { |
/* it's a destroy msg, free the handle */ |
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) |
atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); |
radeon_bo_kunmap(bo); |
return 0; |
} else { |
/* it's a create msg, calc image size (width * height) */ |
img_size = msg[7] * msg[8]; |
radeon_bo_kunmap(bo); |
if (msg_type != 0) { |
DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); |
return -EINVAL; |
} |
/* it's a create msg, no special handling needed */ |
} |
/* create or decode, validate the handle */ |
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { |
if (atomic_read(&p->rdev->uvd.handles[i]) == handle) |
return 0; |
} |
/* handle not found try to alloc a new one */ |
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { |
if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { |
p->rdev->uvd.filp[i] = p->filp; |
p->rdev->uvd.img_size[i] = img_size; |
return 0; |
} |
} |
DRM_ERROR("No more free UVD handles!\n"); |
return -EINVAL; |
} |
static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, |
int data0, int data1, |
unsigned buf_sizes[], bool *has_msg_cmd) |
{ |
struct radeon_cs_chunk *relocs_chunk; |
struct radeon_cs_reloc *reloc; |
unsigned idx, cmd, offset; |
uint64_t start, end; |
int r; |
relocs_chunk = &p->chunks[p->chunk_relocs_idx]; |
offset = radeon_get_ib_value(p, data0); |
idx = radeon_get_ib_value(p, data1); |
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[data0] = start & 0xFFFFFFFF; |
p->ib.ptr[data1] = start >> 32; |
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]); |
return -EINVAL; |
} |
} else if (cmd != 0x100) { |
DRM_ERROR("invalid UVD command %X!\n", cmd); |
return -EINVAL; |
} |
if ((start >> 28) != ((end - 1) >> 28)) { |
DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n", |
start, end); |
return -EINVAL; |
} |
/* 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); |
return -EINVAL; |
} |
if (cmd == 0) { |
if (*has_msg_cmd) { |
DRM_ERROR("More than one message in a UVD-IB!\n"); |
return -EINVAL; |
} |
*has_msg_cmd = true; |
r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes); |
if (r) |
return r; |
} else if (!*has_msg_cmd) { |
DRM_ERROR("Message needed before other commands are send!\n"); |
return -EINVAL; |
} |
return 0; |
} |
static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, |
struct radeon_cs_packet *pkt, |
int *data0, int *data1, |
unsigned buf_sizes[], |
bool *has_msg_cmd) |
{ |
int i, r; |
p->idx++; |
for (i = 0; i <= pkt->count; ++i) { |
switch (pkt->reg + i*4) { |
case UVD_GPCOM_VCPU_DATA0: |
*data0 = p->idx; |
break; |
case UVD_GPCOM_VCPU_DATA1: |
*data1 = p->idx; |
break; |
case UVD_GPCOM_VCPU_CMD: |
r = radeon_uvd_cs_reloc(p, *data0, *data1, |
buf_sizes, has_msg_cmd); |
if (r) |
return r; |
break; |
case UVD_ENGINE_CNTL: |
break; |
default: |
DRM_ERROR("Invalid reg 0x%X!\n", |
pkt->reg + i*4); |
return -EINVAL; |
} |
p->idx++; |
} |
return 0; |
} |
int radeon_uvd_cs_parse(struct radeon_cs_parser *p) |
{ |
struct radeon_cs_packet pkt; |
int r, data0 = 0, data1 = 0; |
/* does the IB has a msg command */ |
bool has_msg_cmd = false; |
/* minimum buffer sizes */ |
unsigned buf_sizes[] = { |
[0x00000000] = 2048, |
[0x00000001] = 32 * 1024 * 1024, |
[0x00000002] = 2048 * 1152 * 3, |
[0x00000003] = 2048, |
}; |
if (p->chunks[p->chunk_ib_idx].length_dw % 16) { |
DRM_ERROR("UVD IB length (%d) not 16 dwords aligned!\n", |
p->chunks[p->chunk_ib_idx].length_dw); |
return -EINVAL; |
} |
if (p->chunk_relocs_idx == -1) { |
DRM_ERROR("No relocation chunk !\n"); |
return -EINVAL; |
} |
do { |
r = radeon_cs_packet_parse(p, &pkt, p->idx); |
if (r) |
return r; |
switch (pkt.type) { |
case RADEON_PACKET_TYPE0: |
r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1, |
buf_sizes, &has_msg_cmd); |
if (r) |
return r; |
break; |
case RADEON_PACKET_TYPE2: |
p->idx += pkt.count + 2; |
break; |
default: |
DRM_ERROR("Unknown packet type %d !\n", pkt.type); |
return -EINVAL; |
} |
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); |
if (!has_msg_cmd) { |
DRM_ERROR("UVD-IBs need a msg command!\n"); |
return -EINVAL; |
} |
return 0; |
} |
static int radeon_uvd_send_msg(struct radeon_device *rdev, |
int ring, struct radeon_bo *bo, |
struct radeon_fence **fence) |
{ |
struct ttm_validate_buffer tv; |
struct ww_acquire_ctx ticket; |
struct list_head head; |
struct radeon_ib ib; |
uint64_t addr; |
int i, 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; |
radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM); |
radeon_uvd_force_into_uvd_segment(bo); |
r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); |
if (r) |
goto err; |
r = radeon_ib_get(rdev, ring, &ib, NULL, 64); |
if (r) |
goto err; |
addr = radeon_bo_gpu_offset(bo); |
ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0); |
ib.ptr[1] = addr; |
ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0); |
ib.ptr[3] = addr >> 32; |
ib.ptr[4] = PACKET0(UVD_GPCOM_VCPU_CMD, 0); |
ib.ptr[5] = 0; |
for (i = 6; i < 16; ++i) |
ib.ptr[i] = PACKET2(0); |
ib.length_dw = 16; |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
if (r) |
goto err; |
ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence); |
if (fence) |
*fence = radeon_fence_ref(ib.fence); |
radeon_ib_free(rdev, &ib); |
radeon_bo_unref(&bo); |
return 0; |
err: |
ttm_eu_backoff_reservation(&ticket, &head); |
return r; |
} |
/* multiple fence commands without any stream commands in between can |
crash the vcpu so just try to emmit a dummy create/destroy msg to |
avoid this */ |
int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, |
uint32_t handle, struct radeon_fence **fence) |
{ |
struct radeon_bo *bo; |
uint32_t *msg; |
int r, i; |
r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, 0, NULL, &bo); |
if (r) |
return r; |
r = radeon_bo_reserve(bo, false); |
if (r) { |
radeon_bo_unref(&bo); |
return r; |
} |
r = radeon_bo_kmap(bo, (void **)&msg); |
if (r) { |
radeon_bo_unreserve(bo); |
radeon_bo_unref(&bo); |
return r; |
} |
/* stitch together an UVD create msg */ |
msg[0] = cpu_to_le32(0x00000de4); |
msg[1] = cpu_to_le32(0x00000000); |
msg[2] = cpu_to_le32(handle); |
msg[3] = cpu_to_le32(0x00000000); |
msg[4] = cpu_to_le32(0x00000000); |
msg[5] = cpu_to_le32(0x00000000); |
msg[6] = cpu_to_le32(0x00000000); |
msg[7] = cpu_to_le32(0x00000780); |
msg[8] = cpu_to_le32(0x00000440); |
msg[9] = cpu_to_le32(0x00000000); |
msg[10] = cpu_to_le32(0x01b37000); |
for (i = 11; i < 1024; ++i) |
msg[i] = cpu_to_le32(0x0); |
radeon_bo_kunmap(bo); |
radeon_bo_unreserve(bo); |
return radeon_uvd_send_msg(rdev, ring, bo, fence); |
} |
int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, |
uint32_t handle, struct radeon_fence **fence) |
{ |
struct radeon_bo *bo; |
uint32_t *msg; |
int r, i; |
r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, 0, NULL, &bo); |
if (r) |
return r; |
r = radeon_bo_reserve(bo, false); |
if (r) { |
radeon_bo_unref(&bo); |
return r; |
} |
r = radeon_bo_kmap(bo, (void **)&msg); |
if (r) { |
radeon_bo_unreserve(bo); |
radeon_bo_unref(&bo); |
return r; |
} |
/* stitch together an UVD destroy msg */ |
msg[0] = cpu_to_le32(0x00000de4); |
msg[1] = cpu_to_le32(0x00000002); |
msg[2] = cpu_to_le32(handle); |
msg[3] = cpu_to_le32(0x00000000); |
for (i = 4; i < 1024; ++i) |
msg[i] = cpu_to_le32(0x0); |
radeon_bo_kunmap(bo); |
radeon_bo_unreserve(bo); |
return radeon_uvd_send_msg(rdev, ring, bo, fence); |
} |
/** |
* radeon_uvd_count_handles - count number of open streams |
* |
* @rdev: radeon_device pointer |
* @sd: number of SD streams |
* @hd: number of HD streams |
* |
* Count the number of open SD/HD streams as a hint for power mangement |
*/ |
static void radeon_uvd_count_handles(struct radeon_device *rdev, |
unsigned *sd, unsigned *hd) |
{ |
unsigned i; |
*sd = 0; |
*hd = 0; |
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { |
if (!atomic_read(&rdev->uvd.handles[i])) |
continue; |
if (rdev->uvd.img_size[i] >= 720*576) |
++(*hd); |
else |
++(*sd); |
} |
} |
static void radeon_uvd_idle_work_handler(struct work_struct *work) |
{ |
struct radeon_device *rdev = |
container_of(work, struct radeon_device, uvd.idle_work.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); |
} |
} else { |
schedule_delayed_work(&rdev->uvd.idle_work, |
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS)); |
} |
} |
void radeon_uvd_note_usage(struct radeon_device *rdev) |
{ |
bool streams_changed = false; |
bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work); |
set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work, |
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS)); |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { |
unsigned hd = 0, sd = 0; |
radeon_uvd_count_handles(rdev, &sd, &hd); |
if ((rdev->pm.dpm.sd != sd) || |
(rdev->pm.dpm.hd != hd)) { |
rdev->pm.dpm.sd = sd; |
rdev->pm.dpm.hd = hd; |
/* disable this for now */ |
/*streams_changed = true;*/ |
} |
} |
if (set_clocks || streams_changed) { |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { |
radeon_dpm_enable_uvd(rdev, true); |
} else { |
radeon_set_uvd_clocks(rdev, 53300, 40000); |
} |
} |
} |
static unsigned radeon_uvd_calc_upll_post_div(unsigned vco_freq, |
unsigned target_freq, |
unsigned pd_min, |
unsigned pd_even) |
{ |
unsigned post_div = vco_freq / target_freq; |
/* adjust to post divider minimum value */ |
if (post_div < pd_min) |
post_div = pd_min; |
/* we alway need a frequency less than or equal the target */ |
if ((vco_freq / post_div) > target_freq) |
post_div += 1; |
/* post dividers above a certain value must be even */ |
if (post_div > pd_even && post_div % 2) |
post_div += 1; |
return post_div; |
} |
/** |
* radeon_uvd_calc_upll_dividers - calc UPLL clock dividers |
* |
* @rdev: radeon_device pointer |
* @vclk: wanted VCLK |
* @dclk: wanted DCLK |
* @vco_min: minimum VCO frequency |
* @vco_max: maximum VCO frequency |
* @fb_factor: factor to multiply vco freq with |
* @fb_mask: limit and bitmask for feedback divider |
* @pd_min: post divider minimum |
* @pd_max: post divider maximum |
* @pd_even: post divider must be even above this value |
* @optimal_fb_div: resulting feedback divider |
* @optimal_vclk_div: resulting vclk post divider |
* @optimal_dclk_div: resulting dclk post divider |
* |
* Calculate dividers for UVDs UPLL (R6xx-SI, except APUs). |
* Returns zero on success -EINVAL on error. |
*/ |
int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev, |
unsigned vclk, unsigned dclk, |
unsigned vco_min, unsigned vco_max, |
unsigned fb_factor, unsigned fb_mask, |
unsigned pd_min, unsigned pd_max, |
unsigned pd_even, |
unsigned *optimal_fb_div, |
unsigned *optimal_vclk_div, |
unsigned *optimal_dclk_div) |
{ |
unsigned vco_freq, ref_freq = rdev->clock.spll.reference_freq; |
/* start off with something large */ |
unsigned optimal_score = ~0; |
/* loop through vco from low to high */ |
vco_min = max(max(vco_min, vclk), dclk); |
for (vco_freq = vco_min; vco_freq <= vco_max; vco_freq += 100) { |
uint64_t fb_div = (uint64_t)vco_freq * fb_factor; |
unsigned vclk_div, dclk_div, score; |
do_div(fb_div, ref_freq); |
/* fb div out of range ? */ |
if (fb_div > fb_mask) |
break; /* it can oly get worse */ |
fb_div &= fb_mask; |
/* calc vclk divider with current vco freq */ |
vclk_div = radeon_uvd_calc_upll_post_div(vco_freq, vclk, |
pd_min, pd_even); |
if (vclk_div > pd_max) |
break; /* vco is too big, it has to stop */ |
/* calc dclk divider with current vco freq */ |
dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk, |
pd_min, pd_even); |
if (vclk_div > pd_max) |
break; /* vco is too big, it has to stop */ |
/* calc score with current vco freq */ |
score = vclk - (vco_freq / vclk_div) + dclk - (vco_freq / dclk_div); |
/* determine if this vco setting is better than current optimal settings */ |
if (score < optimal_score) { |
*optimal_fb_div = fb_div; |
*optimal_vclk_div = vclk_div; |
*optimal_dclk_div = dclk_div; |
optimal_score = score; |
if (optimal_score == 0) |
break; /* it can't get better than this */ |
} |
} |
/* did we found a valid setup ? */ |
if (optimal_score == ~0) |
return -EINVAL; |
return 0; |
} |
int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, |
unsigned cg_upll_func_cntl) |
{ |
unsigned i; |
/* make sure UPLL_CTLREQ is deasserted */ |
WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK); |
mdelay(10); |
/* assert UPLL_CTLREQ */ |
WREG32_P(cg_upll_func_cntl, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK); |
/* wait for CTLACK and CTLACK2 to get asserted */ |
for (i = 0; i < 100; ++i) { |
uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK; |
if ((RREG32(cg_upll_func_cntl) & mask) == mask) |
break; |
mdelay(10); |
} |
/* deassert UPLL_CTLREQ */ |
WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK); |
if (i == 100) { |
DRM_ERROR("Timeout setting UVD clocks!\n"); |
return -ETIMEDOUT; |
} |
return 0; |
} |
/drivers/video/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, 0, 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, false); |
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, false); |
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, false); |
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; |
} |
/drivers/video/drm/radeon/radeon_vm.c |
---|
0,0 → 1,1179 |
/* |
* 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! */ |
if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) { |
trace_radeon_vm_flush(pd_addr, ring, vm->id); |
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->it.start = 0; |
bo_va->it.last = 0; |
bo_va->flags = 0; |
bo_va->addr = 0; |
bo_va->ref_count = 1; |
INIT_LIST_HEAD(&bo_va->bo_list); |
INIT_LIST_HEAD(&bo_va->vm_status); |
mutex_lock(&vm->mutex); |
list_add_tail(&bo_va->bo_list, &bo->va); |
mutex_unlock(&vm->mutex); |
return bo_va; |
} |
/** |
* radeon_vm_set_pages - helper to call the right asic function |
* |
* @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: hw access flags |
* |
* Traces the parameters and calls the right asic functions |
* to setup the page table using the DMA. |
*/ |
static void radeon_vm_set_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags) |
{ |
trace_radeon_vm_set_page(pe, addr, count, incr, flags); |
if ((flags & R600_PTE_GART_MASK) == R600_PTE_GART_MASK) { |
uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8; |
radeon_asic_vm_copy_pages(rdev, ib, pe, src, count); |
} else if ((flags & R600_PTE_SYSTEM) || (count < 3)) { |
radeon_asic_vm_write_pages(rdev, ib, pe, addr, |
count, incr, flags); |
} else { |
radeon_asic_vm_set_pages(rdev, ib, pe, addr, |
count, incr, flags); |
} |
} |
/** |
* 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, 256); |
if (r) |
goto error; |
ib.length_dw = 0; |
radeon_vm_set_pages(rdev, &ib, addr, 0, entries, 0, 0); |
radeon_asic_vm_pad_ib(rdev, &ib); |
WARN_ON(ib.length_dw > 64); |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
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); |
struct radeon_vm *vm = bo_va->vm; |
unsigned last_pfn, pt_idx; |
uint64_t eoffset; |
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); |
if (bo_va->it.start || bo_va->it.last) { |
if (bo_va->addr) { |
/* add a clone of the bo_va to clear the old address */ |
struct radeon_bo_va *tmp; |
tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); |
if (!tmp) { |
mutex_unlock(&vm->mutex); |
return -ENOMEM; |
} |
tmp->it.start = bo_va->it.start; |
tmp->it.last = bo_va->it.last; |
tmp->vm = vm; |
tmp->addr = bo_va->addr; |
tmp->bo = radeon_bo_ref(bo_va->bo); |
list_add(&tmp->vm_status, &vm->freed); |
} |
interval_tree_remove(&bo_va->it, &vm->va); |
bo_va->it.start = 0; |
bo_va->it.last = 0; |
} |
soffset /= RADEON_GPU_PAGE_SIZE; |
eoffset /= RADEON_GPU_PAGE_SIZE; |
if (soffset || eoffset) { |
struct interval_tree_node *it; |
it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1); |
if (it) { |
struct radeon_bo_va *tmp; |
tmp = container_of(it, struct radeon_bo_va, it); |
/* bo and tmp overlap, invalid offset */ |
dev_err(rdev->dev, "bo %p va 0x%010Lx conflict with " |
"(bo %p 0x%010lx 0x%010lx)\n", bo_va->bo, |
soffset, tmp->bo, tmp->it.start, tmp->it.last); |
mutex_unlock(&vm->mutex); |
return -EINVAL; |
} |
bo_va->it.start = soffset; |
bo_va->it.last = eoffset - 1; |
interval_tree_insert(&bo_va->it, &vm->va); |
} |
bo_va->flags = flags; |
bo_va->addr = 0; |
soffset >>= radeon_vm_block_size; |
eoffset >>= 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, 0, 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 * 6; |
/* 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_vm_set_pages(rdev, &ib, last_pde, |
last_pt, count, incr, |
R600_PTE_VALID); |
} |
count = 1; |
last_pde = pde; |
last_pt = pt; |
} else { |
++count; |
} |
} |
if (count) |
radeon_vm_set_pages(rdev, &ib, last_pde, last_pt, count, |
incr, R600_PTE_VALID); |
if (ib.length_dw != 0) { |
radeon_asic_vm_pad_ib(rdev, &ib); |
radeon_semaphore_sync_to(ib.semaphore, pd->tbo.sync_obj); |
radeon_semaphore_sync_to(ib.semaphore, vm->last_id_use); |
WARN_ON(ib.length_dw > ndw); |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
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_vm_set_pages(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_vm_set_pages(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_vm_set_pages(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_vm_set_pages(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; |
/* 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, ncmds, ndw; |
uint64_t addr; |
uint32_t flags; |
int r; |
if (!bo_va->it.start) { |
dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n", |
bo_va->bo, vm); |
return -EINVAL; |
} |
list_del_init(&bo_va->vm_status); |
bo_va->flags &= ~RADEON_VM_PAGE_VALID; |
bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; |
bo_va->flags &= ~RADEON_VM_PAGE_SNOOPED; |
if (mem) { |
addr = mem->start << PAGE_SHIFT; |
if (mem->mem_type != TTM_PL_SYSTEM) { |
bo_va->flags |= RADEON_VM_PAGE_VALID; |
} |
if (mem->mem_type == TTM_PL_TT) { |
bo_va->flags |= RADEON_VM_PAGE_SYSTEM; |
if (!(bo_va->bo->flags & (RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC))) |
bo_va->flags |= RADEON_VM_PAGE_SNOOPED; |
} else { |
addr += rdev->vm_manager.vram_base_offset; |
} |
} else { |
addr = 0; |
} |
if (addr == bo_va->addr) |
return 0; |
bo_va->addr = addr; |
trace_radeon_vm_bo_update(bo_va); |
nptes = bo_va->it.last - bo_va->it.start + 1; |
/* reserve space for one command every (1 << BLOCK_SIZE) entries |
or 2k dwords (whatever is smaller) */ |
ncmds = (nptes >> min(radeon_vm_block_size, 11)) + 1; |
/* padding, etc. */ |
ndw = 64; |
flags = radeon_vm_page_flags(bo_va->flags); |
if ((flags & R600_PTE_GART_MASK) == R600_PTE_GART_MASK) { |
/* only copy commands needed */ |
ndw += ncmds * 7; |
} else if (flags & R600_PTE_SYSTEM) { |
/* header for write data commands */ |
ndw += ncmds * 4; |
/* body of write data command */ |
ndw += nptes * 2; |
} else { |
/* set page commands needed */ |
ndw += ncmds * 10; |
/* two extra commands for begin/end of fragment */ |
ndw += 2 * 10; |
} |
/* 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->it.start, |
bo_va->it.last + 1, addr, |
radeon_vm_page_flags(bo_va->flags)); |
radeon_asic_vm_pad_ib(rdev, &ib); |
WARN_ON(ib.length_dw > ndw); |
radeon_semaphore_sync_to(ib.semaphore, vm->fence); |
r = radeon_ib_schedule(rdev, &ib, NULL, false); |
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) { |
r = radeon_vm_bo_update(rdev, bo_va, NULL); |
radeon_bo_unref(&bo_va->bo); |
kfree(bo_va); |
if (r) |
return r; |
} |
return 0; |
} |
/** |
* radeon_vm_clear_invalids - clear invalidated BOs in the PT |
* |
* @rdev: radeon_device pointer |
* @vm: requested vm |
* |
* Make sure all invalidated BOs are cleared in the PT. |
* Returns 0 for success. |
* |
* PTs have to be reserved and mutex must be locked! |
*/ |
int radeon_vm_clear_invalids(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->invalidated, vm_status) { |
r = radeon_vm_bo_update(rdev, bo_va, NULL); |
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); |
interval_tree_remove(&bo_va->it, &vm->va); |
list_del(&bo_va->vm_status); |
if (bo_va->addr) { |
bo_va->bo = radeon_bo_ref(bo_va->bo); |
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) { |
if (bo_va->addr) { |
mutex_lock(&bo_va->vm->mutex); |
list_del(&bo_va->vm_status); |
list_add(&bo_va->vm_status, &bo_va->vm->invalidated); |
mutex_unlock(&bo_va->vm->mutex); |
} |
} |
} |
/** |
* 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); |
vm->va = RB_ROOT; |
INIT_LIST_HEAD(&vm->invalidated); |
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, 0, 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 (!RB_EMPTY_ROOT(&vm->va)) { |
dev_err(rdev->dev, "still active bo inside vm\n"); |
} |
rbtree_postorder_for_each_entry_safe(bo_va, tmp, &vm->va, it.rb) { |
interval_tree_remove(&bo_va->it, &vm->va); |
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) { |
radeon_bo_unref(&bo_va->bo); |
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); |
} |
/drivers/video/drm/radeon/rdisplay.c |
---|
1,8 → 1,8 |
#include <drm/drmP.h> |
#include <drm/radeon_drm.h> |
#include <drm.h> |
#include <drm_mm.h> |
#include "radeon_drm.h" |
#include "radeon.h" |
#include "radeon_object.h" |
#include "bitmap.h" |
11,7 → 11,7 |
#include "r100d.h" |
display_t *rdisplay; |
display_t *os_display; |
static cursor_t* __stdcall select_cursor(cursor_t *cursor); |
static void __stdcall move_cursor(cursor_t *cursor, int x, int y); |
31,10 → 31,10 |
int i,j; |
int r; |
rdev = (struct radeon_device *)rdisplay->ddev->dev_private; |
rdev = (struct radeon_device *)os_display->ddev->dev_private; |
r = radeon_bo_create(rdev, CURSOR_WIDTH*CURSOR_HEIGHT*4, |
PAGE_SIZE, false, RADEON_GEM_DOMAIN_VRAM, NULL, &cursor->robj); |
PAGE_SIZE, false, RADEON_GEM_DOMAIN_VRAM, 0, NULL, &cursor->robj); |
if (unlikely(r != 0)) |
return r; |
82,7 → 82,7 |
static void radeon_show_cursor() |
{ |
struct radeon_device *rdev = (struct radeon_device *)rdisplay->ddev->dev_private; |
struct radeon_device *rdev = (struct radeon_device *)os_display->ddev->dev_private; |
if (ASIC_IS_DCE4(rdev)) { |
107,11 → 107,11 |
cursor_t *old; |
uint32_t gpu_addr; |
rdev = (struct radeon_device *)rdisplay->ddev->dev_private; |
rdev = (struct radeon_device *)os_display->ddev->dev_private; |
old = rdisplay->cursor; |
old = os_display->cursor; |
rdisplay->cursor = cursor; |
os_display->cursor = cursor; |
gpu_addr = radeon_bo_gpu_offset(cursor->robj); |
if (ASIC_IS_DCE4(rdev)) |
136,7 → 136,7 |
{ |
struct radeon_device *rdev; |
rdev = (struct radeon_device *)rdisplay->ddev->dev_private; |
rdev = (struct radeon_device *)os_display->ddev->dev_private; |
uint32_t cur_lock; |
168,7 → 168,7 |
void __stdcall move_cursor(cursor_t *cursor, int x, int y) |
{ |
struct radeon_device *rdev; |
rdev = (struct radeon_device *)rdisplay->ddev->dev_private; |
rdev = (struct radeon_device *)os_display->ddev->dev_private; |
int hot_x = cursor->hot_x; |
int hot_y = cursor->hot_y; |
233,26 → 233,26 |
ENTER(); |
rdisplay = GetDisplay(); |
os_display = GetDisplay(); |
dev = rdisplay->ddev = rdev->ddev; |
dev = os_display->ddev = rdev->ddev; |
ifl = safe_cli(); |
{ |
list_for_each_entry(cursor, &rdisplay->cursors, list) |
list_for_each_entry(cursor, &os_display->cursors, list) |
{ |
init_cursor(cursor); |
}; |
rdisplay->restore_cursor(0,0); |
rdisplay->init_cursor = init_cursor; |
rdisplay->select_cursor = select_cursor; |
rdisplay->show_cursor = NULL; |
rdisplay->move_cursor = move_cursor; |
rdisplay->restore_cursor = restore_cursor; |
rdisplay->disable_mouse = disable_mouse; |
os_display->restore_cursor(0,0); |
os_display->init_cursor = init_cursor; |
os_display->select_cursor = select_cursor; |
os_display->show_cursor = NULL; |
os_display->move_cursor = move_cursor; |
os_display->restore_cursor = restore_cursor; |
os_display->disable_mouse = disable_mouse; |
select_cursor(rdisplay->cursor); |
select_cursor(os_display->cursor); |
radeon_show_cursor(); |
}; |
safe_sti(ifl); |
/drivers/video/drm/radeon/rdisplay_kms.c |
---|
1,8 → 1,8 |
#include <drm/drmP.h> |
#include <drm/radeon_drm.h> |
#include <drm.h> |
#include <drm_mm.h> |
#include "radeon_drm.h" |
#include "radeon.h" |
#include "radeon_object.h" |
#include "drm_fb_helper.h" |
10,16 → 10,11 |
#include "bitmap.h" |
#include "display.h" |
struct radeon_fbdev { |
struct drm_fb_helper helper; |
struct radeon_framebuffer rfb; |
struct list_head fbdev_list; |
struct radeon_device *rdev; |
}; |
extern struct drm_framebuffer *main_fb; |
extern struct drm_gem_object *main_fb_obj; |
struct radeon_fbdev *kos_rfbdev; |
display_t *os_display; |
static cursor_t* __stdcall select_cursor_kms(cursor_t *cursor); |
static void __stdcall move_cursor_kms(cursor_t *cursor, int x, int y); |
95,12 → 90,12 |
cursor_t *old; |
uint32_t gpu_addr; |
rdev = (struct radeon_device *)rdisplay->ddev->dev_private; |
radeon_crtc = to_radeon_crtc(rdisplay->crtc); |
rdev = (struct radeon_device *)os_display->ddev->dev_private; |
radeon_crtc = to_radeon_crtc(os_display->crtc); |
old = rdisplay->cursor; |
old = os_display->cursor; |
rdisplay->cursor = cursor; |
os_display->cursor = cursor; |
gpu_addr = radeon_bo_gpu_offset(cursor->robj); |
if (ASIC_IS_DCE4(rdev)) { |
125,8 → 120,8 |
void __stdcall move_cursor_kms(cursor_t *cursor, int x, int y) |
{ |
struct radeon_device *rdev; |
rdev = (struct radeon_device *)rdisplay->ddev->dev_private; |
struct drm_crtc *crtc = rdisplay->crtc; |
rdev = (struct radeon_device *)os_display->ddev->dev_private; |
struct drm_crtc *crtc = os_display->crtc; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
int hot_x = cursor->hot_x; |
197,27 → 192,22 |
return name; |
} |
bool set_mode(struct drm_device *dev, struct drm_connector *connector, |
videomode_t *reqmode, bool strict) |
static int set_mode(struct drm_device *dev, struct drm_connector *connector, |
struct drm_crtc *crtc, videomode_t *reqmode, bool strict) |
{ |
struct drm_display_mode *mode = NULL, *tmpmode; |
struct drm_framebuffer *fb = NULL; |
struct drm_mode_set set; |
const char *con_name; |
unsigned hdisplay, vdisplay; |
int ret; |
struct drm_fb_helper *fb_helper; |
drm_modeset_lock_all(dev); |
fb_helper = &kos_rfbdev->helper; |
bool ret = false; |
ENTER(); |
dbgprintf("width %d height %d vrefresh %d\n", |
reqmode->width, reqmode->height, reqmode->freq); |
list_for_each_entry(tmpmode, &connector->modes, head) |
{ |
if( (drm_mode_width(tmpmode) == reqmode->width) && |
(drm_mode_height(tmpmode) == reqmode->height) && |
if( (tmpmode->hdisplay == reqmode->width) && |
(tmpmode->vdisplay == reqmode->height) && |
(drm_mode_vrefresh(tmpmode) == reqmode->freq) ) |
{ |
mode = tmpmode; |
229,8 → 219,8 |
{ |
list_for_each_entry(tmpmode, &connector->modes, head) |
{ |
if( (drm_mode_width(tmpmode) == reqmode->width) && |
(drm_mode_height(tmpmode) == reqmode->height) ) |
if( (tmpmode->hdisplay == reqmode->width) && |
(tmpmode->vdisplay == reqmode->height) ) |
{ |
mode = tmpmode; |
goto do_set; |
238,77 → 228,73 |
}; |
}; |
do_set: |
DRM_ERROR("%s failed\n", __FUNCTION__); |
if( mode != NULL ) |
{ |
struct drm_framebuffer *fb; |
struct drm_encoder *encoder; |
struct drm_crtc *crtc; |
return -1; |
// char con_edid[128]; |
char *con_name; |
char *enc_name; |
do_set: |
encoder = connector->encoder; |
crtc = encoder->crtc; |
con_name = connector->name; |
// fb = list_first_entry(&dev->mode_config.fb_kernel_list, |
// struct drm_framebuffer, filp_head); |
DRM_DEBUG_KMS("set mode %d %d: crtc %d connector %s\n", |
reqmode->width, reqmode->height, crtc->base.id, |
con_name); |
// memcpy(con_edid, connector->edid_blob_ptr->data, 128); |
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
// dbgprintf("Manufacturer: %s Model %x Serial Number %u\n", |
// manufacturer_name(con_edid + 0x08), |
// (unsigned short)(con_edid[0x0A] + (con_edid[0x0B] << 8)), |
// (unsigned int)(con_edid[0x0C] + (con_edid[0x0D] << 8) |
// + (con_edid[0x0E] << 16) + (con_edid[0x0F] << 24))); |
hdisplay = mode->hdisplay; |
vdisplay = mode->vdisplay; |
con_name = drm_get_connector_name(connector); |
enc_name = drm_get_encoder_name(encoder); |
if (crtc->invert_dimensions) |
swap(hdisplay, vdisplay); |
dbgprintf("set mode %d %d connector %s encoder %s\n", |
reqmode->width, reqmode->height, con_name, enc_name); |
fb = main_fb; |
fb = fb_helper->fb; |
fb->width = reqmode->width; |
fb->height = reqmode->height; |
fb->pitches[0] = fb->pitches[1] = fb->pitches[2] = |
fb->pitches[0] = |
fb->pitches[1] = |
fb->pitches[2] = |
fb->pitches[3] = radeon_align_pitch(dev->dev_private, reqmode->width, 32, false) * ((32 + 1) / 8); |
fb->bits_per_pixel = 32; |
fb->depth = 24; |
crtc->fb = fb; |
crtc->enabled = true; |
rdisplay->crtc = crtc; |
os_display->crtc = crtc; |
ret = drm_crtc_helper_set_mode(crtc, mode, 0, 0, fb); |
set.crtc = crtc; |
set.x = 0; |
set.y = 0; |
set.mode = mode; |
set.connectors = &connector; |
set.num_connectors = 1; |
set.fb = fb; |
select_cursor_kms(rdisplay->cursor); |
ret = drm_mode_set_config_internal(&set); |
drm_modeset_unlock_all(dev); |
select_cursor_kms(os_display->cursor); |
radeon_show_cursor_kms(crtc); |
if (ret == true) |
if ( !ret ) |
{ |
rdisplay->width = fb->width; |
rdisplay->height = fb->height; |
rdisplay->pitch = fb->pitches[0]; |
rdisplay->vrefresh = drm_mode_vrefresh(mode); |
os_display->width = fb->width; |
os_display->height = fb->height; |
os_display->vrefresh = drm_mode_vrefresh(mode); |
sysSetScreen(fb->width, fb->height, fb->pitches[0]); |
dbgprintf("new mode %d x %d pitch %d\n", |
DRM_DEBUG_KMS("new mode %d x %d pitch %d\n", |
fb->width, fb->height, fb->pitches[0]); |
} |
else |
DRM_ERROR("failed to set mode %d_%d on crtc %p\n", |
fb->width, fb->height, crtc); |
} |
LEAVE(); |
return ret; |
}; |
} |
static int count_connector_modes(struct drm_connector* connector) |
{ |
322,109 → 308,125 |
return count; |
}; |
static struct drm_connector* get_def_connector(struct drm_device *dev) |
static struct drm_crtc *get_possible_crtc(struct drm_device *dev, struct drm_encoder *encoder) |
{ |
struct drm_connector *connector; |
struct drm_connector_helper_funcs *connector_funcs; |
struct drm_crtc *tmp_crtc; |
int crtc_mask = 1; |
struct drm_connector *def_connector = NULL; |
list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) |
{ |
if (encoder->possible_crtcs & crtc_mask) |
{ |
encoder->crtc = tmp_crtc; |
DRM_DEBUG_KMS("use CRTC %p ID %d\n", tmp_crtc, tmp_crtc->base.id); |
return tmp_crtc; |
}; |
crtc_mask <<= 1; |
}; |
return NULL; |
}; |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
static int choose_config(struct drm_device *dev, struct drm_connector **boot_connector, |
struct drm_crtc **boot_crtc) |
{ |
struct drm_connector_helper_funcs *connector_funcs; |
struct drm_connector *connector; |
struct drm_encoder *encoder; |
struct drm_crtc *crtc; |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
{ |
if( connector->status != connector_status_connected) |
continue; |
encoder = connector->encoder; |
if(encoder == NULL) |
{ |
connector_funcs = connector->helper_private; |
encoder = connector_funcs->best_encoder(connector); |
if( encoder == NULL) |
{ |
DRM_DEBUG_KMS("CONNECTOR %x ID: %d no active encoders\n", |
connector, connector->base.id); |
continue; |
}; |
} |
connector->encoder = encoder; |
crtc = encoder->crtc; |
if(crtc == NULL) |
crtc = get_possible_crtc(dev, encoder); |
dbgprintf("CONNECTOR %x ID: %d status %d encoder %x\n crtc %x", |
connector, connector->base.id, |
connector->status, connector->encoder, |
crtc); |
if(crtc != NULL) |
{ |
*boot_connector = connector; |
*boot_crtc = crtc; |
connector->encoder = encoder; |
DRM_DEBUG_KMS("CONNECTOR %p ID:%d status:%d ENCODER %p ID: %d CRTC %p ID:%d\n", |
connector, connector->base.id, connector->status, |
encoder, encoder->base.id, crtc, crtc->base.id ); |
return 0; |
} |
else |
DRM_DEBUG_KMS("No CRTC for encoder %d\n", encoder->base.id); |
// if (crtc == NULL) |
// continue; |
def_connector = connector; |
break; |
}; |
return def_connector; |
return -ENOENT; |
}; |
static int get_boot_mode(struct drm_connector *connector, videomode_t *usermode) |
{ |
struct drm_display_mode *mode; |
list_for_each_entry(mode, &connector->modes, head) |
{ |
DRM_DEBUG_KMS("check mode w:%d h:%d %dHz\n", |
mode->hdisplay, mode->vdisplay, |
drm_mode_vrefresh(mode)); |
bool init_display_kms(struct radeon_device *rdev, videomode_t *usermode) |
if( os_display->width == mode->hdisplay && |
os_display->height == mode->vdisplay && |
drm_mode_vrefresh(mode) == 60) |
{ |
struct drm_device *dev; |
usermode->width = os_display->width; |
usermode->height = os_display->height; |
usermode->freq = 60; |
return 1; |
} |
} |
return 0; |
} |
struct drm_connector *connector; |
int init_display_kms(struct drm_device *dev, videomode_t *usermode) |
{ |
struct drm_connector_helper_funcs *connector_funcs; |
struct drm_encoder *encoder; |
struct drm_connector *connector = NULL; |
struct drm_crtc *crtc = NULL; |
struct drm_framebuffer *fb; |
struct drm_display_mode *native; |
cursor_t *cursor; |
bool retval = false; |
u32_t ifl; |
int ret; |
struct radeon_fbdev *rfbdev; |
struct drm_fb_helper *fb_helper; |
mutex_lock(&dev->mode_config.mutex); |
int i; |
ENTER(); |
dev = rdev->ddev; |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
ret = choose_config(dev, &connector, &crtc); |
if(ret) |
{ |
if( connector->status != connector_status_connected) |
continue; |
connector_funcs = connector->helper_private; |
encoder = connector_funcs->best_encoder(connector); |
if( encoder == NULL) |
{ |
dbgprintf("CONNECTOR %x ID: %d no active encoders\n", |
connector, connector->base.id); |
continue; |
} |
connector->encoder = encoder; |
dbgprintf("CONNECTOR %x ID: %d status %d encoder %x\n crtc %x\n", |
connector, connector->base.id, |
connector->status, connector->encoder, |
encoder->crtc); |
crtc = encoder->crtc; |
break; |
}; |
if(connector == NULL) |
{ |
dbgprintf("No active connectors!\n"); |
DRM_DEBUG_KMS("No active connectors!\n"); |
mutex_unlock(&dev->mode_config.mutex); |
return -1; |
}; |
{ |
struct drm_display_mode *tmp; |
struct drm_display_mode *tmp, *native = NULL; |
struct radeon_device *rdev = dev->dev_private; |
list_for_each_entry(tmp, &connector->modes, head) { |
if (drm_mode_width(tmp) > 16384 || |
drm_mode_height(tmp) > 16384) |
if (tmp->hdisplay > 16384 || |
tmp->vdisplay > 16384) |
continue; |
if (tmp->type & DRM_MODE_TYPE_PREFERRED) |
{ |
432,122 → 434,97 |
break; |
}; |
} |
} |
if( ASIC_IS_AVIVO(rdev) && native ) |
{ |
dbgprintf("native w %d h %d\n", native->hdisplay, native->vdisplay); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(connector->encoder); |
radeon_encoder->rmx_type = RMX_FULL; |
radeon_encoder->native_mode = *native; |
}; |
} |
#if 0 |
mutex_lock(&dev->object_name_lock); |
idr_preload(GFP_KERNEL); |
if(crtc == NULL) |
{ |
struct drm_crtc *tmp_crtc; |
int crtc_mask = 1; |
if (!main_fb_obj->name) { |
ret = idr_alloc(&dev->object_name_idr, &main_fb_obj, 1, 0, GFP_NOWAIT); |
list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) |
{ |
if (encoder->possible_crtcs & crtc_mask) |
{ |
crtc = tmp_crtc; |
encoder->crtc = crtc; |
break; |
}; |
crtc_mask <<= 1; |
}; |
}; |
main_fb_obj->name = ret; |
if(crtc == NULL) |
{ |
dbgprintf("No CRTC for encoder %d\n", encoder->base.id); |
return -1; |
}; |
/* Allocate a reference for the name table. */ |
drm_gem_object_reference(main_fb_obj); |
DRM_DEBUG_KMS("%s allocate fb name %d\n", __FUNCTION__, main_fb_obj->name ); |
} |
dbgprintf("[Select CRTC:%d]\n", crtc->base.id); |
idr_preload_end(); |
mutex_unlock(&dev->object_name_lock); |
drm_gem_object_unreference(main_fb_obj); |
#endif |
os_display = GetDisplay(); |
os_display->ddev = dev; |
os_display->connector = connector; |
os_display->crtc = crtc; |
// drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); |
os_display->supported_modes = count_connector_modes(connector); |
rdisplay = GetDisplay(); |
rdisplay->ddev = dev; |
rdisplay->connector = connector; |
rdisplay->crtc = crtc; |
rdisplay->supported_modes = count_connector_modes(connector); |
ifl = safe_cli(); |
{ |
list_for_each_entry(cursor, &rdisplay->cursors, list) |
list_for_each_entry(cursor, &os_display->cursors, list) |
{ |
init_cursor(cursor); |
}; |
os_display->restore_cursor(0,0); |
os_display->init_cursor = init_cursor; |
os_display->select_cursor = select_cursor_kms; |
os_display->show_cursor = NULL; |
os_display->move_cursor = move_cursor_kms; |
os_display->restore_cursor = restore_cursor; |
os_display->disable_mouse = disable_mouse; |
select_cursor_kms(os_display->cursor); |
}; |
safe_sti(ifl); |
dbgprintf("current mode %d x %d x %d\n", |
rdisplay->width, rdisplay->height, rdisplay->vrefresh); |
dbgprintf("user mode mode %d x %d x %d\n", |
usermode->width, usermode->height, usermode->freq); |
// dbgprintf("current mode %d x %d x %d\n", |
// os_display->width, os_display->height, os_display->vrefresh); |
// dbgprintf("user mode mode %d x %d x %d\n", |
// usermode->width, usermode->height, usermode->freq); |
if( (usermode->width != 0) && |
(usermode->height != 0) && |
( (usermode->width != rdisplay->width) || |
(usermode->height != rdisplay->height) || |
(usermode->freq != rdisplay->vrefresh) ) ) |
if( (usermode->width == 0) || |
(usermode->height == 0)) |
{ |
if( !get_boot_mode(connector, usermode)) |
{ |
struct drm_display_mode *mode; |
retval = set_mode(dev, rdisplay->connector, usermode, false); |
} |
else |
{ |
usermode->width = rdisplay->width; |
usermode->height = rdisplay->height; |
usermode->freq = 60; |
retval = set_mode(dev, rdisplay->connector, usermode, false); |
mode = list_entry(connector->modes.next, typeof(*mode), head); |
usermode->width = mode->hdisplay; |
usermode->height = mode->vdisplay; |
usermode->freq = drm_mode_vrefresh(mode); |
}; |
}; |
ifl = safe_cli(); |
{ |
rdisplay->restore_cursor(0,0); |
rdisplay->init_cursor = init_cursor; |
rdisplay->select_cursor = select_cursor_kms; |
rdisplay->show_cursor = NULL; |
rdisplay->move_cursor = move_cursor_kms; |
rdisplay->restore_cursor = restore_cursor; |
rdisplay->disable_mouse = disable_mouse; |
mutex_unlock(&dev->mode_config.mutex); |
select_cursor_kms(rdisplay->cursor); |
radeon_show_cursor_kms(rdisplay->crtc); |
}; |
safe_sti(ifl); |
set_mode(dev, os_display->connector, os_display->crtc, usermode, false); |
// init_bitmaps(); |
radeon_show_cursor_kms(os_display->crtc); |
LEAVE(); |
return retval; |
return 0; |
}; |
int get_modes(videomode_t *mode, int *count) |
int get_videomodes(videomode_t *mode, int *count) |
{ |
int err = -1; |
// ENTER(); |
dbgprintf("mode %x count %d\n", mode, *count); |
if( *count == 0 ) |
{ |
*count = rdisplay->supported_modes; |
*count = os_display->supported_modes; |
err = 0; |
} |
else if( mode != NULL ) |
555,15 → 532,15 |
struct drm_display_mode *drmmode; |
int i = 0; |
if( *count > rdisplay->supported_modes) |
*count = rdisplay->supported_modes; |
if( *count > os_display->supported_modes) |
*count = os_display->supported_modes; |
list_for_each_entry(drmmode, &rdisplay->connector->modes, head) |
list_for_each_entry(drmmode, &os_display->connector->modes, head) |
{ |
if( i < *count) |
{ |
mode->width = drm_mode_width(drmmode); |
mode->height = drm_mode_height(drmmode); |
mode->width = drmmode->hdisplay; |
mode->height = drmmode->vdisplay; |
mode->bpp = 32; |
mode->freq = drm_mode_vrefresh(drmmode); |
i++; |
574,109 → 551,30 |
*count = i; |
err = 0; |
}; |
// LEAVE(); |
return err; |
} |
}; |
int set_user_mode(videomode_t *mode) |
{ |
int err = -1; |
// ENTER(); |
dbgprintf("width %d height %d vrefresh %d\n", |
mode->width, mode->height, mode->freq); |
if( (mode->width != 0) && |
(mode->height != 0) && |
(mode->freq != 0 ) && |
( (mode->width != rdisplay->width) || |
(mode->height != rdisplay->height) || |
(mode->freq != rdisplay->vrefresh) ) ) |
( (mode->width != os_display->width) || |
(mode->height != os_display->height) || |
(mode->freq != os_display->vrefresh) ) ) |
{ |
if( set_mode(rdisplay->ddev, rdisplay->connector, mode, true) ) |
err = 0; |
return set_mode(os_display->ddev, os_display->connector, os_display->crtc, mode, true); |
}; |
// LEAVE(); |
return err; |
return -1; |
}; |
int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, |
struct drm_mode_fb_cmd2 *mode_cmd, |
struct drm_gem_object **gobj_p) |
{ |
struct radeon_device *rdev = rfbdev->rdev; |
struct drm_gem_object *gobj = NULL; |
struct radeon_bo *rbo = NULL; |
bool fb_tiled = false; /* useful for testing */ |
u32 tiling_flags = 0; |
int ret; |
int aligned_size, size; |
int height = mode_cmd->height; |
u32 bpp, depth; |
static struct radeon_bo kos_bo; |
static struct drm_mm_node vm_node; |
drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); |
/* need to align pitch with crtc limits */ |
mode_cmd->pitches[0] = radeon_align_pitch(rdev, mode_cmd->width, bpp, |
fb_tiled) * ((bpp + 1) / 8); |
if (rdev->family >= CHIP_R600) |
height = ALIGN(mode_cmd->height, 8); |
size = mode_cmd->pitches[0] * height; |
aligned_size = ALIGN(size, PAGE_SIZE); |
#ifndef __TTM__ |
ret = drm_gem_object_init(rdev->ddev, &kos_bo.gem_base, aligned_size); |
if (unlikely(ret)) { |
printk(KERN_ERR "failed to allocate framebuffer (%d)\n", |
aligned_size); |
return -ENOMEM; |
} |
#endif |
kos_bo.rdev = rdev; |
kos_bo.gem_base.driver_private = NULL; |
kos_bo.surface_reg = -1; |
// kos_bo.domain = RADEON_GEM_DOMAIN_VRAM; |
INIT_LIST_HEAD(&kos_bo.list); |
gobj = &kos_bo.gem_base; |
rbo = gem_to_radeon_bo(gobj); |
if (fb_tiled) |
tiling_flags = RADEON_TILING_MACRO; |
// if (tiling_flags) { |
// ret = radeon_bo_set_tiling_flags(rbo, |
// tiling_flags | RADEON_TILING_SURFACE, |
// mode_cmd->pitches[0]); |
// if (ret) |
// dev_err(rdev->dev, "FB failed to set tiling flags\n"); |
// } |
vm_node.size = 0xC00000 >> 12; |
vm_node.start = 0; |
vm_node.mm = NULL; |
rbo->tbo.vm_node = &vm_node; |
rbo->tbo.offset = rbo->tbo.vm_node->start << PAGE_SHIFT; |
rbo->tbo.offset += (u64)rbo->rdev->mc.vram_start; |
rbo->kptr = (void*)0xFE000000; |
rbo->pin_count = 1; |
*gobj_p = gobj; |
return 0; |
} |
#if 0 |
typedef struct |
{ |
687,7 → 585,7 |
}rect_t; |
extern struct hmm bm_mm; |
struct drm_device *main_drm_device; |
struct drm_device *main_device; |
void FASTCALL GetWindowRect(rect_t *rc)__asm__("GetWindowRect"); |
697,7 → 595,7 |
{ |
u32_t addr; |
addr = (u32_t)rdisplay; |
addr = (u32_t)os_display; |
addr+= sizeof(display_t); /* shoot me */ |
return *(u32_t*)addr; |
} |
792,7 → 690,7 |
src_offset = (u8*)(src_y*bitmap->pitch + src_x*4); |
src_offset += (u32)bitmap->uaddr; |
dst_offset = (u8*)(dst_y*rdisplay->width + dst_x); |
dst_offset = (u8*)(dst_y*os_display->width + dst_x); |
dst_offset+= get_display_map(); |
u32_t tmp_h = height; |
806,7 → 704,7 |
u8* tmp_dst = dst_offset; |
src_offset+= bitmap->pitch; |
dst_offset+= rdisplay->width; |
dst_offset+= os_display->width; |
while( tmp_w--) |
{ |
866,7 → 764,7 |
RADEON_GMC_WR_MSK_DIS; |
ib->ptr[4] = ((bitmap->pitch/64) << 22) | (bitmap->gaddr >> 10); |
ib->ptr[5] = ((rdisplay->pitch/64) << 22) | (rdev->mc.vram_start >> 10); |
ib->ptr[5] = ((os_display->pitch/64) << 22) | (rdev->mc.vram_start >> 10); |
ib->ptr[6] = (0x1fff) | (0x1fff << 16); |
ib->ptr[7] = 0; |
ib->ptr[8] = (0x1fff) | (0x1fff << 16); |
/drivers/video/drm/radeon/reg_srcs/cayman |
---|
21,7 → 21,7 |
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 |
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 |
/drivers/video/drm/radeon/reg_srcs/evergreen |
---|
22,7 → 22,7 |
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 |
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 |
/drivers/video/drm/radeon/reg_srcs/r600 |
---|
18,6 → 18,7 |
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 |
/drivers/video/drm/radeon/rs400.c |
---|
109,7 → 109,6 |
uint32_t size_reg; |
uint32_t tmp; |
radeon_gart_restore(rdev); |
tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH); |
tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS; |
WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp); |
174,10 → 173,13 |
/* FIXME: according to doc we should set HIDE_MMCFG_BAR=0, |
* AGPMODE30=0 & AGP30ENHANCED=0 in NB_CNTL */ |
if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) { |
WREG32_MC(RS480_MC_MISC_CNTL, |
(RS480_GART_INDEX_REG_EN | RS690_BLOCK_GFX_D3_EN)); |
tmp = RREG32_MC(RS480_MC_MISC_CNTL); |
tmp |= RS480_GART_INDEX_REG_EN | RS690_BLOCK_GFX_D3_EN; |
WREG32_MC(RS480_MC_MISC_CNTL, tmp); |
} else { |
WREG32_MC(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN); |
tmp = RREG32_MC(RS480_MC_MISC_CNTL); |
tmp |= RS480_GART_INDEX_REG_EN; |
WREG32_MC(RS480_MC_MISC_CNTL, tmp); |
} |
/* Enable gart */ |
WREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | size_reg)); |
206,24 → 208,26 |
radeon_gart_table_ram_free(rdev); |
} |
#define RS400_PTE_UNSNOOPED (1 << 0) |
#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 flags) |
{ |
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; |
((upper_32_bits(addr) & 0xff) << 4); |
if (flags & RADEON_GART_PAGE_READ) |
addr |= RS400_PTE_READABLE; |
if (flags & RADEON_GART_PAGE_WRITE) |
addr |= RS400_PTE_WRITEABLE; |
if (!(flags & RADEON_GART_PAGE_SNOOP)) |
entry |= RS400_PTE_UNSNOOPED; |
entry = cpu_to_le32(entry); |
gtt[i] = entry; |
return 0; |
} |
int rs400_mc_wait_for_idle(struct radeon_device *rdev) |
271,19 → 275,26 |
uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg) |
{ |
unsigned long flags; |
uint32_t r; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(RS480_NB_MC_INDEX, reg & 0xff); |
r = RREG32(RS480_NB_MC_DATA); |
WREG32(RS480_NB_MC_INDEX, 0xff); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
return r; |
} |
void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(RS480_NB_MC_INDEX, ((reg) & 0xff) | RS480_NB_MC_IND_WR_EN); |
WREG32(RS480_NB_MC_DATA, (v)); |
WREG32(RS480_NB_MC_INDEX, 0xff); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
} |
#if defined(CONFIG_DEBUG_FS) |
498,6 → 509,9 |
return r; |
r300_set_reg_safe(rdev); |
/* Initialize power management */ |
radeon_pm_init(rdev); |
rdev->accel_working = true; |
r = rs400_startup(rdev); |
if (r) { |
/drivers/video/drm/radeon/rs600.c |
---|
106,13 → 106,202 |
if (!avivo_is_counter_moving(rdev, crtc)) |
break; |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK) |
} |
} |
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; |
udelay(1); |
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) |
{ |
int requested_index = rdev->pm.requested_power_state_index; |
struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; |
struct radeon_voltage *voltage = &ps->clock_info[0].voltage; |
u32 tmp, dyn_pwrmgt_sclk_length, dyn_sclk_vol_cntl; |
u32 hdp_dyn_cntl, /*mc_host_dyn_cntl,*/ dyn_backbias_cntl; |
if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { |
if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { |
tmp = RREG32(voltage->gpio.reg); |
if (voltage->active_high) |
tmp |= voltage->gpio.mask; |
else |
tmp &= ~(voltage->gpio.mask); |
WREG32(voltage->gpio.reg, tmp); |
if (voltage->delay) |
udelay(voltage->delay); |
} else { |
tmp = RREG32(voltage->gpio.reg); |
if (voltage->active_high) |
tmp &= ~voltage->gpio.mask; |
else |
tmp |= voltage->gpio.mask; |
WREG32(voltage->gpio.reg, tmp); |
if (voltage->delay) |
udelay(voltage->delay); |
} |
} else if (voltage->type == VOLTAGE_VDDC) |
radeon_atom_set_voltage(rdev, voltage->vddc_id, SET_VOLTAGE_TYPE_ASIC_VDDC); |
dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH); |
dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf); |
dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_LOLEN(0xf); |
if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) { |
if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) { |
dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(2); |
dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(2); |
} else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) { |
dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(4); |
dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(4); |
} |
} else { |
dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(1); |
dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(1); |
} |
WREG32_PLL(DYN_PWRMGT_SCLK_LENGTH, dyn_pwrmgt_sclk_length); |
dyn_sclk_vol_cntl = RREG32_PLL(DYN_SCLK_VOL_CNTL); |
if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) { |
dyn_sclk_vol_cntl |= IO_CG_VOLTAGE_DROP; |
if (voltage->delay) { |
dyn_sclk_vol_cntl |= VOLTAGE_DROP_SYNC; |
dyn_sclk_vol_cntl |= VOLTAGE_DELAY_SEL(voltage->delay); |
} else |
dyn_sclk_vol_cntl &= ~VOLTAGE_DROP_SYNC; |
} else |
dyn_sclk_vol_cntl &= ~IO_CG_VOLTAGE_DROP; |
WREG32_PLL(DYN_SCLK_VOL_CNTL, dyn_sclk_vol_cntl); |
hdp_dyn_cntl = RREG32_PLL(HDP_DYN_CNTL); |
if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN) |
hdp_dyn_cntl &= ~HDP_FORCEON; |
else |
hdp_dyn_cntl |= HDP_FORCEON; |
WREG32_PLL(HDP_DYN_CNTL, hdp_dyn_cntl); |
#if 0 |
/* mc_host_dyn seems to cause hangs from time to time */ |
mc_host_dyn_cntl = RREG32_PLL(MC_HOST_DYN_CNTL); |
if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN) |
mc_host_dyn_cntl &= ~MC_HOST_FORCEON; |
else |
mc_host_dyn_cntl |= MC_HOST_FORCEON; |
WREG32_PLL(MC_HOST_DYN_CNTL, mc_host_dyn_cntl); |
#endif |
dyn_backbias_cntl = RREG32_PLL(DYN_BACKBIAS_CNTL); |
if (ps->misc & ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN) |
dyn_backbias_cntl |= IO_CG_BACKBIAS_EN; |
else |
dyn_backbias_cntl &= ~IO_CG_BACKBIAS_EN; |
WREG32_PLL(DYN_BACKBIAS_CNTL, dyn_backbias_cntl); |
/* set pcie lanes */ |
if ((rdev->flags & RADEON_IS_PCIE) && |
!(rdev->flags & RADEON_IS_IGP) && |
rdev->asic->pm.set_pcie_lanes && |
(ps->pcie_lanes != |
rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { |
radeon_set_pcie_lanes(rdev, |
ps->pcie_lanes); |
DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes); |
} |
} |
void rs600_pm_prepare(struct radeon_device *rdev) |
{ |
struct drm_device *ddev = rdev->ddev; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
u32 tmp; |
/* disable any active CRTCs */ |
list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { |
radeon_crtc = to_radeon_crtc(crtc); |
if (radeon_crtc->enabled) { |
tmp = RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset); |
tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; |
WREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); |
} |
} |
} |
void rs600_pm_finish(struct radeon_device *rdev) |
{ |
struct drm_device *ddev = rdev->ddev; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
u32 tmp; |
/* enable any active CRTCs */ |
list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { |
radeon_crtc = to_radeon_crtc(crtc); |
if (radeon_crtc->enabled) { |
tmp = RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset); |
tmp &= ~AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; |
WREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); |
} |
} |
} |
/* hpd for digital panel detect/disconnect */ |
bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) |
{ |
327,7 → 516,6 |
r = radeon_gart_table_vram_pin(rdev); |
if (r) |
return r; |
radeon_gart_restore(rdev); |
/* Enable bus master */ |
tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; |
WREG32(RADEON_BUS_CNTL, tmp); |
398,24 → 586,22 |
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, uint32_t flags) |
{ |
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; |
addr |= R600_PTE_SYSTEM; |
if (flags & RADEON_GART_PAGE_VALID) |
addr |= R600_PTE_VALID; |
if (flags & RADEON_GART_PAGE_READ) |
addr |= R600_PTE_READABLE; |
if (flags & RADEON_GART_PAGE_WRITE) |
addr |= R600_PTE_WRITEABLE; |
if (flags & RADEON_GART_PAGE_SNOOP) |
addr |= R600_PTE_SNOOPED; |
writeq(addr, ptr + (i * 8)); |
return 0; |
} |
int rs600_irq_set(struct radeon_device *rdev) |
677,16 → 863,26 |
uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg) |
{ |
unsigned long flags; |
u32 r; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) | |
S_000070_MC_IND_CITF_ARB0(1)); |
return RREG32(R_000074_MC_IND_DATA); |
r = RREG32(R_000074_MC_IND_DATA); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
return r; |
} |
void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) | |
S_000070_MC_IND_CITF_ARB0(1) | S_000070_MC_IND_WR_EN(1)); |
WREG32(R_000074_MC_IND_DATA, v); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
} |
static void rs600_debugfs(struct radeon_device *rdev) |
774,6 → 970,11 |
return r; |
} |
r = r600_audio_init(rdev); |
if (r) { |
dev_err(rdev->dev, "failed initializing audio\n"); |
return r; |
} |
return 0; |
} |
834,6 → 1035,9 |
return r; |
rs600_set_safe_registers(rdev); |
/* Initialize power management */ |
radeon_pm_init(rdev); |
rdev->accel_working = true; |
r = rs600_startup(rdev); |
if (r) { |
/drivers/video/drm/radeon/rs600_reg_safe.h |
---|
31,14 → 31,14 |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, |
0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE009FF, |
0xFFFFFC48, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, |
0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE00BFF, |
0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, |
0x00000000, 0x0000C100, 0x00000000, 0x00000000, |
0x00000000, 0x00000100, 0x00000000, 0x00000000, |
0x00000000, 0x00000000, 0x00000000, 0x00000000, |
0x00000000, 0xFFFF0000, 0xFFFFFFFF, 0xFF80FFFF, |
0x00000000, 0x00000000, 0x00000000, 0xFF800000, |
0x00000000, 0x00000000, 0x00000000, 0x00000000, |
0x0003FC01, 0xFFFFFCF8, 0xFF800B19, 0xFFFFFFFF, |
0x0003FC0B, 0xFFFFFCFF, 0xFFBFFB99, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
/drivers/video/drm/radeon/rs690.c |
---|
162,6 → 162,16 |
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; |
249,12 → 259,15 |
static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, |
struct radeon_crtc *crtc, |
struct rs690_watermark *wm) |
struct rs690_watermark *wm, |
bool low) |
{ |
struct drm_display_mode *mode = &crtc->base.mode; |
fixed20_12 a, b, c; |
fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width; |
fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency; |
fixed20_12 sclk, core_bandwidth, max_bandwidth; |
u32 selected_sclk; |
if (!crtc->base.enabled) { |
/* FIXME: wouldn't it better to set priority mark to maximum */ |
262,6 → 275,21 |
return; |
} |
if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) && |
(rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) |
selected_sclk = radeon_dpm_get_sclk(rdev, low); |
else |
selected_sclk = rdev->pm.current_sclk; |
/* sclk in Mhz */ |
a.full = dfixed_const(100); |
sclk.full = dfixed_const(selected_sclk); |
sclk.full = dfixed_div(sclk, a); |
/* core_bandwidth = sclk(Mhz) * 16 */ |
a.full = dfixed_const(16); |
core_bandwidth.full = dfixed_div(rdev->pm.sclk, a); |
if (crtc->vsc.full > dfixed_const(2)) |
wm->num_line_pair.full = dfixed_const(2); |
else |
322,29 → 350,31 |
wm->active_time.full = dfixed_div(wm->active_time, a); |
/* Maximun bandwidth is the minimun bandwidth of all component */ |
rdev->pm.max_bandwidth = rdev->pm.core_bandwidth; |
max_bandwidth = core_bandwidth; |
if (rdev->mc.igp_sideport_enabled) { |
if (rdev->pm.max_bandwidth.full > rdev->pm.sideport_bandwidth.full && |
if (max_bandwidth.full > rdev->pm.sideport_bandwidth.full && |
rdev->pm.sideport_bandwidth.full) |
rdev->pm.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); |
max_bandwidth = rdev->pm.sideport_bandwidth; |
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 (rdev->pm.max_bandwidth.full > rdev->pm.k8_bandwidth.full && |
if (max_bandwidth.full > rdev->pm.k8_bandwidth.full && |
rdev->pm.k8_bandwidth.full) |
rdev->pm.max_bandwidth = rdev->pm.k8_bandwidth; |
if (rdev->pm.max_bandwidth.full > rdev->pm.ht_bandwidth.full && |
max_bandwidth = rdev->pm.k8_bandwidth; |
if (max_bandwidth.full > rdev->pm.ht_bandwidth.full && |
rdev->pm.ht_bandwidth.full) |
rdev->pm.max_bandwidth = rdev->pm.ht_bandwidth; |
max_bandwidth = rdev->pm.ht_bandwidth; |
read_delay_latency.full = dfixed_const(5000); |
} |
/* sclk = system clocks(ns) = 1000 / max_bandwidth / 16 */ |
a.full = dfixed_const(16); |
rdev->pm.sclk.full = dfixed_mul(rdev->pm.max_bandwidth, a); |
sclk.full = dfixed_mul(max_bandwidth, a); |
a.full = dfixed_const(1000); |
rdev->pm.sclk.full = dfixed_div(a, rdev->pm.sclk); |
sclk.full = dfixed_div(a, sclk); |
/* Determine chunk time |
* ChunkTime = the time it takes the DCP to send one chunk of data |
* to the LB which consists of pipeline delay and inter chunk gap |
351,7 → 381,7 |
* sclk = system clock(ns) |
*/ |
a.full = dfixed_const(256 * 13); |
chunk_time.full = dfixed_mul(rdev->pm.sclk, a); |
chunk_time.full = dfixed_mul(sclk, a); |
a.full = dfixed_const(10); |
chunk_time.full = dfixed_div(chunk_time, a); |
415,193 → 445,217 |
} |
} |
void rs690_bandwidth_update(struct radeon_device *rdev) |
static void rs690_compute_mode_priority(struct radeon_device *rdev, |
struct rs690_watermark *wm0, |
struct rs690_watermark *wm1, |
struct drm_display_mode *mode0, |
struct drm_display_mode *mode1, |
u32 *d1mode_priority_a_cnt, |
u32 *d2mode_priority_a_cnt) |
{ |
struct drm_display_mode *mode0 = NULL; |
struct drm_display_mode *mode1 = NULL; |
struct rs690_watermark wm0; |
struct rs690_watermark wm1; |
u32 tmp; |
u32 d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); |
u32 d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); |
fixed20_12 priority_mark02, priority_mark12, fill_rate; |
fixed20_12 a, b; |
radeon_update_display_priority(rdev); |
*d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); |
*d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); |
if (rdev->mode_info.crtcs[0]->base.enabled) |
mode0 = &rdev->mode_info.crtcs[0]->base.mode; |
if (rdev->mode_info.crtcs[1]->base.enabled) |
mode1 = &rdev->mode_info.crtcs[1]->base.mode; |
/* |
* Set display0/1 priority up in the memory controller for |
* modes if the user specifies HIGH for displaypriority |
* option. |
*/ |
if ((rdev->disp_priority == 2) && |
((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) { |
tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER); |
tmp &= C_000104_MC_DISP0R_INIT_LAT; |
tmp &= C_000104_MC_DISP1R_INIT_LAT; |
if (mode0) |
tmp |= S_000104_MC_DISP0R_INIT_LAT(1); |
if (mode1) |
tmp |= S_000104_MC_DISP1R_INIT_LAT(1); |
WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp); |
} |
rs690_line_buffer_adjust(rdev, mode0, mode1); |
if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) |
WREG32(R_006C9C_DCP_CONTROL, 0); |
if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) |
WREG32(R_006C9C_DCP_CONTROL, 2); |
rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0); |
rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1); |
tmp = (wm0.lb_request_fifo_depth - 1); |
tmp |= (wm1.lb_request_fifo_depth - 1) << 16; |
WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp); |
if (mode0 && mode1) { |
if (dfixed_trunc(wm0.dbpp) > 64) |
a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair); |
if (dfixed_trunc(wm0->dbpp) > 64) |
a.full = dfixed_mul(wm0->dbpp, wm0->num_line_pair); |
else |
a.full = wm0.num_line_pair.full; |
if (dfixed_trunc(wm1.dbpp) > 64) |
b.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair); |
a.full = wm0->num_line_pair.full; |
if (dfixed_trunc(wm1->dbpp) > 64) |
b.full = dfixed_mul(wm1->dbpp, wm1->num_line_pair); |
else |
b.full = wm1.num_line_pair.full; |
b.full = wm1->num_line_pair.full; |
a.full += b.full; |
fill_rate.full = dfixed_div(wm0.sclk, a); |
if (wm0.consumption_rate.full > fill_rate.full) { |
b.full = wm0.consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm0.active_time); |
a.full = dfixed_mul(wm0.worst_case_latency, |
wm0.consumption_rate); |
fill_rate.full = dfixed_div(wm0->sclk, a); |
if (wm0->consumption_rate.full > fill_rate.full) { |
b.full = wm0->consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm0->active_time); |
a.full = dfixed_mul(wm0->worst_case_latency, |
wm0->consumption_rate); |
a.full = a.full + b.full; |
b.full = dfixed_const(16 * 1000); |
priority_mark02.full = dfixed_div(a, b); |
} else { |
a.full = dfixed_mul(wm0.worst_case_latency, |
wm0.consumption_rate); |
a.full = dfixed_mul(wm0->worst_case_latency, |
wm0->consumption_rate); |
b.full = dfixed_const(16 * 1000); |
priority_mark02.full = dfixed_div(a, b); |
} |
if (wm1.consumption_rate.full > fill_rate.full) { |
b.full = wm1.consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm1.active_time); |
a.full = dfixed_mul(wm1.worst_case_latency, |
wm1.consumption_rate); |
if (wm1->consumption_rate.full > fill_rate.full) { |
b.full = wm1->consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm1->active_time); |
a.full = dfixed_mul(wm1->worst_case_latency, |
wm1->consumption_rate); |
a.full = a.full + b.full; |
b.full = dfixed_const(16 * 1000); |
priority_mark12.full = dfixed_div(a, b); |
} else { |
a.full = dfixed_mul(wm1.worst_case_latency, |
wm1.consumption_rate); |
a.full = dfixed_mul(wm1->worst_case_latency, |
wm1->consumption_rate); |
b.full = dfixed_const(16 * 1000); |
priority_mark12.full = dfixed_div(a, b); |
} |
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); |
d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); |
if (wm0->priority_mark.full > priority_mark02.full) |
priority_mark02.full = wm0->priority_mark.full; |
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 (wm1->priority_mark_max.full > priority_mark12.full) |
priority_mark12.full = wm1->priority_mark_max.full; |
*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); |
*d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); |
if (rdev->disp_priority == 2) { |
d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); |
d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); |
*d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); |
*d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); |
} |
} else if (mode0) { |
if (dfixed_trunc(wm0.dbpp) > 64) |
a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair); |
if (dfixed_trunc(wm0->dbpp) > 64) |
a.full = dfixed_mul(wm0->dbpp, wm0->num_line_pair); |
else |
a.full = wm0.num_line_pair.full; |
fill_rate.full = dfixed_div(wm0.sclk, a); |
if (wm0.consumption_rate.full > fill_rate.full) { |
b.full = wm0.consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm0.active_time); |
a.full = dfixed_mul(wm0.worst_case_latency, |
wm0.consumption_rate); |
a.full = wm0->num_line_pair.full; |
fill_rate.full = dfixed_div(wm0->sclk, a); |
if (wm0->consumption_rate.full > fill_rate.full) { |
b.full = wm0->consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm0->active_time); |
a.full = dfixed_mul(wm0->worst_case_latency, |
wm0->consumption_rate); |
a.full = a.full + b.full; |
b.full = dfixed_const(16 * 1000); |
priority_mark02.full = dfixed_div(a, b); |
} else { |
a.full = dfixed_mul(wm0.worst_case_latency, |
wm0.consumption_rate); |
a.full = dfixed_mul(wm0->worst_case_latency, |
wm0->consumption_rate); |
b.full = dfixed_const(16 * 1000); |
priority_mark02.full = dfixed_div(a, b); |
} |
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); |
if (wm0->priority_mark.full > priority_mark02.full) |
priority_mark02.full = wm0->priority_mark.full; |
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); |
if (rdev->disp_priority == 2) |
d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); |
*d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); |
} else if (mode1) { |
if (dfixed_trunc(wm1.dbpp) > 64) |
a.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair); |
if (dfixed_trunc(wm1->dbpp) > 64) |
a.full = dfixed_mul(wm1->dbpp, wm1->num_line_pair); |
else |
a.full = wm1.num_line_pair.full; |
fill_rate.full = dfixed_div(wm1.sclk, a); |
if (wm1.consumption_rate.full > fill_rate.full) { |
b.full = wm1.consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm1.active_time); |
a.full = dfixed_mul(wm1.worst_case_latency, |
wm1.consumption_rate); |
a.full = wm1->num_line_pair.full; |
fill_rate.full = dfixed_div(wm1->sclk, a); |
if (wm1->consumption_rate.full > fill_rate.full) { |
b.full = wm1->consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm1->active_time); |
a.full = dfixed_mul(wm1->worst_case_latency, |
wm1->consumption_rate); |
a.full = a.full + b.full; |
b.full = dfixed_const(16 * 1000); |
priority_mark12.full = dfixed_div(a, b); |
} else { |
a.full = dfixed_mul(wm1.worst_case_latency, |
wm1.consumption_rate); |
a.full = dfixed_mul(wm1->worst_case_latency, |
wm1->consumption_rate); |
b.full = dfixed_const(16 * 1000); |
priority_mark12.full = dfixed_div(a, b); |
} |
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); |
if (wm1->priority_mark.full > priority_mark12.full) |
priority_mark12.full = wm1->priority_mark.full; |
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); |
if (rdev->disp_priority == 2) |
d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); |
*d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); |
} |
} |
void rs690_bandwidth_update(struct radeon_device *rdev) |
{ |
struct drm_display_mode *mode0 = NULL; |
struct drm_display_mode *mode1 = NULL; |
struct rs690_watermark wm0_high, wm0_low; |
struct rs690_watermark wm1_high, wm1_low; |
u32 tmp; |
u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt; |
u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt; |
radeon_update_display_priority(rdev); |
if (rdev->mode_info.crtcs[0]->base.enabled) |
mode0 = &rdev->mode_info.crtcs[0]->base.mode; |
if (rdev->mode_info.crtcs[1]->base.enabled) |
mode1 = &rdev->mode_info.crtcs[1]->base.mode; |
/* |
* Set display0/1 priority up in the memory controller for |
* modes if the user specifies HIGH for displaypriority |
* option. |
*/ |
if ((rdev->disp_priority == 2) && |
((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) { |
tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER); |
tmp &= C_000104_MC_DISP0R_INIT_LAT; |
tmp &= C_000104_MC_DISP1R_INIT_LAT; |
if (mode0) |
tmp |= S_000104_MC_DISP0R_INIT_LAT(1); |
if (mode1) |
tmp |= S_000104_MC_DISP1R_INIT_LAT(1); |
WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp); |
} |
rs690_line_buffer_adjust(rdev, mode0, mode1); |
if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) |
WREG32(R_006C9C_DCP_CONTROL, 0); |
if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) |
WREG32(R_006C9C_DCP_CONTROL, 2); |
rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_high, false); |
rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_high, false); |
rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_low, true); |
rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_low, true); |
tmp = (wm0_high.lb_request_fifo_depth - 1); |
tmp |= (wm1_high.lb_request_fifo_depth - 1) << 16; |
WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp); |
rs690_compute_mode_priority(rdev, |
&wm0_high, &wm1_high, |
mode0, mode1, |
&d1mode_priority_a_cnt, &d2mode_priority_a_cnt); |
rs690_compute_mode_priority(rdev, |
&wm0_low, &wm1_low, |
mode0, mode1, |
&d1mode_priority_b_cnt, &d2mode_priority_b_cnt); |
WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); |
WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); |
WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_b_cnt); |
WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); |
WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); |
WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_b_cnt); |
} |
uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg) |
{ |
unsigned long flags; |
uint32_t r; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg)); |
r = RREG32(R_00007C_MC_DATA); |
WREG32(R_000078_MC_INDEX, ~C_000078_MC_IND_ADDR); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
return r; |
} |
void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg) | |
S_000078_MC_IND_WR_EN(1)); |
WREG32(R_00007C_MC_DATA, v); |
WREG32(R_000078_MC_INDEX, 0x7F); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
} |
static void rs690_mc_program(struct radeon_device *rdev) |
672,6 → 726,11 |
return r; |
} |
r = r600_audio_init(rdev); |
if (r) { |
dev_err(rdev->dev, "failed initializing audio\n"); |
return r; |
} |
return 0; |
} |
734,6 → 793,9 |
return r; |
rs600_set_safe_registers(rdev); |
/* Initialize power management */ |
radeon_pm_init(rdev); |
rdev->accel_working = true; |
r = rs690_startup(rdev); |
if (r) { |
/drivers/video/drm/radeon/rs780_dpm.c |
---|
0,0 → 1,1053 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "rs780d.h" |
#include "r600_dpm.h" |
#include "rs780_dpm.h" |
#include "atom.h" |
#include <linux/seq_file.h> |
static struct igp_ps *rs780_get_ps(struct radeon_ps *rps) |
{ |
struct igp_ps *ps = rps->ps_priv; |
return ps; |
} |
static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev) |
{ |
struct igp_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
static void rs780_get_pm_mode_parameters(struct radeon_device *rdev) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
struct radeon_mode_info *minfo = &rdev->mode_info; |
struct drm_crtc *crtc; |
struct radeon_crtc *radeon_crtc; |
int i; |
/* defaults */ |
pi->crtc_id = 0; |
pi->refresh_rate = 60; |
for (i = 0; i < rdev->num_crtc; i++) { |
crtc = (struct drm_crtc *)minfo->crtcs[i]; |
if (crtc && crtc->enabled) { |
radeon_crtc = to_radeon_crtc(crtc); |
pi->crtc_id = radeon_crtc->crtc_id; |
if (crtc->mode.htotal && crtc->mode.vtotal) |
pi->refresh_rate = drm_mode_vrefresh(&crtc->mode); |
break; |
} |
} |
} |
static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable); |
static int rs780_initialize_dpm_power_state(struct radeon_device *rdev, |
struct radeon_ps *boot_ps) |
{ |
struct atom_clock_dividers dividers; |
struct igp_ps *default_state = rs780_get_ps(boot_ps); |
int i, ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
default_state->sclk_low, false, ÷rs); |
if (ret) |
return ret; |
r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div); |
r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div); |
r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div); |
if (dividers.enable_post_div) |
r600_engine_clock_entry_enable_post_divider(rdev, 0, true); |
else |
r600_engine_clock_entry_enable_post_divider(rdev, 0, false); |
r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT); |
r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false); |
r600_engine_clock_entry_enable(rdev, 0, true); |
for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++) |
r600_engine_clock_entry_enable(rdev, i, false); |
r600_enable_mclk_control(rdev, false); |
r600_voltage_control_enable_pins(rdev, 0); |
return 0; |
} |
static int rs780_initialize_dpm_parameters(struct radeon_device *rdev, |
struct radeon_ps *boot_ps) |
{ |
int ret = 0; |
int i; |
r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT); |
r600_set_at(rdev, 0, 0, 0, 0); |
r600_set_git(rdev, R600_GICST_DFLT); |
for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) |
r600_set_tc(rdev, i, 0, 0); |
r600_select_td(rdev, R600_TD_DFLT); |
r600_set_vrc(rdev, 0); |
r600_set_tpu(rdev, R600_TPU_DFLT); |
r600_set_tpc(rdev, R600_TPC_DFLT); |
r600_set_sstu(rdev, R600_SSTU_DFLT); |
r600_set_sst(rdev, R600_SST_DFLT); |
r600_set_fctu(rdev, R600_FCTU_DFLT); |
r600_set_fct(rdev, R600_FCT_DFLT); |
r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT); |
r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT); |
r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT); |
r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT); |
r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT); |
r600_vid_rt_set_vru(rdev, R600_VRU_DFLT); |
r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT); |
r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT); |
ret = rs780_initialize_dpm_power_state(rdev, boot_ps); |
r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0); |
r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 0); |
r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH, 0); |
r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); |
r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0); |
r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH, 0); |
r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); |
r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0); |
r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH, 0); |
r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, R600_DISPLAY_WATERMARK_HIGH); |
r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH); |
r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH, R600_DISPLAY_WATERMARK_HIGH); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); |
r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW); |
r600_set_vrc(rdev, RS780_CGFTV_DFLT); |
return ret; |
} |
static void rs780_start_dpm(struct radeon_device *rdev) |
{ |
r600_enable_sclk_control(rdev, false); |
r600_enable_mclk_control(rdev, false); |
r600_dynamicpm_enable(rdev, true); |
radeon_wait_for_vblank(rdev, 0); |
radeon_wait_for_vblank(rdev, 1); |
r600_enable_spll_bypass(rdev, true); |
r600_wait_for_spll_change(rdev); |
r600_enable_spll_bypass(rdev, false); |
r600_wait_for_spll_change(rdev); |
r600_enable_spll_bypass(rdev, true); |
r600_wait_for_spll_change(rdev); |
r600_enable_spll_bypass(rdev, false); |
r600_wait_for_spll_change(rdev); |
r600_enable_sclk_control(rdev, true); |
} |
static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev) |
{ |
WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN, |
~RANGE_SLOW_CLK_FEEDBACK_DIV_EN); |
WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, |
RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT), |
~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK); |
} |
static void rs780_preset_starting_fbdiv(struct radeon_device *rdev) |
{ |
u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT; |
WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv), |
~STARTING_FEEDBACK_DIV_MASK); |
WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv), |
~FORCED_FEEDBACK_DIV_MASK); |
WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV); |
} |
static void rs780_voltage_scaling_init(struct radeon_device *rdev) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
struct drm_device *dev = rdev->ddev; |
u32 fv_throt_pwm_fb_div_range[3]; |
u32 fv_throt_pwm_range[4]; |
if (dev->pdev->device == 0x9614) { |
fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT; |
fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT; |
fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT; |
} else if ((dev->pdev->device == 0x9714) || |
(dev->pdev->device == 0x9715)) { |
fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT; |
fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT; |
fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT; |
} else { |
fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT; |
fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT; |
fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT; |
} |
if (pi->pwm_voltage_control) { |
fv_throt_pwm_range[0] = pi->min_voltage; |
fv_throt_pwm_range[1] = pi->min_voltage; |
fv_throt_pwm_range[2] = pi->max_voltage; |
fv_throt_pwm_range[3] = pi->max_voltage; |
} else { |
fv_throt_pwm_range[0] = pi->invert_pwm_required ? |
RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT; |
fv_throt_pwm_range[1] = pi->invert_pwm_required ? |
RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT; |
fv_throt_pwm_range[2] = pi->invert_pwm_required ? |
RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT; |
fv_throt_pwm_range[3] = pi->invert_pwm_required ? |
RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT; |
} |
WREG32_P(FVTHROT_PWM_CTRL_REG0, |
STARTING_PWM_HIGHTIME(pi->max_voltage), |
~STARTING_PWM_HIGHTIME_MASK); |
WREG32_P(FVTHROT_PWM_CTRL_REG0, |
NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period), |
~NUMBER_OF_CYCLES_IN_PERIOD_MASK); |
WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME, |
~FORCE_STARTING_PWM_HIGHTIME); |
if (pi->invert_pwm_required) |
WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM); |
else |
WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM); |
rs780_voltage_scaling_enable(rdev, true); |
WREG32(FVTHROT_PWM_CTRL_REG1, |
(MIN_PWM_HIGHTIME(pi->min_voltage) | |
MAX_PWM_HIGHTIME(pi->max_voltage))); |
WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT); |
WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT); |
WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT); |
WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT); |
WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, |
RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]), |
~RANGE0_PWM_FEEDBACK_DIV_MASK); |
WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2, |
(RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) | |
RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2]))); |
WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3, |
(RANGE0_PWM(fv_throt_pwm_range[1]) | |
RANGE1_PWM(fv_throt_pwm_range[2]))); |
WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4, |
(RANGE2_PWM(fv_throt_pwm_range[1]) | |
RANGE3_PWM(fv_throt_pwm_range[2]))); |
} |
static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE, |
~(ENABLE_FV_THROT | ENABLE_FV_UPDATE)); |
else |
WREG32_P(FVTHROT_CNTRL_REG, 0, |
~(ENABLE_FV_THROT | ENABLE_FV_UPDATE)); |
} |
static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO); |
else |
WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO); |
} |
static void rs780_set_engine_clock_wfc(struct radeon_device *rdev) |
{ |
WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT); |
WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT); |
WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT); |
WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT); |
WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT); |
WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT); |
WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT); |
WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT); |
WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT); |
WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT); |
} |
static void rs780_set_engine_clock_sc(struct radeon_device *rdev) |
{ |
WREG32_P(FVTHROT_FBDIV_REG2, |
FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT), |
~FB_DIV_TIMER_VAL_MASK); |
WREG32_P(FVTHROT_CNTRL_REG, |
REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf), |
~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK)); |
} |
static void rs780_set_engine_clock_tdc(struct radeon_device *rdev) |
{ |
WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE)); |
} |
static void rs780_set_engine_clock_ssc(struct radeon_device *rdev) |
{ |
WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT); |
WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT); |
WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT); |
WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT); |
WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK); |
} |
static void rs780_program_at(struct radeon_device *rdev) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate); |
WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate); |
WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate); |
WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate); |
WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate); |
} |
static void rs780_disable_vbios_powersaving(struct radeon_device *rdev) |
{ |
WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000); |
} |
static void rs780_force_voltage(struct radeon_device *rdev, u16 voltage) |
{ |
struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps); |
if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) && |
(current_state->min_voltage == RS780_VDDC_LEVEL_HIGH)) |
return; |
WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL); |
udelay(1); |
WREG32_P(FVTHROT_PWM_CTRL_REG0, |
STARTING_PWM_HIGHTIME(voltage), |
~STARTING_PWM_HIGHTIME_MASK); |
WREG32_P(FVTHROT_PWM_CTRL_REG0, |
FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME); |
WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0, |
~RANGE_PWM_FEEDBACK_DIV_EN); |
udelay(1); |
WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL); |
} |
static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div) |
{ |
struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps); |
if (current_state->sclk_low == current_state->sclk_high) |
return; |
WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL); |
WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fb_div), |
~FORCED_FEEDBACK_DIV_MASK); |
WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fb_div), |
~STARTING_FEEDBACK_DIV_MASK); |
WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV); |
udelay(100); |
WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL); |
} |
static int rs780_set_engine_clock_scaling(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers; |
struct igp_ps *new_state = rs780_get_ps(new_ps); |
struct igp_ps *old_state = rs780_get_ps(old_ps); |
int ret; |
if ((new_state->sclk_high == old_state->sclk_high) && |
(new_state->sclk_low == old_state->sclk_low)) |
return 0; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
new_state->sclk_low, false, &min_dividers); |
if (ret) |
return ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
new_state->sclk_high, false, &max_dividers); |
if (ret) |
return ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
old_state->sclk_high, false, ¤t_max_dividers); |
if (ret) |
return ret; |
if ((min_dividers.ref_div != max_dividers.ref_div) || |
(min_dividers.post_div != max_dividers.post_div) || |
(max_dividers.ref_div != current_max_dividers.ref_div) || |
(max_dividers.post_div != current_max_dividers.post_div)) |
return -EINVAL; |
rs780_force_fbdiv(rdev, max_dividers.fb_div); |
if (max_dividers.fb_div > min_dividers.fb_div) { |
WREG32_P(FVTHROT_FBDIV_REG0, |
MIN_FEEDBACK_DIV(min_dividers.fb_div) | |
MAX_FEEDBACK_DIV(max_dividers.fb_div), |
~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK)); |
WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV); |
} |
return 0; |
} |
static void rs780_set_engine_clock_spc(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct igp_ps *new_state = rs780_get_ps(new_ps); |
struct igp_ps *old_state = rs780_get_ps(old_ps); |
struct igp_power_info *pi = rs780_get_pi(rdev); |
if ((new_state->sclk_high == old_state->sclk_high) && |
(new_state->sclk_low == old_state->sclk_low)) |
return; |
if (pi->crtc_id == 0) |
WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL); |
else |
WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL); |
} |
static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct igp_ps *new_state = rs780_get_ps(new_ps); |
struct igp_ps *old_state = rs780_get_ps(old_ps); |
if ((new_state->sclk_high == old_state->sclk_high) && |
(new_state->sclk_low == old_state->sclk_low)) |
return; |
if (new_state->sclk_high == new_state->sclk_low) |
return; |
rs780_clk_scaling_enable(rdev, true); |
} |
static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev, |
enum rs780_vddc_level vddc) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
if (vddc == RS780_VDDC_LEVEL_HIGH) |
return pi->max_voltage; |
else if (vddc == RS780_VDDC_LEVEL_LOW) |
return pi->min_voltage; |
else |
return pi->max_voltage; |
} |
static void rs780_enable_voltage_scaling(struct radeon_device *rdev, |
struct radeon_ps *new_ps) |
{ |
struct igp_ps *new_state = rs780_get_ps(new_ps); |
struct igp_power_info *pi = rs780_get_pi(rdev); |
enum rs780_vddc_level vddc_high, vddc_low; |
udelay(100); |
if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) && |
(new_state->min_voltage == RS780_VDDC_LEVEL_HIGH)) |
return; |
vddc_high = rs780_get_voltage_for_vddc_level(rdev, |
new_state->max_voltage); |
vddc_low = rs780_get_voltage_for_vddc_level(rdev, |
new_state->min_voltage); |
WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL); |
udelay(1); |
if (vddc_high > vddc_low) { |
WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, |
RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN); |
WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME); |
} else if (vddc_high == vddc_low) { |
if (pi->max_voltage != vddc_high) { |
WREG32_P(FVTHROT_PWM_CTRL_REG0, |
STARTING_PWM_HIGHTIME(vddc_high), |
~STARTING_PWM_HIGHTIME_MASK); |
WREG32_P(FVTHROT_PWM_CTRL_REG0, |
FORCE_STARTING_PWM_HIGHTIME, |
~FORCE_STARTING_PWM_HIGHTIME); |
} |
} |
WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL); |
} |
static void rs780_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct igp_ps *new_state = rs780_get_ps(new_ps); |
struct igp_ps *current_state = rs780_get_ps(old_ps); |
if ((new_ps->vclk == old_ps->vclk) && |
(new_ps->dclk == old_ps->dclk)) |
return; |
if (new_state->sclk_high >= current_state->sclk_high) |
return; |
radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); |
} |
static void rs780_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct igp_ps *new_state = rs780_get_ps(new_ps); |
struct igp_ps *current_state = rs780_get_ps(old_ps); |
if ((new_ps->vclk == old_ps->vclk) && |
(new_ps->dclk == old_ps->dclk)) |
return; |
if (new_state->sclk_high < current_state->sclk_high) |
return; |
radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); |
} |
int rs780_dpm_enable(struct radeon_device *rdev) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
int ret; |
rs780_get_pm_mode_parameters(rdev); |
rs780_disable_vbios_powersaving(rdev); |
if (r600_dynamicpm_enabled(rdev)) |
return -EINVAL; |
ret = rs780_initialize_dpm_parameters(rdev, boot_ps); |
if (ret) |
return ret; |
rs780_start_dpm(rdev); |
rs780_preset_ranges_slow_clk_fbdiv_en(rdev); |
rs780_preset_starting_fbdiv(rdev); |
if (pi->voltage_control) |
rs780_voltage_scaling_init(rdev); |
rs780_clk_scaling_enable(rdev, true); |
rs780_set_engine_clock_sc(rdev); |
rs780_set_engine_clock_wfc(rdev); |
rs780_program_at(rdev); |
rs780_set_engine_clock_tdc(rdev); |
rs780_set_engine_clock_ssc(rdev); |
if (pi->gfx_clock_gating) |
r600_gfx_clockgating_enable(rdev, true); |
return 0; |
} |
void rs780_dpm_disable(struct radeon_device *rdev) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
r600_dynamicpm_enable(rdev, false); |
rs780_clk_scaling_enable(rdev, false); |
rs780_voltage_scaling_enable(rdev, false); |
if (pi->gfx_clock_gating) |
r600_gfx_clockgating_enable(rdev, false); |
if (rdev->irq.installed && |
(rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) { |
rdev->irq.dpm_thermal = false; |
radeon_irq_set(rdev); |
} |
} |
int rs780_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; |
struct radeon_ps *old_ps = rdev->pm.dpm.current_ps; |
int ret; |
rs780_get_pm_mode_parameters(rdev); |
rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
if (pi->voltage_control) { |
rs780_force_voltage(rdev, pi->max_voltage); |
mdelay(5); |
} |
ret = rs780_set_engine_clock_scaling(rdev, new_ps, old_ps); |
if (ret) |
return ret; |
rs780_set_engine_clock_spc(rdev, new_ps, old_ps); |
rs780_activate_engine_clk_scaling(rdev, new_ps, old_ps); |
if (pi->voltage_control) |
rs780_enable_voltage_scaling(rdev, new_ps); |
rs780_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
return 0; |
} |
void rs780_dpm_setup_asic(struct radeon_device *rdev) |
{ |
} |
void rs780_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
rs780_get_pm_mode_parameters(rdev); |
rs780_program_at(rdev); |
} |
union igp_info { |
struct _ATOM_INTEGRATED_SYSTEM_INFO info; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; |
}; |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, |
u8 table_rev) |
{ |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { |
rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); |
rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (r600_is_uvd_state(rps->class, rps->class2)) { |
if ((rps->vclk == 0) || (rps->dclk == 0)) { |
rps->vclk = RS780_DEFAULT_VCLK_FREQ; |
rps->dclk = RS780_DEFAULT_DCLK_FREQ; |
} |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) |
rdev->pm.dpm.boot_ps = rps; |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void rs780_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
union pplib_clock_info *clock_info) |
{ |
struct igp_ps *ps = rs780_get_ps(rps); |
u32 sclk; |
sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); |
sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; |
ps->sclk_low = sclk; |
sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow); |
sclk |= clock_info->rs780.ucHighEngineClockHigh << 16; |
ps->sclk_high = sclk; |
switch (le16_to_cpu(clock_info->rs780.usVDDC)) { |
case ATOM_PPLIB_RS780_VOLTAGE_NONE: |
default: |
ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN; |
ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN; |
break; |
case ATOM_PPLIB_RS780_VOLTAGE_LOW: |
ps->min_voltage = RS780_VDDC_LEVEL_LOW; |
ps->max_voltage = RS780_VDDC_LEVEL_LOW; |
break; |
case ATOM_PPLIB_RS780_VOLTAGE_HIGH: |
ps->min_voltage = RS780_VDDC_LEVEL_HIGH; |
ps->max_voltage = RS780_VDDC_LEVEL_HIGH; |
break; |
case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE: |
ps->min_voltage = RS780_VDDC_LEVEL_LOW; |
ps->max_voltage = RS780_VDDC_LEVEL_HIGH; |
break; |
} |
ps->flags = le32_to_cpu(clock_info->rs780.ulFlags); |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
ps->sclk_low = rdev->clock.default_sclk; |
ps->sclk_high = rdev->clock.default_sclk; |
ps->min_voltage = RS780_VDDC_LEVEL_HIGH; |
ps->max_voltage = RS780_VDDC_LEVEL_HIGH; |
} |
} |
static int rs780_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i; |
union pplib_clock_info *clock_info; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
struct igp_ps *ps; |
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.ps = kzalloc(sizeof(struct radeon_ps) * |
power_info->pplib.ucNumStates, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
for (i = 0; i < power_info->pplib.ucNumStates; i++) { |
power_state = (union pplib_power_state *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset) + |
i * power_info->pplib.ucStateEntrySize); |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + |
(power_state->v1.ucNonClockStateIndex * |
power_info->pplib.ucNonClockSize)); |
if (power_info->pplib.ucStateEntrySize - 1) { |
clock_info = (union pplib_clock_info *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + |
(power_state->v1.ucClockStateIndices[0] * |
power_info->pplib.ucClockInfoSize)); |
ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info, |
power_info->pplib.ucNonClockSize); |
rs780_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], |
clock_info); |
} |
} |
rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates; |
return 0; |
} |
int rs780_dpm_init(struct radeon_device *rdev) |
{ |
struct igp_power_info *pi; |
int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); |
union igp_info *info; |
u16 data_offset; |
u8 frev, crev; |
int ret; |
pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL); |
if (pi == NULL) |
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; |
pi->voltage_control = false; |
pi->gfx_clock_gating = true; |
if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL, |
&frev, &crev, &data_offset)) { |
info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset); |
/* Get various system informations from bios */ |
switch (crev) { |
case 1: |
pi->num_of_cycles_in_period = |
info->info.ucNumberOfCyclesInPeriod; |
pi->num_of_cycles_in_period |= |
info->info.ucNumberOfCyclesInPeriodHi << 8; |
pi->invert_pwm_required = |
(pi->num_of_cycles_in_period & 0x8000) ? true : false; |
pi->boot_voltage = info->info.ucStartingPWM_HighTime; |
pi->max_voltage = info->info.ucMaxNBVoltage; |
pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8; |
pi->min_voltage = info->info.ucMinNBVoltage; |
pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8; |
pi->inter_voltage_low = |
le16_to_cpu(info->info.usInterNBVoltageLow); |
pi->inter_voltage_high = |
le16_to_cpu(info->info.usInterNBVoltageHigh); |
pi->voltage_control = true; |
pi->bootup_uma_clk = info->info.usK8MemoryClock * 100; |
break; |
case 2: |
pi->num_of_cycles_in_period = |
le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod); |
pi->invert_pwm_required = |
(pi->num_of_cycles_in_period & 0x8000) ? true : false; |
pi->boot_voltage = |
le16_to_cpu(info->info_2.usBootUpNBVoltage); |
pi->max_voltage = |
le16_to_cpu(info->info_2.usMaxNBVoltage); |
pi->min_voltage = |
le16_to_cpu(info->info_2.usMinNBVoltage); |
pi->system_config = |
le32_to_cpu(info->info_2.ulSystemConfig); |
pi->pwm_voltage_control = |
(pi->system_config & 0x4) ? true : false; |
pi->voltage_control = true; |
pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock); |
break; |
default: |
DRM_ERROR("No integrated system info for your GPU\n"); |
return -EINVAL; |
} |
if (pi->min_voltage > pi->max_voltage) |
pi->voltage_control = false; |
if (pi->pwm_voltage_control) { |
if ((pi->num_of_cycles_in_period == 0) || |
(pi->max_voltage == 0) || |
(pi->min_voltage == 0)) |
pi->voltage_control = false; |
} else { |
if ((pi->num_of_cycles_in_period == 0) || |
(pi->max_voltage == 0)) |
pi->voltage_control = false; |
} |
return 0; |
} |
radeon_dpm_fini(rdev); |
return -EINVAL; |
} |
void rs780_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct igp_ps *ps = rs780_get_ps(rps); |
r600_dpm_print_class_info(rps->class, rps->class2); |
r600_dpm_print_cap_info(rps->caps); |
printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
printk("\t\tpower level 0 sclk: %u vddc_index: %d\n", |
ps->sclk_low, ps->min_voltage); |
printk("\t\tpower level 1 sclk: %u vddc_index: %d\n", |
ps->sclk_high, ps->max_voltage); |
r600_dpm_print_ps_status(rdev, rps); |
} |
void rs780_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
} |
u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low) |
{ |
struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps); |
if (low) |
return requested_state->sclk_low; |
else |
return requested_state->sclk_high; |
} |
u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
return pi->bootup_uma_clk; |
} |
void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m) |
{ |
struct radeon_ps *rps = rdev->pm.dpm.current_ps; |
struct igp_ps *ps = rs780_get_ps(rps); |
u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK; |
u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL); |
u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1; |
u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 + |
((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1; |
u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) / |
(post_div * ref_div); |
seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
/* guess based on the current sclk */ |
if (sclk < (ps->sclk_low + 500)) |
seq_printf(m, "power level 0 sclk: %u vddc_index: %d\n", |
ps->sclk_low, ps->min_voltage); |
else |
seq_printf(m, "power level 1 sclk: %u vddc_index: %d\n", |
ps->sclk_high, ps->max_voltage); |
} |
int rs780_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
struct igp_power_info *pi = rs780_get_pi(rdev); |
struct radeon_ps *rps = rdev->pm.dpm.current_ps; |
struct igp_ps *ps = rs780_get_ps(rps); |
struct atom_clock_dividers dividers; |
int ret; |
rs780_clk_scaling_enable(rdev, false); |
rs780_voltage_scaling_enable(rdev, false); |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
if (pi->voltage_control) |
rs780_force_voltage(rdev, pi->max_voltage); |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
ps->sclk_high, false, ÷rs); |
if (ret) |
return ret; |
rs780_force_fbdiv(rdev, dividers.fb_div); |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
ps->sclk_low, false, ÷rs); |
if (ret) |
return ret; |
rs780_force_fbdiv(rdev, dividers.fb_div); |
if (pi->voltage_control) |
rs780_force_voltage(rdev, pi->min_voltage); |
} else { |
if (pi->voltage_control) |
rs780_force_voltage(rdev, pi->max_voltage); |
if (ps->sclk_high != ps->sclk_low) { |
WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV); |
rs780_clk_scaling_enable(rdev, true); |
} |
if (pi->voltage_control) { |
rs780_voltage_scaling_enable(rdev, true); |
rs780_enable_voltage_scaling(rdev, rps); |
} |
} |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
/drivers/video/drm/radeon/rs780_dpm.h |
---|
0,0 → 1,109 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __RS780_DPM_H__ |
#define __RS780_DPM_H__ |
enum rs780_vddc_level { |
RS780_VDDC_LEVEL_UNKNOWN = 0, |
RS780_VDDC_LEVEL_LOW = 1, |
RS780_VDDC_LEVEL_HIGH = 2, |
}; |
struct igp_power_info { |
/* flags */ |
bool invert_pwm_required; |
bool pwm_voltage_control; |
bool voltage_control; |
bool gfx_clock_gating; |
/* stored values */ |
u32 system_config; |
u32 bootup_uma_clk; |
u16 max_voltage; |
u16 min_voltage; |
u16 boot_voltage; |
u16 inter_voltage_low; |
u16 inter_voltage_high; |
u16 num_of_cycles_in_period; |
/* variable */ |
int crtc_id; |
int refresh_rate; |
}; |
struct igp_ps { |
enum rs780_vddc_level min_voltage; |
enum rs780_vddc_level max_voltage; |
u32 sclk_low; |
u32 sclk_high; |
u32 flags; |
}; |
#define RS780_CGFTV_DFLT 0x0303000f |
#define RS780_FBDIVTIMERVAL_DFLT 0x2710 |
#define RS780_FVTHROTUTC0_DFLT 0x04010040 |
#define RS780_FVTHROTUTC1_DFLT 0x04010040 |
#define RS780_FVTHROTUTC2_DFLT 0x04010040 |
#define RS780_FVTHROTUTC3_DFLT 0x04010040 |
#define RS780_FVTHROTUTC4_DFLT 0x04010040 |
#define RS780_FVTHROTDTC0_DFLT 0x04010040 |
#define RS780_FVTHROTDTC1_DFLT 0x04010040 |
#define RS780_FVTHROTDTC2_DFLT 0x04010040 |
#define RS780_FVTHROTDTC3_DFLT 0x04010040 |
#define RS780_FVTHROTDTC4_DFLT 0x04010040 |
#define RS780_FVTHROTFBUSREG0_DFLT 0x00001001 |
#define RS780_FVTHROTFBUSREG1_DFLT 0x00002002 |
#define RS780_FVTHROTFBDSREG0_DFLT 0x00004001 |
#define RS780_FVTHROTFBDSREG1_DFLT 0x00020010 |
#define RS780_FVTHROTPWMUSREG0_DFLT 0x00002001 |
#define RS780_FVTHROTPWMUSREG1_DFLT 0x00004003 |
#define RS780_FVTHROTPWMDSREG0_DFLT 0x00002001 |
#define RS780_FVTHROTPWMDSREG1_DFLT 0x00004003 |
#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT 0x37 |
#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT 0x4b |
#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT 0x8b |
#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT 0x8b |
#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT 0x8c |
#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT 0xb5 |
#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT 0x8d |
#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT 0x8e |
#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT 0xBa |
#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT 0x1a |
#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT 0x1a |
#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT 0x0 |
#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT 0x0 |
#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110 |
#define RS780_CGCLKGATING_DFLT 0x0000E204 |
#define RS780_DEFAULT_VCLK_FREQ 53300 /* 10 khz */ |
#define RS780_DEFAULT_DCLK_FREQ 40000 /* 10 khz */ |
#endif |
/drivers/video/drm/radeon/rs780d.h |
---|
0,0 → 1,171 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __RS780D_H__ |
#define __RS780D_H__ |
#define CG_SPLL_FUNC_CNTL 0x600 |
# define SPLL_RESET (1 << 0) |
# define SPLL_SLEEP (1 << 1) |
# define SPLL_REF_DIV(x) ((x) << 2) |
# define SPLL_REF_DIV_MASK (7 << 2) |
# define SPLL_REF_DIV_SHIFT 2 |
# define SPLL_FB_DIV(x) ((x) << 5) |
# define SPLL_FB_DIV_MASK (0xff << 2) |
# define SPLL_FB_DIV_SHIFT 2 |
# define SPLL_PULSEEN (1 << 13) |
# define SPLL_PULSENUM(x) ((x) << 14) |
# define SPLL_PULSENUM_MASK (3 << 14) |
# define SPLL_SW_HILEN(x) ((x) << 16) |
# define SPLL_SW_HILEN_MASK (0xf << 16) |
# define SPLL_SW_HILEN_SHIFT 16 |
# define SPLL_SW_LOLEN(x) ((x) << 20) |
# define SPLL_SW_LOLEN_MASK (0xf << 20) |
# define SPLL_SW_LOLEN_SHIFT 20 |
# define SPLL_DIVEN (1 << 24) |
# define SPLL_BYPASS_EN (1 << 25) |
# define SPLL_CHG_STATUS (1 << 29) |
# define SPLL_CTLREQ (1 << 30) |
# define SPLL_CTLACK (1 << 31) |
/* RS780/RS880 PM */ |
#define FVTHROT_CNTRL_REG 0x3000 |
#define DONT_WAIT_FOR_FBDIV_WRAP (1 << 0) |
#define MINIMUM_CIP(x) ((x) << 1) |
#define MINIMUM_CIP_SHIFT 1 |
#define MINIMUM_CIP_MASK 0x1fffffe |
#define REFRESH_RATE_DIVISOR(x) ((x) << 25) |
#define REFRESH_RATE_DIVISOR_SHIFT 25 |
#define REFRESH_RATE_DIVISOR_MASK (0x3 << 25) |
#define ENABLE_FV_THROT (1 << 27) |
#define ENABLE_FV_UPDATE (1 << 28) |
#define TREND_SEL_MODE (1 << 29) |
#define FORCE_TREND_SEL (1 << 30) |
#define ENABLE_FV_THROT_IO (1 << 31) |
#define FVTHROT_TARGET_REG 0x3004 |
#define TARGET_IDLE_COUNT(x) ((x) << 0) |
#define TARGET_IDLE_COUNT_MASK 0xffffff |
#define TARGET_IDLE_COUNT_SHIFT 0 |
#define FVTHROT_CB1 0x3008 |
#define FVTHROT_CB2 0x300c |
#define FVTHROT_CB3 0x3010 |
#define FVTHROT_CB4 0x3014 |
#define FVTHROT_UTC0 0x3018 |
#define FVTHROT_UTC1 0x301c |
#define FVTHROT_UTC2 0x3020 |
#define FVTHROT_UTC3 0x3024 |
#define FVTHROT_UTC4 0x3028 |
#define FVTHROT_DTC0 0x302c |
#define FVTHROT_DTC1 0x3030 |
#define FVTHROT_DTC2 0x3034 |
#define FVTHROT_DTC3 0x3038 |
#define FVTHROT_DTC4 0x303c |
#define FVTHROT_FBDIV_REG0 0x3040 |
#define MIN_FEEDBACK_DIV(x) ((x) << 0) |
#define MIN_FEEDBACK_DIV_MASK 0xfff |
#define MIN_FEEDBACK_DIV_SHIFT 0 |
#define MAX_FEEDBACK_DIV(x) ((x) << 12) |
#define MAX_FEEDBACK_DIV_MASK (0xfff << 12) |
#define MAX_FEEDBACK_DIV_SHIFT 12 |
#define FVTHROT_FBDIV_REG1 0x3044 |
#define MAX_FEEDBACK_STEP(x) ((x) << 0) |
#define MAX_FEEDBACK_STEP_MASK 0xfff |
#define MAX_FEEDBACK_STEP_SHIFT 0 |
#define STARTING_FEEDBACK_DIV(x) ((x) << 12) |
#define STARTING_FEEDBACK_DIV_MASK (0xfff << 12) |
#define STARTING_FEEDBACK_DIV_SHIFT 12 |
#define FORCE_FEEDBACK_DIV (1 << 24) |
#define FVTHROT_FBDIV_REG2 0x3048 |
#define FORCED_FEEDBACK_DIV(x) ((x) << 0) |
#define FORCED_FEEDBACK_DIV_MASK 0xfff |
#define FORCED_FEEDBACK_DIV_SHIFT 0 |
#define FB_DIV_TIMER_VAL(x) ((x) << 12) |
#define FB_DIV_TIMER_VAL_MASK (0xffff << 12) |
#define FB_DIV_TIMER_VAL_SHIFT 12 |
#define FVTHROT_FB_US_REG0 0x304c |
#define FVTHROT_FB_US_REG1 0x3050 |
#define FVTHROT_FB_DS_REG0 0x3054 |
#define FVTHROT_FB_DS_REG1 0x3058 |
#define FVTHROT_PWM_CTRL_REG0 0x305c |
#define STARTING_PWM_HIGHTIME(x) ((x) << 0) |
#define STARTING_PWM_HIGHTIME_MASK 0xfff |
#define STARTING_PWM_HIGHTIME_SHIFT 0 |
#define NUMBER_OF_CYCLES_IN_PERIOD(x) ((x) << 12) |
#define NUMBER_OF_CYCLES_IN_PERIOD_MASK (0xfff << 12) |
#define NUMBER_OF_CYCLES_IN_PERIOD_SHIFT 12 |
#define FORCE_STARTING_PWM_HIGHTIME (1 << 24) |
#define INVERT_PWM_WAVEFORM (1 << 25) |
#define FVTHROT_PWM_CTRL_REG1 0x3060 |
#define MIN_PWM_HIGHTIME(x) ((x) << 0) |
#define MIN_PWM_HIGHTIME_MASK 0xfff |
#define MIN_PWM_HIGHTIME_SHIFT 0 |
#define MAX_PWM_HIGHTIME(x) ((x) << 12) |
#define MAX_PWM_HIGHTIME_MASK (0xfff << 12) |
#define MAX_PWM_HIGHTIME_SHIFT 12 |
#define FVTHROT_PWM_US_REG0 0x3064 |
#define FVTHROT_PWM_US_REG1 0x3068 |
#define FVTHROT_PWM_DS_REG0 0x306c |
#define FVTHROT_PWM_DS_REG1 0x3070 |
#define FVTHROT_STATUS_REG0 0x3074 |
#define CURRENT_FEEDBACK_DIV_MASK 0xfff |
#define CURRENT_FEEDBACK_DIV_SHIFT 0 |
#define FVTHROT_STATUS_REG1 0x3078 |
#define FVTHROT_STATUS_REG2 0x307c |
#define CG_INTGFX_MISC 0x3080 |
#define FVTHROT_VBLANK_SEL (1 << 9) |
#define FVTHROT_PWM_FEEDBACK_DIV_REG1 0x308c |
#define RANGE0_PWM_FEEDBACK_DIV(x) ((x) << 0) |
#define RANGE0_PWM_FEEDBACK_DIV_MASK 0xfff |
#define RANGE0_PWM_FEEDBACK_DIV_SHIFT 0 |
#define RANGE_PWM_FEEDBACK_DIV_EN (1 << 12) |
#define FVTHROT_PWM_FEEDBACK_DIV_REG2 0x3090 |
#define RANGE1_PWM_FEEDBACK_DIV(x) ((x) << 0) |
#define RANGE1_PWM_FEEDBACK_DIV_MASK 0xfff |
#define RANGE1_PWM_FEEDBACK_DIV_SHIFT 0 |
#define RANGE2_PWM_FEEDBACK_DIV(x) ((x) << 12) |
#define RANGE2_PWM_FEEDBACK_DIV_MASK (0xfff << 12) |
#define RANGE2_PWM_FEEDBACK_DIV_SHIFT 12 |
#define FVTHROT_PWM_FEEDBACK_DIV_REG3 0x3094 |
#define RANGE0_PWM(x) ((x) << 0) |
#define RANGE0_PWM_MASK 0xfff |
#define RANGE0_PWM_SHIFT 0 |
#define RANGE1_PWM(x) ((x) << 12) |
#define RANGE1_PWM_MASK (0xfff << 12) |
#define RANGE1_PWM_SHIFT 12 |
#define FVTHROT_PWM_FEEDBACK_DIV_REG4 0x3098 |
#define RANGE2_PWM(x) ((x) << 0) |
#define RANGE2_PWM_MASK 0xfff |
#define RANGE2_PWM_SHIFT 0 |
#define RANGE3_PWM(x) ((x) << 12) |
#define RANGE3_PWM_MASK (0xfff << 12) |
#define RANGE3_PWM_SHIFT 12 |
#define FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1 0x30ac |
#define RANGE0_SLOW_CLK_FEEDBACK_DIV(x) ((x) << 0) |
#define RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK 0xfff |
#define RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT 0 |
#define RANGE_SLOW_CLK_FEEDBACK_DIV_EN (1 << 12) |
#define GFX_MACRO_BYPASS_CNTL 0x30c0 |
#define SPLL_BYPASS_CNTL (1 << 0) |
#define UPLL_BYPASS_CNTL (1 << 1) |
#endif |
/drivers/video/drm/radeon/rv515.c |
---|
124,7 → 124,7 |
radeon_ring_write(ring, GEOMETRY_ROUND_NEAREST | COLOR_ROUND_NEAREST); |
radeon_ring_write(ring, PACKET0(0x20C8, 0)); |
radeon_ring_write(ring, 0); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
} |
int rv515_mc_wait_for_idle(struct radeon_device *rdev) |
209,19 → 209,27 |
uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg) |
{ |
unsigned long flags; |
uint32_t r; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(MC_IND_INDEX, 0x7f0000 | (reg & 0xffff)); |
r = RREG32(MC_IND_DATA); |
WREG32(MC_IND_INDEX, 0); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
return r; |
} |
void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) |
{ |
unsigned long flags; |
spin_lock_irqsave(&rdev->mc_idx_lock, flags); |
WREG32(MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff)); |
WREG32(MC_IND_DATA, (v)); |
WREG32(MC_IND_INDEX, 0); |
spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); |
} |
#if defined(CONFIG_DEBUG_FS) |
398,8 → 406,9 |
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]); |
622,6 → 631,9 |
return r; |
rv515_set_safe_registers(rdev); |
/* Initialize power management */ |
radeon_pm_init(rdev); |
rdev->accel_working = true; |
r = rv515_startup(rdev); |
if (r) { |
877,12 → 889,15 |
static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, |
struct radeon_crtc *crtc, |
struct rv515_watermark *wm) |
struct rv515_watermark *wm, |
bool low) |
{ |
struct drm_display_mode *mode = &crtc->base.mode; |
fixed20_12 a, b, c; |
fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width; |
fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency; |
fixed20_12 sclk; |
u32 selected_sclk; |
if (!crtc->base.enabled) { |
/* FIXME: wouldn't it better to set priority mark to maximum */ |
890,6 → 905,18 |
return; |
} |
/* rv6xx, rv7xx */ |
if ((rdev->family >= CHIP_RV610) && |
(rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) |
selected_sclk = radeon_dpm_get_sclk(rdev, low); |
else |
selected_sclk = rdev->pm.current_sclk; |
/* sclk in Mhz */ |
a.full = dfixed_const(100); |
sclk.full = dfixed_const(selected_sclk); |
sclk.full = dfixed_div(sclk, a); |
if (crtc->vsc.full > dfixed_const(2)) |
wm->num_line_pair.full = dfixed_const(2); |
else |
955,7 → 982,7 |
* sclk = system clock(Mhz) |
*/ |
a.full = dfixed_const(600 * 1000); |
chunk_time.full = dfixed_div(a, rdev->pm.sclk); |
chunk_time.full = dfixed_div(a, sclk); |
read_delay_latency.full = dfixed_const(1000); |
/* Determine the worst case latency |
1016,152 → 1043,169 |
} |
} |
void rv515_bandwidth_avivo_update(struct radeon_device *rdev) |
static void rv515_compute_mode_priority(struct radeon_device *rdev, |
struct rv515_watermark *wm0, |
struct rv515_watermark *wm1, |
struct drm_display_mode *mode0, |
struct drm_display_mode *mode1, |
u32 *d1mode_priority_a_cnt, |
u32 *d2mode_priority_a_cnt) |
{ |
struct drm_display_mode *mode0 = NULL; |
struct drm_display_mode *mode1 = NULL; |
struct rv515_watermark wm0; |
struct rv515_watermark wm1; |
u32 tmp; |
u32 d1mode_priority_a_cnt = MODE_PRIORITY_OFF; |
u32 d2mode_priority_a_cnt = MODE_PRIORITY_OFF; |
fixed20_12 priority_mark02, priority_mark12, fill_rate; |
fixed20_12 a, b; |
if (rdev->mode_info.crtcs[0]->base.enabled) |
mode0 = &rdev->mode_info.crtcs[0]->base.mode; |
if (rdev->mode_info.crtcs[1]->base.enabled) |
mode1 = &rdev->mode_info.crtcs[1]->base.mode; |
rs690_line_buffer_adjust(rdev, mode0, mode1); |
*d1mode_priority_a_cnt = MODE_PRIORITY_OFF; |
*d2mode_priority_a_cnt = MODE_PRIORITY_OFF; |
rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0); |
rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1); |
tmp = wm0.lb_request_fifo_depth; |
tmp |= wm1.lb_request_fifo_depth << 16; |
WREG32(LB_MAX_REQ_OUTSTANDING, tmp); |
if (mode0 && mode1) { |
if (dfixed_trunc(wm0.dbpp) > 64) |
a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair); |
if (dfixed_trunc(wm0->dbpp) > 64) |
a.full = dfixed_div(wm0->dbpp, wm0->num_line_pair); |
else |
a.full = wm0.num_line_pair.full; |
if (dfixed_trunc(wm1.dbpp) > 64) |
b.full = dfixed_div(wm1.dbpp, wm1.num_line_pair); |
a.full = wm0->num_line_pair.full; |
if (dfixed_trunc(wm1->dbpp) > 64) |
b.full = dfixed_div(wm1->dbpp, wm1->num_line_pair); |
else |
b.full = wm1.num_line_pair.full; |
b.full = wm1->num_line_pair.full; |
a.full += b.full; |
fill_rate.full = dfixed_div(wm0.sclk, a); |
if (wm0.consumption_rate.full > fill_rate.full) { |
b.full = wm0.consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm0.active_time); |
fill_rate.full = dfixed_div(wm0->sclk, a); |
if (wm0->consumption_rate.full > fill_rate.full) { |
b.full = wm0->consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm0->active_time); |
a.full = dfixed_const(16); |
b.full = dfixed_div(b, a); |
a.full = dfixed_mul(wm0.worst_case_latency, |
wm0.consumption_rate); |
a.full = dfixed_mul(wm0->worst_case_latency, |
wm0->consumption_rate); |
priority_mark02.full = a.full + b.full; |
} else { |
a.full = dfixed_mul(wm0.worst_case_latency, |
wm0.consumption_rate); |
a.full = dfixed_mul(wm0->worst_case_latency, |
wm0->consumption_rate); |
b.full = dfixed_const(16 * 1000); |
priority_mark02.full = dfixed_div(a, b); |
} |
if (wm1.consumption_rate.full > fill_rate.full) { |
b.full = wm1.consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm1.active_time); |
if (wm1->consumption_rate.full > fill_rate.full) { |
b.full = wm1->consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm1->active_time); |
a.full = dfixed_const(16); |
b.full = dfixed_div(b, a); |
a.full = dfixed_mul(wm1.worst_case_latency, |
wm1.consumption_rate); |
a.full = dfixed_mul(wm1->worst_case_latency, |
wm1->consumption_rate); |
priority_mark12.full = a.full + b.full; |
} else { |
a.full = dfixed_mul(wm1.worst_case_latency, |
wm1.consumption_rate); |
a.full = dfixed_mul(wm1->worst_case_latency, |
wm1->consumption_rate); |
b.full = dfixed_const(16 * 1000); |
priority_mark12.full = dfixed_div(a, b); |
} |
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); |
d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); |
if (wm0->priority_mark.full > priority_mark02.full) |
priority_mark02.full = wm0->priority_mark.full; |
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 (wm1->priority_mark_max.full > priority_mark12.full) |
priority_mark12.full = wm1->priority_mark_max.full; |
*d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); |
*d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); |
if (rdev->disp_priority == 2) { |
d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; |
d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; |
*d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; |
*d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; |
} |
} else if (mode0) { |
if (dfixed_trunc(wm0.dbpp) > 64) |
a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair); |
if (dfixed_trunc(wm0->dbpp) > 64) |
a.full = dfixed_div(wm0->dbpp, wm0->num_line_pair); |
else |
a.full = wm0.num_line_pair.full; |
fill_rate.full = dfixed_div(wm0.sclk, a); |
if (wm0.consumption_rate.full > fill_rate.full) { |
b.full = wm0.consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm0.active_time); |
a.full = wm0->num_line_pair.full; |
fill_rate.full = dfixed_div(wm0->sclk, a); |
if (wm0->consumption_rate.full > fill_rate.full) { |
b.full = wm0->consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm0->active_time); |
a.full = dfixed_const(16); |
b.full = dfixed_div(b, a); |
a.full = dfixed_mul(wm0.worst_case_latency, |
wm0.consumption_rate); |
a.full = dfixed_mul(wm0->worst_case_latency, |
wm0->consumption_rate); |
priority_mark02.full = a.full + b.full; |
} else { |
a.full = dfixed_mul(wm0.worst_case_latency, |
wm0.consumption_rate); |
a.full = dfixed_mul(wm0->worst_case_latency, |
wm0->consumption_rate); |
b.full = dfixed_const(16); |
priority_mark02.full = dfixed_div(a, b); |
} |
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); |
if (wm0->priority_mark.full > priority_mark02.full) |
priority_mark02.full = wm0->priority_mark.full; |
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); |
if (rdev->disp_priority == 2) |
d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; |
*d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; |
} else if (mode1) { |
if (dfixed_trunc(wm1.dbpp) > 64) |
a.full = dfixed_div(wm1.dbpp, wm1.num_line_pair); |
if (dfixed_trunc(wm1->dbpp) > 64) |
a.full = dfixed_div(wm1->dbpp, wm1->num_line_pair); |
else |
a.full = wm1.num_line_pair.full; |
fill_rate.full = dfixed_div(wm1.sclk, a); |
if (wm1.consumption_rate.full > fill_rate.full) { |
b.full = wm1.consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm1.active_time); |
a.full = wm1->num_line_pair.full; |
fill_rate.full = dfixed_div(wm1->sclk, a); |
if (wm1->consumption_rate.full > fill_rate.full) { |
b.full = wm1->consumption_rate.full - fill_rate.full; |
b.full = dfixed_mul(b, wm1->active_time); |
a.full = dfixed_const(16); |
b.full = dfixed_div(b, a); |
a.full = dfixed_mul(wm1.worst_case_latency, |
wm1.consumption_rate); |
a.full = dfixed_mul(wm1->worst_case_latency, |
wm1->consumption_rate); |
priority_mark12.full = a.full + b.full; |
} else { |
a.full = dfixed_mul(wm1.worst_case_latency, |
wm1.consumption_rate); |
a.full = dfixed_mul(wm1->worst_case_latency, |
wm1->consumption_rate); |
b.full = dfixed_const(16 * 1000); |
priority_mark12.full = dfixed_div(a, b); |
} |
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); |
if (wm1->priority_mark.full > priority_mark12.full) |
priority_mark12.full = wm1->priority_mark.full; |
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); |
if (rdev->disp_priority == 2) |
d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; |
*d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; |
} |
} |
void rv515_bandwidth_avivo_update(struct radeon_device *rdev) |
{ |
struct drm_display_mode *mode0 = NULL; |
struct drm_display_mode *mode1 = NULL; |
struct rv515_watermark wm0_high, wm0_low; |
struct rv515_watermark wm1_high, wm1_low; |
u32 tmp; |
u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt; |
u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt; |
if (rdev->mode_info.crtcs[0]->base.enabled) |
mode0 = &rdev->mode_info.crtcs[0]->base.mode; |
if (rdev->mode_info.crtcs[1]->base.enabled) |
mode1 = &rdev->mode_info.crtcs[1]->base.mode; |
rs690_line_buffer_adjust(rdev, mode0, mode1); |
rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_high, false); |
rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_high, false); |
rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_low, false); |
rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_low, false); |
tmp = wm0_high.lb_request_fifo_depth; |
tmp |= wm1_high.lb_request_fifo_depth << 16; |
WREG32(LB_MAX_REQ_OUTSTANDING, tmp); |
rv515_compute_mode_priority(rdev, |
&wm0_high, &wm1_high, |
mode0, mode1, |
&d1mode_priority_a_cnt, &d2mode_priority_a_cnt); |
rv515_compute_mode_priority(rdev, |
&wm0_low, &wm1_low, |
mode0, mode1, |
&d1mode_priority_b_cnt, &d2mode_priority_b_cnt); |
WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); |
WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); |
WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_b_cnt); |
WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); |
WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); |
WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_b_cnt); |
} |
void rv515_bandwidth_update(struct radeon_device *rdev) |
/drivers/video/drm/radeon/rv515_reg_safe.h |
---|
15,7 → 15,7 |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFEFCE, 0xF00EBFFF, 0x007C0000, |
0xFFFFFFFF, 0xFFFFEFC6, 0xF00EBFFF, 0x007C0000, |
0xF0000038, 0xFF000009, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
31,14 → 31,14 |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0x1FFFFC78, 0xFFFFE000, 0xFFFFFFFE, 0xFFFFFFFF, |
0x38CF8F50, 0xFFF88082, 0xFF0000FC, 0xFAE009FF, |
0x1FFFFC48, 0xFFFFE000, 0xFFFFFE1E, 0xFFFFFFFF, |
0x388F8F50, 0xFFF88082, 0xFF0000FC, 0xFAE00BFF, |
0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, |
0xFFFF8CFC, 0xFFFFC1FF, 0xFFFFFFFF, 0xFFFFFFFF, |
0x00008CFC, 0xFFFCC1FF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFE80FFFF, |
0x00000000, 0x00000000, 0x00000000, 0x00000000, |
0x0003FC01, 0x3FFFFCF8, 0xFF800B19, 0xFFDFFFFF, |
0x0003FC0B, 0x3FFFFCFF, 0xFFBFFB99, 0xFFDFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
/drivers/video/drm/radeon/rv6xx_dpm.c |
---|
0,0 → 1,2112 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "rv6xxd.h" |
#include "r600_dpm.h" |
#include "rv6xx_dpm.h" |
#include "atom.h" |
#include <linux/seq_file.h> |
static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, |
u32 unscaled_count, u32 unit); |
static struct rv6xx_ps *rv6xx_get_ps(struct radeon_ps *rps) |
{ |
struct rv6xx_ps *ps = rps->ps_priv; |
return ps; |
} |
static struct rv6xx_power_info *rv6xx_get_pi(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
static void rv6xx_force_pcie_gen1(struct radeon_device *rdev) |
{ |
u32 tmp; |
int i; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
tmp &= LC_GEN2_EN; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
tmp |= LC_INITIATE_LINK_SPEED_CHANGE; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (!(RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE)) |
break; |
udelay(1); |
} |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
tmp &= ~LC_INITIATE_LINK_SPEED_CHANGE; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
static void rv6xx_enable_pcie_gen2_support(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) { |
tmp |= LC_GEN2_EN; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
} |
static void rv6xx_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
if (enable) |
tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); |
else |
tmp |= LC_HW_VOLTAGE_IF_CONTROL(0); |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
static void rv6xx_enable_l0s(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK; |
tmp |= LC_L0S_INACTIVITY(3); |
WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); |
} |
static void rv6xx_enable_l1(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL); |
tmp &= ~LC_L1_INACTIVITY_MASK; |
tmp |= LC_L1_INACTIVITY(4); |
tmp &= ~LC_PMI_TO_L1_DIS; |
tmp &= ~LC_ASPM_TO_L1_DIS; |
WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); |
} |
static void rv6xx_enable_pll_sleep_in_l1(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK; |
tmp |= LC_L1_INACTIVITY(8); |
WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); |
/* NOTE, this is a PCIE indirect reg, not PCIE PORT */ |
tmp = RREG32_PCIE(PCIE_P_CNTL); |
tmp |= P_PLL_PWRDN_IN_L1L23; |
tmp &= ~P_PLL_BUF_PDNB; |
tmp &= ~P_PLL_PDNB; |
tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF; |
WREG32_PCIE(PCIE_P_CNTL, tmp); |
} |
static int rv6xx_convert_clock_to_stepping(struct radeon_device *rdev, |
u32 clock, struct rv6xx_sclk_stepping *step) |
{ |
int ret; |
struct atom_clock_dividers dividers; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
clock, false, ÷rs); |
if (ret) |
return ret; |
if (dividers.enable_post_div) |
step->post_divider = 2 + (dividers.post_div & 0xF) + (dividers.post_div >> 4); |
else |
step->post_divider = 1; |
step->vco_frequency = clock * step->post_divider; |
return 0; |
} |
static void rv6xx_output_stepping(struct radeon_device *rdev, |
u32 step_index, struct rv6xx_sclk_stepping *step) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
u32 ref_clk = rdev->clock.spll.reference_freq; |
u32 fb_divider; |
u32 spll_step_count = rv6xx_scale_count_given_unit(rdev, |
R600_SPLLSTEPTIME_DFLT * |
pi->spll_ref_div, |
R600_SPLLSTEPUNIT_DFLT); |
r600_engine_clock_entry_enable(rdev, step_index, true); |
r600_engine_clock_entry_enable_pulse_skipping(rdev, step_index, false); |
if (step->post_divider == 1) |
r600_engine_clock_entry_enable_post_divider(rdev, step_index, false); |
else { |
u32 lo_len = (step->post_divider - 2) / 2; |
u32 hi_len = step->post_divider - 2 - lo_len; |
r600_engine_clock_entry_enable_post_divider(rdev, step_index, true); |
r600_engine_clock_entry_set_post_divider(rdev, step_index, (hi_len << 4) | lo_len); |
} |
fb_divider = ((step->vco_frequency * pi->spll_ref_div) / ref_clk) >> |
pi->fb_div_scale; |
r600_engine_clock_entry_set_reference_divider(rdev, step_index, |
pi->spll_ref_div - 1); |
r600_engine_clock_entry_set_feedback_divider(rdev, step_index, fb_divider); |
r600_engine_clock_entry_set_step_time(rdev, step_index, spll_step_count); |
} |
static struct rv6xx_sclk_stepping rv6xx_next_vco_step(struct radeon_device *rdev, |
struct rv6xx_sclk_stepping *cur, |
bool increasing_vco, u32 step_size) |
{ |
struct rv6xx_sclk_stepping next; |
next.post_divider = cur->post_divider; |
if (increasing_vco) |
next.vco_frequency = (cur->vco_frequency * (100 + step_size)) / 100; |
else |
next.vco_frequency = (cur->vco_frequency * 100 + 99 + step_size) / (100 + step_size); |
return next; |
} |
static bool rv6xx_can_step_post_div(struct radeon_device *rdev, |
struct rv6xx_sclk_stepping *cur, |
struct rv6xx_sclk_stepping *target) |
{ |
return (cur->post_divider > target->post_divider) && |
((cur->vco_frequency * target->post_divider) <= |
(target->vco_frequency * (cur->post_divider - 1))); |
} |
static struct rv6xx_sclk_stepping rv6xx_next_post_div_step(struct radeon_device *rdev, |
struct rv6xx_sclk_stepping *cur, |
struct rv6xx_sclk_stepping *target) |
{ |
struct rv6xx_sclk_stepping next = *cur; |
while (rv6xx_can_step_post_div(rdev, &next, target)) |
next.post_divider--; |
return next; |
} |
static bool rv6xx_reached_stepping_target(struct radeon_device *rdev, |
struct rv6xx_sclk_stepping *cur, |
struct rv6xx_sclk_stepping *target, |
bool increasing_vco) |
{ |
return (increasing_vco && (cur->vco_frequency >= target->vco_frequency)) || |
(!increasing_vco && (cur->vco_frequency <= target->vco_frequency)); |
} |
static void rv6xx_generate_steps(struct radeon_device *rdev, |
u32 low, u32 high, |
u32 start_index, u8 *end_index) |
{ |
struct rv6xx_sclk_stepping cur; |
struct rv6xx_sclk_stepping target; |
bool increasing_vco; |
u32 step_index = start_index; |
rv6xx_convert_clock_to_stepping(rdev, low, &cur); |
rv6xx_convert_clock_to_stepping(rdev, high, &target); |
rv6xx_output_stepping(rdev, step_index++, &cur); |
increasing_vco = (target.vco_frequency >= cur.vco_frequency); |
if (target.post_divider > cur.post_divider) |
cur.post_divider = target.post_divider; |
while (1) { |
struct rv6xx_sclk_stepping next; |
if (rv6xx_can_step_post_div(rdev, &cur, &target)) |
next = rv6xx_next_post_div_step(rdev, &cur, &target); |
else |
next = rv6xx_next_vco_step(rdev, &cur, increasing_vco, R600_VCOSTEPPCT_DFLT); |
if (rv6xx_reached_stepping_target(rdev, &next, &target, increasing_vco)) { |
struct rv6xx_sclk_stepping tiny = |
rv6xx_next_vco_step(rdev, &target, !increasing_vco, R600_ENDINGVCOSTEPPCT_DFLT); |
tiny.post_divider = next.post_divider; |
if (!rv6xx_reached_stepping_target(rdev, &tiny, &cur, !increasing_vco)) |
rv6xx_output_stepping(rdev, step_index++, &tiny); |
if ((next.post_divider != target.post_divider) && |
(next.vco_frequency != target.vco_frequency)) { |
struct rv6xx_sclk_stepping final_vco; |
final_vco.vco_frequency = target.vco_frequency; |
final_vco.post_divider = next.post_divider; |
rv6xx_output_stepping(rdev, step_index++, &final_vco); |
} |
rv6xx_output_stepping(rdev, step_index++, &target); |
break; |
} else |
rv6xx_output_stepping(rdev, step_index++, &next); |
cur = next; |
} |
*end_index = (u8)step_index - 1; |
} |
static void rv6xx_generate_single_step(struct radeon_device *rdev, |
u32 clock, u32 index) |
{ |
struct rv6xx_sclk_stepping step; |
rv6xx_convert_clock_to_stepping(rdev, clock, &step); |
rv6xx_output_stepping(rdev, index, &step); |
} |
static void rv6xx_invalidate_intermediate_steps_range(struct radeon_device *rdev, |
u32 start_index, u32 end_index) |
{ |
u32 step_index; |
for (step_index = start_index + 1; step_index < end_index; step_index++) |
r600_engine_clock_entry_enable(rdev, step_index, false); |
} |
static void rv6xx_set_engine_spread_spectrum_clk_s(struct radeon_device *rdev, |
u32 index, u32 clk_s) |
{ |
WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), |
CLKS(clk_s), ~CLKS_MASK); |
} |
static void rv6xx_set_engine_spread_spectrum_clk_v(struct radeon_device *rdev, |
u32 index, u32 clk_v) |
{ |
WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), |
CLKV(clk_v), ~CLKV_MASK); |
} |
static void rv6xx_enable_engine_spread_spectrum(struct radeon_device *rdev, |
u32 index, bool enable) |
{ |
if (enable) |
WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), |
SSEN, ~SSEN); |
else |
WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), |
0, ~SSEN); |
} |
static void rv6xx_set_memory_spread_spectrum_clk_s(struct radeon_device *rdev, |
u32 clk_s) |
{ |
WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKS(clk_s), ~CLKS_MASK); |
} |
static void rv6xx_set_memory_spread_spectrum_clk_v(struct radeon_device *rdev, |
u32 clk_v) |
{ |
WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKV(clk_v), ~CLKV_MASK); |
} |
static void rv6xx_enable_memory_spread_spectrum(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(CG_MPLL_SPREAD_SPECTRUM, SSEN, ~SSEN); |
else |
WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN); |
} |
static void rv6xx_enable_dynamic_spread_spectrum(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); |
} |
static void rv6xx_memory_clock_entry_enable_post_divider(struct radeon_device *rdev, |
u32 index, bool enable) |
{ |
if (enable) |
WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), |
LEVEL0_MPLL_DIV_EN, ~LEVEL0_MPLL_DIV_EN); |
else |
WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 0, ~LEVEL0_MPLL_DIV_EN); |
} |
static void rv6xx_memory_clock_entry_set_post_divider(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), |
LEVEL0_MPLL_POST_DIV(divider), ~LEVEL0_MPLL_POST_DIV_MASK); |
} |
static void rv6xx_memory_clock_entry_set_feedback_divider(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), LEVEL0_MPLL_FB_DIV(divider), |
~LEVEL0_MPLL_FB_DIV_MASK); |
} |
static void rv6xx_memory_clock_entry_set_reference_divider(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), |
LEVEL0_MPLL_REF_DIV(divider), ~LEVEL0_MPLL_REF_DIV_MASK); |
} |
static void rv6xx_vid_response_set_brt(struct radeon_device *rdev, u32 rt) |
{ |
WREG32_P(VID_RT, BRT(rt), ~BRT_MASK); |
} |
static void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device *rdev) |
{ |
WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC); |
} |
static u32 rv6xx_clocks_per_unit(u32 unit) |
{ |
u32 tmp = 1 << (2 * unit); |
return tmp; |
} |
static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, |
u32 unscaled_count, u32 unit) |
{ |
u32 count_per_unit = rv6xx_clocks_per_unit(unit); |
return (unscaled_count + count_per_unit - 1) / count_per_unit; |
} |
static u32 rv6xx_compute_count_for_delay(struct radeon_device *rdev, |
u32 delay_us, u32 unit) |
{ |
u32 ref_clk = rdev->clock.spll.reference_freq; |
return rv6xx_scale_count_given_unit(rdev, delay_us * (ref_clk / 100), unit); |
} |
static void rv6xx_calculate_engine_speed_stepping_parameters(struct radeon_device *rdev, |
struct rv6xx_ps *state) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
pi->hw.sclks[R600_POWER_LEVEL_LOW] = |
state->low.sclk; |
pi->hw.sclks[R600_POWER_LEVEL_MEDIUM] = |
state->medium.sclk; |
pi->hw.sclks[R600_POWER_LEVEL_HIGH] = |
state->high.sclk; |
pi->hw.low_sclk_index = R600_POWER_LEVEL_LOW; |
pi->hw.medium_sclk_index = R600_POWER_LEVEL_MEDIUM; |
pi->hw.high_sclk_index = R600_POWER_LEVEL_HIGH; |
} |
static void rv6xx_calculate_memory_clock_stepping_parameters(struct radeon_device *rdev, |
struct rv6xx_ps *state) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
pi->hw.mclks[R600_POWER_LEVEL_CTXSW] = |
state->high.mclk; |
pi->hw.mclks[R600_POWER_LEVEL_HIGH] = |
state->high.mclk; |
pi->hw.mclks[R600_POWER_LEVEL_MEDIUM] = |
state->medium.mclk; |
pi->hw.mclks[R600_POWER_LEVEL_LOW] = |
state->low.mclk; |
pi->hw.high_mclk_index = R600_POWER_LEVEL_HIGH; |
if (state->high.mclk == state->medium.mclk) |
pi->hw.medium_mclk_index = |
pi->hw.high_mclk_index; |
else |
pi->hw.medium_mclk_index = R600_POWER_LEVEL_MEDIUM; |
if (state->medium.mclk == state->low.mclk) |
pi->hw.low_mclk_index = |
pi->hw.medium_mclk_index; |
else |
pi->hw.low_mclk_index = R600_POWER_LEVEL_LOW; |
} |
static void rv6xx_calculate_voltage_stepping_parameters(struct radeon_device *rdev, |
struct rv6xx_ps *state) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
pi->hw.vddc[R600_POWER_LEVEL_CTXSW] = state->high.vddc; |
pi->hw.vddc[R600_POWER_LEVEL_HIGH] = state->high.vddc; |
pi->hw.vddc[R600_POWER_LEVEL_MEDIUM] = state->medium.vddc; |
pi->hw.vddc[R600_POWER_LEVEL_LOW] = state->low.vddc; |
pi->hw.backbias[R600_POWER_LEVEL_CTXSW] = |
(state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; |
pi->hw.backbias[R600_POWER_LEVEL_HIGH] = |
(state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; |
pi->hw.backbias[R600_POWER_LEVEL_MEDIUM] = |
(state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; |
pi->hw.backbias[R600_POWER_LEVEL_LOW] = |
(state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; |
pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH] = |
(state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; |
pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM] = |
(state->medium.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; |
pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW] = |
(state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; |
pi->hw.high_vddc_index = R600_POWER_LEVEL_HIGH; |
if ((state->high.vddc == state->medium.vddc) && |
((state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) == |
(state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))) |
pi->hw.medium_vddc_index = |
pi->hw.high_vddc_index; |
else |
pi->hw.medium_vddc_index = R600_POWER_LEVEL_MEDIUM; |
if ((state->medium.vddc == state->low.vddc) && |
((state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) == |
(state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))) |
pi->hw.low_vddc_index = |
pi->hw.medium_vddc_index; |
else |
pi->hw.medium_vddc_index = R600_POWER_LEVEL_LOW; |
} |
static inline u32 rv6xx_calculate_vco_frequency(u32 ref_clock, |
struct atom_clock_dividers *dividers, |
u32 fb_divider_scale) |
{ |
return ref_clock * ((dividers->fb_div & ~1) << fb_divider_scale) / |
(dividers->ref_div + 1); |
} |
static inline u32 rv6xx_calculate_spread_spectrum_clk_v(u32 vco_freq, u32 ref_freq, |
u32 ss_rate, u32 ss_percent, |
u32 fb_divider_scale) |
{ |
u32 fb_divider = vco_freq / ref_freq; |
return (ss_percent * ss_rate * 4 * (fb_divider * fb_divider) / |
(5375 * ((vco_freq * 10) / (4096 >> fb_divider_scale)))); |
} |
static inline u32 rv6xx_calculate_spread_spectrum_clk_s(u32 ss_rate, u32 ref_freq) |
{ |
return (((ref_freq * 10) / (ss_rate * 2)) - 1) / 4; |
} |
static void rv6xx_program_engine_spread_spectrum(struct radeon_device *rdev, |
u32 clock, enum r600_power_level level) |
{ |
u32 ref_clk = rdev->clock.spll.reference_freq; |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
struct atom_clock_dividers dividers; |
struct radeon_atom_ss ss; |
u32 vco_freq, clk_v, clk_s; |
rv6xx_enable_engine_spread_spectrum(rdev, level, false); |
if (clock && pi->sclk_ss) { |
if (radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, clock, false, ÷rs) == 0) { |
vco_freq = rv6xx_calculate_vco_frequency(ref_clk, ÷rs, |
pi->fb_div_scale); |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, vco_freq)) { |
clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq, |
(ref_clk / (dividers.ref_div + 1)), |
ss.rate, |
ss.percentage, |
pi->fb_div_scale); |
clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate, |
(ref_clk / (dividers.ref_div + 1))); |
rv6xx_set_engine_spread_spectrum_clk_v(rdev, level, clk_v); |
rv6xx_set_engine_spread_spectrum_clk_s(rdev, level, clk_s); |
rv6xx_enable_engine_spread_spectrum(rdev, level, true); |
} |
} |
} |
} |
static void rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
rv6xx_program_engine_spread_spectrum(rdev, |
pi->hw.sclks[R600_POWER_LEVEL_HIGH], |
R600_POWER_LEVEL_HIGH); |
rv6xx_program_engine_spread_spectrum(rdev, |
pi->hw.sclks[R600_POWER_LEVEL_MEDIUM], |
R600_POWER_LEVEL_MEDIUM); |
} |
static int rv6xx_program_mclk_stepping_entry(struct radeon_device *rdev, |
u32 entry, u32 clock) |
{ |
struct atom_clock_dividers dividers; |
if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, clock, false, ÷rs)) |
return -EINVAL; |
rv6xx_memory_clock_entry_set_reference_divider(rdev, entry, dividers.ref_div); |
rv6xx_memory_clock_entry_set_feedback_divider(rdev, entry, dividers.fb_div); |
rv6xx_memory_clock_entry_set_post_divider(rdev, entry, dividers.post_div); |
if (dividers.enable_post_div) |
rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, true); |
else |
rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, false); |
return 0; |
} |
static void rv6xx_program_mclk_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
int i; |
for (i = 1; i < R600_PM_NUMBER_OF_MCLKS; i++) { |
if (pi->hw.mclks[i]) |
rv6xx_program_mclk_stepping_entry(rdev, i, |
pi->hw.mclks[i]); |
} |
} |
static void rv6xx_find_memory_clock_with_highest_vco(struct radeon_device *rdev, |
u32 requested_memory_clock, |
u32 ref_clk, |
struct atom_clock_dividers *dividers, |
u32 *vco_freq) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
struct atom_clock_dividers req_dividers; |
u32 vco_freq_temp; |
if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, |
requested_memory_clock, false, &req_dividers) == 0) { |
vco_freq_temp = rv6xx_calculate_vco_frequency(ref_clk, &req_dividers, |
pi->fb_div_scale); |
if (vco_freq_temp > *vco_freq) { |
*dividers = req_dividers; |
*vco_freq = vco_freq_temp; |
} |
} |
} |
static void rv6xx_program_mclk_spread_spectrum_parameters(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
u32 ref_clk = rdev->clock.mpll.reference_freq; |
struct atom_clock_dividers dividers; |
struct radeon_atom_ss ss; |
u32 vco_freq = 0, clk_v, clk_s; |
rv6xx_enable_memory_spread_spectrum(rdev, false); |
if (pi->mclk_ss) { |
rv6xx_find_memory_clock_with_highest_vco(rdev, |
pi->hw.mclks[pi->hw.high_mclk_index], |
ref_clk, |
÷rs, |
&vco_freq); |
rv6xx_find_memory_clock_with_highest_vco(rdev, |
pi->hw.mclks[pi->hw.medium_mclk_index], |
ref_clk, |
÷rs, |
&vco_freq); |
rv6xx_find_memory_clock_with_highest_vco(rdev, |
pi->hw.mclks[pi->hw.low_mclk_index], |
ref_clk, |
÷rs, |
&vco_freq); |
if (vco_freq) { |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, vco_freq)) { |
clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq, |
(ref_clk / (dividers.ref_div + 1)), |
ss.rate, |
ss.percentage, |
pi->fb_div_scale); |
clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate, |
(ref_clk / (dividers.ref_div + 1))); |
rv6xx_set_memory_spread_spectrum_clk_v(rdev, clk_v); |
rv6xx_set_memory_spread_spectrum_clk_s(rdev, clk_s); |
rv6xx_enable_memory_spread_spectrum(rdev, true); |
} |
} |
} |
} |
static int rv6xx_program_voltage_stepping_entry(struct radeon_device *rdev, |
u32 entry, u16 voltage) |
{ |
u32 mask, set_pins; |
int ret; |
ret = radeon_atom_get_voltage_gpio_settings(rdev, voltage, |
SET_VOLTAGE_TYPE_ASIC_VDDC, |
&set_pins, &mask); |
if (ret) |
return ret; |
r600_voltage_control_program_voltages(rdev, entry, set_pins); |
return 0; |
} |
static void rv6xx_program_voltage_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
int i; |
for (i = 1; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) |
rv6xx_program_voltage_stepping_entry(rdev, i, |
pi->hw.vddc[i]); |
} |
static void rv6xx_program_backbias_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
if (pi->hw.backbias[1]) |
WREG32_P(VID_UPPER_GPIO_CNTL, MEDIUM_BACKBIAS_VALUE, ~MEDIUM_BACKBIAS_VALUE); |
else |
WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~MEDIUM_BACKBIAS_VALUE); |
if (pi->hw.backbias[2]) |
WREG32_P(VID_UPPER_GPIO_CNTL, HIGH_BACKBIAS_VALUE, ~HIGH_BACKBIAS_VALUE); |
else |
WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~HIGH_BACKBIAS_VALUE); |
} |
static void rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
rv6xx_program_engine_spread_spectrum(rdev, |
pi->hw.sclks[R600_POWER_LEVEL_LOW], |
R600_POWER_LEVEL_LOW); |
} |
static void rv6xx_program_mclk_stepping_parameters_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
if (pi->hw.mclks[0]) |
rv6xx_program_mclk_stepping_entry(rdev, 0, |
pi->hw.mclks[0]); |
} |
static void rv6xx_program_voltage_stepping_parameters_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
rv6xx_program_voltage_stepping_entry(rdev, 0, |
pi->hw.vddc[0]); |
} |
static void rv6xx_program_backbias_stepping_parameters_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
if (pi->hw.backbias[0]) |
WREG32_P(VID_UPPER_GPIO_CNTL, LOW_BACKBIAS_VALUE, ~LOW_BACKBIAS_VALUE); |
else |
WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~LOW_BACKBIAS_VALUE); |
} |
static u32 calculate_memory_refresh_rate(struct radeon_device *rdev, |
u32 engine_clock) |
{ |
u32 dram_rows, dram_refresh_rate; |
u32 tmp; |
tmp = (RREG32(RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; |
dram_rows = 1 << (tmp + 10); |
dram_refresh_rate = 1 << ((RREG32(MC_SEQ_RESERVE_M) & 0x3) + 3); |
return ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64; |
} |
static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
u32 sqm_ratio; |
u32 arb_refresh_rate; |
u32 high_clock; |
if (pi->hw.sclks[R600_POWER_LEVEL_HIGH] < |
(pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40)) |
high_clock = pi->hw.sclks[R600_POWER_LEVEL_HIGH]; |
else |
high_clock = |
pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40; |
radeon_atom_set_engine_dram_timings(rdev, high_clock, 0); |
sqm_ratio = (STATE0(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_LOW]) | |
STATE1(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_MEDIUM]) | |
STATE2(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]) | |
STATE3(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH])); |
WREG32(SQM_RATIO, sqm_ratio); |
arb_refresh_rate = |
(POWERMODE0(calculate_memory_refresh_rate(rdev, |
pi->hw.sclks[R600_POWER_LEVEL_LOW])) | |
POWERMODE1(calculate_memory_refresh_rate(rdev, |
pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) | |
POWERMODE2(calculate_memory_refresh_rate(rdev, |
pi->hw.sclks[R600_POWER_LEVEL_HIGH])) | |
POWERMODE3(calculate_memory_refresh_rate(rdev, |
pi->hw.sclks[R600_POWER_LEVEL_HIGH]))); |
WREG32(ARB_RFSH_RATE, arb_refresh_rate); |
} |
static void rv6xx_program_mpll_timing_parameters(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
r600_set_mpll_lock_time(rdev, R600_MPLLLOCKTIME_DFLT * |
pi->mpll_ref_div); |
r600_set_mpll_reset_time(rdev, R600_MPLLRESETTIME_DFLT); |
} |
static void rv6xx_program_bsp(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
u32 ref_clk = rdev->clock.spll.reference_freq; |
r600_calculate_u_and_p(R600_ASI_DFLT, |
ref_clk, 16, |
&pi->bsp, |
&pi->bsu); |
r600_set_bsp(rdev, pi->bsu, pi->bsp); |
} |
static void rv6xx_program_at(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
r600_set_at(rdev, |
(pi->hw.rp[0] * pi->bsp) / 200, |
(pi->hw.rp[1] * pi->bsp) / 200, |
(pi->hw.lp[2] * pi->bsp) / 200, |
(pi->hw.lp[1] * pi->bsp) / 200); |
} |
static void rv6xx_program_git(struct radeon_device *rdev) |
{ |
r600_set_git(rdev, R600_GICST_DFLT); |
} |
static void rv6xx_program_tp(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) |
r600_set_tc(rdev, i, r600_utc[i], r600_dtc[i]); |
r600_select_td(rdev, R600_TD_DFLT); |
} |
static void rv6xx_program_vc(struct radeon_device *rdev) |
{ |
r600_set_vrc(rdev, R600_VRC_DFLT); |
} |
static void rv6xx_clear_vc(struct radeon_device *rdev) |
{ |
r600_set_vrc(rdev, 0); |
} |
static void rv6xx_program_tpp(struct radeon_device *rdev) |
{ |
r600_set_tpu(rdev, R600_TPU_DFLT); |
r600_set_tpc(rdev, R600_TPC_DFLT); |
} |
static void rv6xx_program_sstp(struct radeon_device *rdev) |
{ |
r600_set_sstu(rdev, R600_SSTU_DFLT); |
r600_set_sst(rdev, R600_SST_DFLT); |
} |
static void rv6xx_program_fcp(struct radeon_device *rdev) |
{ |
r600_set_fctu(rdev, R600_FCTU_DFLT); |
r600_set_fct(rdev, R600_FCT_DFLT); |
} |
static void rv6xx_program_vddc3d_parameters(struct radeon_device *rdev) |
{ |
r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT); |
r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT); |
r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT); |
r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT); |
r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT); |
} |
static void rv6xx_program_voltage_timing_parameters(struct radeon_device *rdev) |
{ |
u32 rt; |
r600_vid_rt_set_vru(rdev, R600_VRU_DFLT); |
r600_vid_rt_set_vrt(rdev, |
rv6xx_compute_count_for_delay(rdev, |
rdev->pm.dpm.voltage_response_time, |
R600_VRU_DFLT)); |
rt = rv6xx_compute_count_for_delay(rdev, |
rdev->pm.dpm.backbias_response_time, |
R600_VRU_DFLT); |
rv6xx_vid_response_set_brt(rdev, (rt + 0x1F) >> 5); |
} |
static void rv6xx_program_engine_speed_parameters(struct radeon_device *rdev) |
{ |
r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT); |
rv6xx_enable_engine_feedback_and_reference_sync(rdev); |
} |
static u64 rv6xx_get_master_voltage_mask(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
u64 master_mask = 0; |
int i; |
for (i = 0; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) { |
u32 tmp_mask, tmp_set_pins; |
int ret; |
ret = radeon_atom_get_voltage_gpio_settings(rdev, |
pi->hw.vddc[i], |
SET_VOLTAGE_TYPE_ASIC_VDDC, |
&tmp_set_pins, &tmp_mask); |
if (ret == 0) |
master_mask |= tmp_mask; |
} |
return master_mask; |
} |
static void rv6xx_program_voltage_gpio_pins(struct radeon_device *rdev) |
{ |
r600_voltage_control_enable_pins(rdev, |
rv6xx_get_master_voltage_mask(rdev)); |
} |
static void rv6xx_enable_static_voltage_control(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
bool enable) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
if (enable) |
radeon_atom_set_voltage(rdev, |
new_state->low.vddc, |
SET_VOLTAGE_TYPE_ASIC_VDDC); |
else |
r600_voltage_control_deactivate_static_control(rdev, |
rv6xx_get_master_voltage_mask(rdev)); |
} |
static void rv6xx_enable_display_gap(struct radeon_device *rdev, bool enable) |
{ |
if (enable) { |
u32 tmp = (DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) | |
DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) | |
DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | |
DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | |
VBI_TIMER_COUNT(0x3FFF) | |
VBI_TIMER_UNIT(7)); |
WREG32(CG_DISPLAY_GAP_CNTL, tmp); |
WREG32_P(MCLK_PWRMGT_CNTL, USE_DISPLAY_GAP, ~USE_DISPLAY_GAP); |
} else |
WREG32_P(MCLK_PWRMGT_CNTL, 0, ~USE_DISPLAY_GAP); |
} |
static void rv6xx_program_power_level_enter_state(struct radeon_device *rdev) |
{ |
r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_MEDIUM); |
} |
static void rv6xx_calculate_t(u32 l_f, u32 h_f, int h, |
int d_l, int d_r, u8 *l, u8 *r) |
{ |
int a_n, a_d, h_r, l_r; |
h_r = d_l; |
l_r = 100 - d_r; |
a_n = (int)h_f * d_l + (int)l_f * (h - d_r); |
a_d = (int)l_f * l_r + (int)h_f * h_r; |
if (a_d != 0) { |
*l = d_l - h_r * a_n / a_d; |
*r = d_r + l_r * a_n / a_d; |
} |
} |
static void rv6xx_calculate_ap(struct radeon_device *rdev, |
struct rv6xx_ps *state) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
pi->hw.lp[0] = 0; |
pi->hw.rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS - 1] |
= 100; |
rv6xx_calculate_t(state->low.sclk, |
state->medium.sclk, |
R600_AH_DFLT, |
R600_LMP_DFLT, |
R600_RLP_DFLT, |
&pi->hw.lp[1], |
&pi->hw.rp[0]); |
rv6xx_calculate_t(state->medium.sclk, |
state->high.sclk, |
R600_AH_DFLT, |
R600_LHP_DFLT, |
R600_RMP_DFLT, |
&pi->hw.lp[2], |
&pi->hw.rp[1]); |
} |
static void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev, |
struct radeon_ps *new_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
rv6xx_calculate_engine_speed_stepping_parameters(rdev, new_state); |
rv6xx_calculate_memory_clock_stepping_parameters(rdev, new_state); |
rv6xx_calculate_voltage_stepping_parameters(rdev, new_state); |
rv6xx_calculate_ap(rdev, new_state); |
} |
static void rv6xx_program_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
rv6xx_program_mclk_stepping_parameters_except_lowest_entry(rdev); |
if (pi->voltage_control) |
rv6xx_program_voltage_stepping_parameters_except_lowest_entry(rdev); |
rv6xx_program_backbias_stepping_parameters_except_lowest_entry(rdev); |
rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(rdev); |
rv6xx_program_mclk_spread_spectrum_parameters(rdev); |
rv6xx_program_memory_timing_parameters(rdev); |
} |
static void rv6xx_program_stepping_parameters_lowest_entry(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
rv6xx_program_mclk_stepping_parameters_lowest_entry(rdev); |
if (pi->voltage_control) |
rv6xx_program_voltage_stepping_parameters_lowest_entry(rdev); |
rv6xx_program_backbias_stepping_parameters_lowest_entry(rdev); |
rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(rdev); |
} |
static void rv6xx_program_power_level_low(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, |
pi->hw.low_vddc_index); |
r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, |
pi->hw.low_mclk_index); |
r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, |
pi->hw.low_sclk_index); |
r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, |
R600_DISPLAY_WATERMARK_LOW); |
r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW, |
pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); |
} |
static void rv6xx_program_power_level_low_to_lowest_state(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0); |
r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); |
r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); |
r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, |
R600_DISPLAY_WATERMARK_LOW); |
r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW, |
pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); |
} |
static void rv6xx_program_power_level_medium(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, |
pi->hw.medium_vddc_index); |
r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, |
pi->hw.medium_mclk_index); |
r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, |
pi->hw.medium_sclk_index); |
r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, |
R600_DISPLAY_WATERMARK_LOW); |
r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM, |
pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM]); |
} |
static void rv6xx_program_power_level_medium_for_transition(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
rv6xx_program_mclk_stepping_entry(rdev, |
R600_POWER_LEVEL_CTXSW, |
pi->hw.mclks[pi->hw.low_mclk_index]); |
r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 1); |
r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, |
R600_POWER_LEVEL_CTXSW); |
r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, |
pi->hw.medium_sclk_index); |
r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, |
R600_DISPLAY_WATERMARK_LOW); |
rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false); |
r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM, |
pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); |
} |
static void rv6xx_program_power_level_high(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH, |
pi->hw.high_vddc_index); |
r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH, |
pi->hw.high_mclk_index); |
r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH, |
pi->hw.high_sclk_index); |
r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH, |
R600_DISPLAY_WATERMARK_HIGH); |
r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_HIGH, |
pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH]); |
} |
static void rv6xx_enable_backbias(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL, |
~(BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL)); |
else |
WREG32_P(GENERAL_PWRMGT, 0, |
~(BACKBIAS_VALUE | BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL)); |
} |
static void rv6xx_program_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); |
tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); |
if (rdev->pm.dpm.new_active_crtcs & 1) { |
tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); |
tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); |
} else if (rdev->pm.dpm.new_active_crtcs & 2) { |
tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); |
tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); |
} else { |
tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); |
tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); |
} |
WREG32(CG_DISPLAY_GAP_CNTL, tmp); |
} |
static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); |
u16 safe_voltage; |
safe_voltage = (new_state->low.vddc >= old_state->low.vddc) ? |
new_state->low.vddc : old_state->low.vddc; |
rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, |
safe_voltage); |
WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW), |
~SW_GPIO_INDEX_MASK); |
} |
static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); |
rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, |
old_state->low.vddc); |
WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW), |
~SW_GPIO_INDEX_MASK); |
} |
static void rv6xx_set_safe_backbias(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); |
if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) && |
(old_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)) |
WREG32_P(GENERAL_PWRMGT, BACKBIAS_VALUE, ~BACKBIAS_VALUE); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_VALUE); |
} |
static void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); |
if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) != |
(old_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)) |
rv6xx_force_pcie_gen1(rdev); |
} |
static void rv6xx_enable_dynamic_voltage_control(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN); |
} |
static void rv6xx_enable_dynamic_backbias_control(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, BACKBIAS_DPM_CNTL, ~BACKBIAS_DPM_CNTL); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_DPM_CNTL); |
} |
static int rv6xx_step_sw_voltage(struct radeon_device *rdev, |
u16 initial_voltage, |
u16 target_voltage) |
{ |
u16 current_voltage; |
u16 true_target_voltage; |
u16 voltage_step; |
int signed_voltage_step; |
if ((radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, |
&voltage_step)) || |
(radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, |
initial_voltage, ¤t_voltage)) || |
(radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, |
target_voltage, &true_target_voltage))) |
return -EINVAL; |
if (true_target_voltage < current_voltage) |
signed_voltage_step = -(int)voltage_step; |
else |
signed_voltage_step = voltage_step; |
while (current_voltage != true_target_voltage) { |
current_voltage += signed_voltage_step; |
rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, |
current_voltage); |
msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000); |
} |
return 0; |
} |
static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); |
if (new_state->low.vddc > old_state->low.vddc) |
return rv6xx_step_sw_voltage(rdev, |
old_state->low.vddc, |
new_state->low.vddc); |
return 0; |
} |
static int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); |
if (new_state->low.vddc < old_state->low.vddc) |
return rv6xx_step_sw_voltage(rdev, |
old_state->low.vddc, |
new_state->low.vddc); |
else |
return 0; |
} |
static void rv6xx_enable_high(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
if ((pi->restricted_levels < 1) || |
(pi->restricted_levels == 3)) |
r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); |
} |
static void rv6xx_enable_medium(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
if (pi->restricted_levels < 2) |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); |
} |
static void rv6xx_set_dpm_event_sources(struct radeon_device *rdev, u32 sources) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
bool want_thermal_protection; |
enum radeon_dpm_event_src dpm_event_src; |
switch (sources) { |
case 0: |
default: |
want_thermal_protection = false; |
break; |
case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL; |
break; |
case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL; |
break; |
case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) | |
(1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL; |
break; |
} |
if (want_thermal_protection) { |
WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK); |
if (pi->thermal_protection) |
WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); |
} else { |
WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); |
} |
} |
static void rv6xx_enable_auto_throttle_source(struct radeon_device *rdev, |
enum radeon_dpm_auto_throttle_src source, |
bool enable) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
if (enable) { |
if (!(pi->active_auto_throttle_sources & (1 << source))) { |
pi->active_auto_throttle_sources |= 1 << source; |
rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); |
} |
} else { |
if (pi->active_auto_throttle_sources & (1 << source)) { |
pi->active_auto_throttle_sources &= ~(1 << source); |
rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); |
} |
} |
} |
static void rv6xx_enable_thermal_protection(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
if (pi->active_auto_throttle_sources) |
r600_enable_thermal_protection(rdev, enable); |
} |
static void rv6xx_generate_transition_stepping(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
rv6xx_generate_steps(rdev, |
old_state->low.sclk, |
new_state->low.sclk, |
0, &pi->hw.medium_sclk_index); |
} |
static void rv6xx_generate_low_step(struct radeon_device *rdev, |
struct radeon_ps *new_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
pi->hw.low_sclk_index = 0; |
rv6xx_generate_single_step(rdev, |
new_state->low.sclk, |
0); |
} |
static void rv6xx_invalidate_intermediate_steps(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
rv6xx_invalidate_intermediate_steps_range(rdev, 0, |
pi->hw.medium_sclk_index); |
} |
static void rv6xx_generate_stepping_table(struct radeon_device *rdev, |
struct radeon_ps *new_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
pi->hw.low_sclk_index = 0; |
rv6xx_generate_steps(rdev, |
new_state->low.sclk, |
new_state->medium.sclk, |
0, |
&pi->hw.medium_sclk_index); |
rv6xx_generate_steps(rdev, |
new_state->medium.sclk, |
new_state->high.sclk, |
pi->hw.medium_sclk_index, |
&pi->hw.high_sclk_index); |
} |
static void rv6xx_enable_spread_spectrum(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
rv6xx_enable_dynamic_spread_spectrum(rdev, true); |
else { |
rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_LOW, false); |
rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false); |
rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_HIGH, false); |
rv6xx_enable_dynamic_spread_spectrum(rdev, false); |
rv6xx_enable_memory_spread_spectrum(rdev, false); |
} |
} |
static void rv6xx_reset_lvtm_data_sync(struct radeon_device *rdev) |
{ |
if (ASIC_IS_DCE3(rdev)) |
WREG32_P(DCE3_LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG); |
else |
WREG32_P(LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG); |
} |
static void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
bool enable) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
if (enable) { |
rv6xx_enable_bif_dynamic_pcie_gen2(rdev, true); |
rv6xx_enable_pcie_gen2_support(rdev); |
r600_enable_dynamic_pcie_gen2(rdev, true); |
} else { |
if (!(new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)) |
rv6xx_force_pcie_gen1(rdev); |
rv6xx_enable_bif_dynamic_pcie_gen2(rdev, false); |
r600_enable_dynamic_pcie_gen2(rdev, false); |
} |
} |
static void rv6xx_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_ps *current_state = rv6xx_get_ps(old_ps); |
if ((new_ps->vclk == old_ps->vclk) && |
(new_ps->dclk == old_ps->dclk)) |
return; |
if (new_state->high.sclk >= current_state->high.sclk) |
return; |
radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); |
} |
static void rv6xx_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); |
struct rv6xx_ps *current_state = rv6xx_get_ps(old_ps); |
if ((new_ps->vclk == old_ps->vclk) && |
(new_ps->dclk == old_ps->dclk)) |
return; |
if (new_state->high.sclk < current_state->high.sclk) |
return; |
radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); |
} |
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; |
if (r600_dynamicpm_enabled(rdev)) |
return -EINVAL; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) |
rv6xx_enable_backbias(rdev, true); |
if (pi->dynamic_ss) |
rv6xx_enable_spread_spectrum(rdev, true); |
rv6xx_program_mpll_timing_parameters(rdev); |
rv6xx_program_bsp(rdev); |
rv6xx_program_git(rdev); |
rv6xx_program_tp(rdev); |
rv6xx_program_tpp(rdev); |
rv6xx_program_sstp(rdev); |
rv6xx_program_fcp(rdev); |
rv6xx_program_vddc3d_parameters(rdev); |
rv6xx_program_voltage_timing_parameters(rdev); |
rv6xx_program_engine_speed_parameters(rdev); |
rv6xx_enable_display_gap(rdev, true); |
if (pi->display_gap == false) |
rv6xx_enable_display_gap(rdev, false); |
rv6xx_program_power_level_enter_state(rdev); |
rv6xx_calculate_stepping_parameters(rdev, boot_ps); |
if (pi->voltage_control) |
rv6xx_program_voltage_gpio_pins(rdev); |
rv6xx_generate_stepping_table(rdev, boot_ps); |
rv6xx_program_stepping_parameters_except_lowest_entry(rdev); |
rv6xx_program_stepping_parameters_lowest_entry(rdev); |
rv6xx_program_power_level_low(rdev); |
rv6xx_program_power_level_medium(rdev); |
rv6xx_program_power_level_high(rdev); |
rv6xx_program_vc(rdev); |
rv6xx_program_at(rdev); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); |
rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); |
r600_start_dpm(rdev); |
if (pi->voltage_control) |
rv6xx_enable_static_voltage_control(rdev, boot_ps, false); |
if (pi->dynamic_pcie_gen2) |
rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, true); |
if (pi->gfx_clock_gating) |
r600_gfx_clockgating_enable(rdev, true); |
return 0; |
} |
void rv6xx_dpm_disable(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
if (!r600_dynamicpm_enabled(rdev)) |
return; |
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); |
rv6xx_enable_display_gap(rdev, false); |
rv6xx_clear_vc(rdev); |
r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); |
if (pi->thermal_protection) |
r600_enable_thermal_protection(rdev, false); |
r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) |
rv6xx_enable_backbias(rdev, false); |
rv6xx_enable_spread_spectrum(rdev, false); |
if (pi->voltage_control) |
rv6xx_enable_static_voltage_control(rdev, boot_ps, true); |
if (pi->dynamic_pcie_gen2) |
rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, false); |
if (rdev->irq.installed && |
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { |
rdev->irq.dpm_thermal = false; |
radeon_irq_set(rdev); |
} |
if (pi->gfx_clock_gating) |
r600_gfx_clockgating_enable(rdev, false); |
r600_stop_dpm(rdev); |
} |
int rv6xx_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; |
struct radeon_ps *old_ps = rdev->pm.dpm.current_ps; |
int ret; |
pi->restricted_levels = 0; |
rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
rv6xx_clear_vc(rdev); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); |
r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); |
if (pi->thermal_protection) |
r600_enable_thermal_protection(rdev, false); |
r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); |
rv6xx_generate_transition_stepping(rdev, new_ps, old_ps); |
rv6xx_program_power_level_medium_for_transition(rdev); |
if (pi->voltage_control) { |
rv6xx_set_sw_voltage_to_safe(rdev, new_ps, old_ps); |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) |
rv6xx_set_sw_voltage_to_low(rdev, old_ps); |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) |
rv6xx_set_safe_backbias(rdev, new_ps, old_ps); |
if (pi->dynamic_pcie_gen2) |
rv6xx_set_safe_pcie_gen2(rdev, new_ps, old_ps); |
if (pi->voltage_control) |
rv6xx_enable_dynamic_voltage_control(rdev, false); |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) |
rv6xx_enable_dynamic_backbias_control(rdev, false); |
if (pi->voltage_control) { |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) |
rv6xx_step_voltage_if_increasing(rdev, new_ps, old_ps); |
msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000); |
} |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false); |
r600_wait_for_power_level_unequal(rdev, R600_POWER_LEVEL_LOW); |
rv6xx_generate_low_step(rdev, new_ps); |
rv6xx_invalidate_intermediate_steps(rdev); |
rv6xx_calculate_stepping_parameters(rdev, new_ps); |
rv6xx_program_stepping_parameters_lowest_entry(rdev); |
rv6xx_program_power_level_low_to_lowest_state(rdev); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); |
r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); |
if (pi->voltage_control) { |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) { |
ret = rv6xx_step_voltage_if_decreasing(rdev, new_ps, old_ps); |
if (ret) |
return ret; |
} |
rv6xx_enable_dynamic_voltage_control(rdev, true); |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) |
rv6xx_enable_dynamic_backbias_control(rdev, true); |
if (pi->dynamic_pcie_gen2) |
rv6xx_enable_dynamic_pcie_gen2(rdev, new_ps, true); |
rv6xx_reset_lvtm_data_sync(rdev); |
rv6xx_generate_stepping_table(rdev, new_ps); |
rv6xx_program_stepping_parameters_except_lowest_entry(rdev); |
rv6xx_program_power_level_low(rdev); |
rv6xx_program_power_level_medium(rdev); |
rv6xx_program_power_level_high(rdev); |
rv6xx_enable_medium(rdev); |
rv6xx_enable_high(rdev); |
if (pi->thermal_protection) |
rv6xx_enable_thermal_protection(rdev, true); |
rv6xx_program_vc(rdev); |
rv6xx_program_at(rdev); |
rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
return 0; |
} |
void rv6xx_setup_asic(struct radeon_device *rdev) |
{ |
r600_enable_acpi_pm(rdev); |
if (radeon_aspm != 0) { |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) |
rv6xx_enable_l0s(rdev); |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) |
rv6xx_enable_l1(rdev); |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) |
rv6xx_enable_pll_sleep_in_l1(rdev); |
} |
} |
void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
rv6xx_program_display_gap(rdev); |
} |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void rv6xx_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) |
{ |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (r600_is_uvd_state(rps->class, rps->class2)) { |
rps->vclk = RV6XX_DEFAULT_VCLK_FREQ; |
rps->dclk = RV6XX_DEFAULT_DCLK_FREQ; |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) |
rdev->pm.dpm.boot_ps = rps; |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void rv6xx_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, int index, |
union pplib_clock_info *clock_info) |
{ |
struct rv6xx_ps *ps = rv6xx_get_ps(rps); |
u32 sclk, mclk; |
u16 vddc; |
struct rv6xx_pl *pl; |
switch (index) { |
case 0: |
pl = &ps->low; |
break; |
case 1: |
pl = &ps->medium; |
break; |
case 2: |
default: |
pl = &ps->high; |
break; |
} |
sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); |
sclk |= clock_info->r600.ucEngineClockHigh << 16; |
mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); |
mclk |= clock_info->r600.ucMemoryClockHigh << 16; |
pl->mclk = mclk; |
pl->sclk = sclk; |
pl->vddc = le16_to_cpu(clock_info->r600.usVDDC); |
pl->flags = le32_to_cpu(clock_info->r600.ulFlags); |
/* patch up vddc if necessary */ |
if (pl->vddc == 0xff01) { |
if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) |
pl->vddc = vddc; |
} |
/* fix up pcie gen2 */ |
if (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) { |
if ((rdev->family == CHIP_RV610) || (rdev->family == CHIP_RV630)) { |
if (pl->vddc < 1100) |
pl->flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2; |
} |
} |
/* patch up boot state */ |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
u16 vddc, vddci, mvdd; |
radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); |
pl->mclk = rdev->clock.default_mclk; |
pl->sclk = rdev->clock.default_sclk; |
pl->vddc = vddc; |
} |
} |
static int rv6xx_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i, j; |
union pplib_clock_info *clock_info; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
struct rv6xx_ps *ps; |
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.ps = kzalloc(sizeof(struct radeon_ps) * |
power_info->pplib.ucNumStates, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
for (i = 0; i < power_info->pplib.ucNumStates; i++) { |
power_state = (union pplib_power_state *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset) + |
i * power_info->pplib.ucStateEntrySize); |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + |
(power_state->v1.ucNonClockStateIndex * |
power_info->pplib.ucNonClockSize)); |
if (power_info->pplib.ucStateEntrySize - 1) { |
u8 *idx; |
ps = kzalloc(sizeof(struct rv6xx_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
rv6xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info); |
idx = (u8 *)&power_state->v1.ucClockStateIndices[0]; |
for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { |
clock_info = (union pplib_clock_info *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + |
(idx[j] * power_info->pplib.ucClockInfoSize)); |
rv6xx_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], j, |
clock_info); |
} |
} |
} |
rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates; |
return 0; |
} |
int rv6xx_dpm_init(struct radeon_device *rdev) |
{ |
struct radeon_atom_ss ss; |
struct atom_clock_dividers dividers; |
struct rv6xx_power_info *pi; |
int ret; |
pi = kzalloc(sizeof(struct rv6xx_power_info), GFP_KERNEL); |
if (pi == NULL) |
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; |
if (rdev->pm.dpm.voltage_response_time == 0) |
rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; |
if (rdev->pm.dpm.backbias_response_time == 0) |
rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
0, false, ÷rs); |
if (ret) |
pi->spll_ref_div = dividers.ref_div + 1; |
else |
pi->spll_ref_div = R600_REFERENCEDIVIDER_DFLT; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, |
0, false, ÷rs); |
if (ret) |
pi->mpll_ref_div = dividers.ref_div + 1; |
else |
pi->mpll_ref_div = R600_REFERENCEDIVIDER_DFLT; |
if (rdev->family >= CHIP_RV670) |
pi->fb_div_scale = 1; |
else |
pi->fb_div_scale = 0; |
pi->voltage_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0); |
pi->gfx_clock_gating = true; |
pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, 0); |
pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, 0); |
/* Disable sclk ss, causes hangs on a lot of systems */ |
pi->sclk_ss = false; |
if (pi->sclk_ss || pi->mclk_ss) |
pi->dynamic_ss = true; |
else |
pi->dynamic_ss = false; |
pi->dynamic_pcie_gen2 = true; |
if (pi->gfx_clock_gating && |
(rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) |
pi->thermal_protection = true; |
else |
pi->thermal_protection = false; |
pi->display_gap = true; |
return 0; |
} |
void rv6xx_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct rv6xx_ps *ps = rv6xx_get_ps(rps); |
struct rv6xx_pl *pl; |
r600_dpm_print_class_info(rps->class, rps->class2); |
r600_dpm_print_cap_info(rps->caps); |
printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
pl = &ps->low; |
printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n", |
pl->sclk, pl->mclk, pl->vddc); |
pl = &ps->medium; |
printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n", |
pl->sclk, pl->mclk, pl->vddc); |
pl = &ps->high; |
printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n", |
pl->sclk, pl->mclk, pl->vddc); |
r600_dpm_print_ps_status(rdev, rps); |
} |
void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m) |
{ |
struct radeon_ps *rps = rdev->pm.dpm.current_ps; |
struct rv6xx_ps *ps = rv6xx_get_ps(rps); |
struct rv6xx_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); |
seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n", |
current_index, pl->sclk, pl->mclk, pl->vddc); |
} |
} |
void rv6xx_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
} |
u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low) |
{ |
struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); |
if (low) |
return requested_state->low.sclk; |
else |
return requested_state->high.sclk; |
} |
u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); |
if (low) |
return requested_state->low.mclk; |
else |
return requested_state->high.mclk; |
} |
int rv6xx_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
pi->restricted_levels = 3; |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
pi->restricted_levels = 2; |
} else { |
pi->restricted_levels = 0; |
} |
rv6xx_clear_vc(rdev); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); |
r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); |
r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); |
r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); |
rv6xx_enable_medium(rdev); |
rv6xx_enable_high(rdev); |
if (pi->restricted_levels == 3) |
r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false); |
rv6xx_program_vc(rdev); |
rv6xx_program_at(rdev); |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
/drivers/video/drm/radeon/rv6xx_dpm.h |
---|
0,0 → 1,95 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#ifndef __RV6XX_DPM_H__ |
#define __RV6XX_DPM_H__ |
#include "r600_dpm.h" |
/* Represents a single SCLK step. */ |
struct rv6xx_sclk_stepping |
{ |
u32 vco_frequency; |
u32 post_divider; |
}; |
struct rv6xx_pm_hw_state { |
u32 sclks[R600_PM_NUMBER_OF_ACTIVITY_LEVELS]; |
u32 mclks[R600_PM_NUMBER_OF_MCLKS]; |
u16 vddc[R600_PM_NUMBER_OF_VOLTAGE_LEVELS]; |
bool backbias[R600_PM_NUMBER_OF_VOLTAGE_LEVELS]; |
bool pcie_gen2[R600_PM_NUMBER_OF_ACTIVITY_LEVELS]; |
u8 high_sclk_index; |
u8 medium_sclk_index; |
u8 low_sclk_index; |
u8 high_mclk_index; |
u8 medium_mclk_index; |
u8 low_mclk_index; |
u8 high_vddc_index; |
u8 medium_vddc_index; |
u8 low_vddc_index; |
u8 rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS]; |
u8 lp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS]; |
}; |
struct rv6xx_power_info { |
/* flags */ |
bool voltage_control; |
bool sclk_ss; |
bool mclk_ss; |
bool dynamic_ss; |
bool dynamic_pcie_gen2; |
bool thermal_protection; |
bool display_gap; |
bool gfx_clock_gating; |
/* clk values */ |
u32 fb_div_scale; |
u32 spll_ref_div; |
u32 mpll_ref_div; |
u32 bsu; |
u32 bsp; |
/* */ |
u32 active_auto_throttle_sources; |
/* current power state */ |
u32 restricted_levels; |
struct rv6xx_pm_hw_state hw; |
}; |
struct rv6xx_pl { |
u32 sclk; |
u32 mclk; |
u16 vddc; |
u32 flags; |
}; |
struct rv6xx_ps { |
struct rv6xx_pl high; |
struct rv6xx_pl medium; |
struct rv6xx_pl low; |
}; |
#define RV6XX_DEFAULT_VCLK_FREQ 40000 /* 10 khz */ |
#define RV6XX_DEFAULT_DCLK_FREQ 30000 /* 10 khz */ |
#endif |
/drivers/video/drm/radeon/rv6xxd.h |
---|
0,0 → 1,246 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef RV6XXD_H |
#define RV6XXD_H |
/* RV6xx power management */ |
#define SPLL_CNTL_MODE 0x60c |
# define SPLL_DIV_SYNC (1 << 5) |
#define GENERAL_PWRMGT 0x618 |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define MOBILE_SU (1 << 2) |
# define THERMAL_PROTECTION_DIS (1 << 3) |
# define THERMAL_PROTECTION_TYPE (1 << 4) |
# define ENABLE_GEN2PCIE (1 << 5) |
# define SW_GPIO_INDEX(x) ((x) << 6) |
# define SW_GPIO_INDEX_MASK (3 << 6) |
# define LOW_VOLT_D2_ACPI (1 << 8) |
# define LOW_VOLT_D3_ACPI (1 << 9) |
# define VOLT_PWRMGT_EN (1 << 10) |
# define BACKBIAS_PAD_EN (1 << 16) |
# define BACKBIAS_VALUE (1 << 17) |
# define BACKBIAS_DPM_CNTL (1 << 18) |
# define DYN_SPREAD_SPECTRUM_EN (1 << 21) |
#define MCLK_PWRMGT_CNTL 0x624 |
# define MPLL_PWRMGT_OFF (1 << 0) |
# define YCLK_TURNOFF (1 << 1) |
# define MPLL_TURNOFF (1 << 2) |
# define SU_MCLK_USE_BCLK (1 << 3) |
# define DLL_READY (1 << 4) |
# define MC_BUSY (1 << 5) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCKA_SLEEP (1 << 8) |
# define MRDCKB_SLEEP (1 << 9) |
# define MRDCKC_SLEEP (1 << 10) |
# define MRDCKD_SLEEP (1 << 11) |
# define MRDCKE_SLEEP (1 << 12) |
# define MRDCKF_SLEEP (1 << 13) |
# define MRDCKG_SLEEP (1 << 14) |
# define MRDCKH_SLEEP (1 << 15) |
# define MRDCKA_RESET (1 << 16) |
# define MRDCKB_RESET (1 << 17) |
# define MRDCKC_RESET (1 << 18) |
# define MRDCKD_RESET (1 << 19) |
# define MRDCKE_RESET (1 << 20) |
# define MRDCKF_RESET (1 << 21) |
# define MRDCKG_RESET (1 << 22) |
# define MRDCKH_RESET (1 << 23) |
# define DLL_READY_READ (1 << 24) |
# define USE_DISPLAY_GAP (1 << 25) |
# define USE_DISPLAY_URGENT_NORMAL (1 << 26) |
# define USE_DISPLAY_GAP_CTXSW (1 << 27) |
# define MPLL_TURNOFF_D2 (1 << 28) |
# define USE_DISPLAY_URGENT_CTXSW (1 << 29) |
#define MPLL_FREQ_LEVEL_0 0x6e8 |
# define LEVEL0_MPLL_POST_DIV(x) ((x) << 0) |
# define LEVEL0_MPLL_POST_DIV_MASK (0xff << 0) |
# define LEVEL0_MPLL_FB_DIV(x) ((x) << 8) |
# define LEVEL0_MPLL_FB_DIV_MASK (0xfff << 8) |
# define LEVEL0_MPLL_REF_DIV(x) ((x) << 20) |
# define LEVEL0_MPLL_REF_DIV_MASK (0x3f << 20) |
# define LEVEL0_MPLL_DIV_EN (1 << 28) |
# define LEVEL0_DLL_BYPASS (1 << 29) |
# define LEVEL0_DLL_RESET (1 << 30) |
#define VID_RT 0x6f8 |
# define VID_CRT(x) ((x) << 0) |
# define VID_CRT_MASK (0x1fff << 0) |
# define VID_CRTU(x) ((x) << 13) |
# define VID_CRTU_MASK (7 << 13) |
# define SSTU(x) ((x) << 16) |
# define SSTU_MASK (7 << 16) |
# define VID_SWT(x) ((x) << 19) |
# define VID_SWT_MASK (0x1f << 19) |
# define BRT(x) ((x) << 24) |
# define BRT_MASK (0xff << 24) |
#define TARGET_AND_CURRENT_PROFILE_INDEX 0x70c |
# define TARGET_PROFILE_INDEX_MASK (3 << 0) |
# define TARGET_PROFILE_INDEX_SHIFT 0 |
# define CURRENT_PROFILE_INDEX_MASK (3 << 2) |
# define CURRENT_PROFILE_INDEX_SHIFT 2 |
# define DYN_PWR_ENTER_INDEX(x) ((x) << 4) |
# define DYN_PWR_ENTER_INDEX_MASK (3 << 4) |
# define DYN_PWR_ENTER_INDEX_SHIFT 4 |
# define CURR_MCLK_INDEX_MASK (3 << 6) |
# define CURR_MCLK_INDEX_SHIFT 6 |
# define CURR_SCLK_INDEX_MASK (0x1f << 8) |
# define CURR_SCLK_INDEX_SHIFT 8 |
# define CURR_VID_INDEX_MASK (3 << 13) |
# define CURR_VID_INDEX_SHIFT 13 |
#define VID_UPPER_GPIO_CNTL 0x740 |
# define CTXSW_UPPER_GPIO_VALUES(x) ((x) << 0) |
# define CTXSW_UPPER_GPIO_VALUES_MASK (7 << 0) |
# define HIGH_UPPER_GPIO_VALUES(x) ((x) << 3) |
# define HIGH_UPPER_GPIO_VALUES_MASK (7 << 3) |
# define MEDIUM_UPPER_GPIO_VALUES(x) ((x) << 6) |
# define MEDIUM_UPPER_GPIO_VALUES_MASK (7 << 6) |
# define LOW_UPPER_GPIO_VALUES(x) ((x) << 9) |
# define LOW_UPPER_GPIO_VALUES_MASK (7 << 9) |
# define CTXSW_BACKBIAS_VALUE (1 << 12) |
# define HIGH_BACKBIAS_VALUE (1 << 13) |
# define MEDIUM_BACKBIAS_VALUE (1 << 14) |
# define LOW_BACKBIAS_VALUE (1 << 15) |
#define CG_DISPLAY_GAP_CNTL 0x7dc |
# define DISP1_GAP(x) ((x) << 0) |
# define DISP1_GAP_MASK (3 << 0) |
# define DISP2_GAP(x) ((x) << 2) |
# define DISP2_GAP_MASK (3 << 2) |
# define VBI_TIMER_COUNT(x) ((x) << 4) |
# define VBI_TIMER_COUNT_MASK (0x3fff << 4) |
# define VBI_TIMER_UNIT(x) ((x) << 20) |
# define VBI_TIMER_UNIT_MASK (7 << 20) |
# define DISP1_GAP_MCHG(x) ((x) << 24) |
# define DISP1_GAP_MCHG_MASK (3 << 24) |
# define DISP2_GAP_MCHG(x) ((x) << 26) |
# define DISP2_GAP_MCHG_MASK (3 << 26) |
#define CG_THERMAL_CTRL 0x7f0 |
# define DPM_EVENT_SRC(x) ((x) << 0) |
# define DPM_EVENT_SRC_MASK (7 << 0) |
# define THERM_INC_CLK (1 << 3) |
# define TOFFSET(x) ((x) << 4) |
# define TOFFSET_MASK (0xff << 4) |
# define DIG_THERM_DPM(x) ((x) << 12) |
# define DIG_THERM_DPM_MASK (0xff << 12) |
# define CTF_SEL(x) ((x) << 20) |
# define CTF_SEL_MASK (7 << 20) |
# define CTF_PAD_POLARITY (1 << 23) |
# define CTF_PAD_EN (1 << 24) |
#define CG_SPLL_SPREAD_SPECTRUM_LOW 0x820 |
# define SSEN (1 << 0) |
# define CLKS(x) ((x) << 3) |
# define CLKS_MASK (0xff << 3) |
# define CLKS_SHIFT 3 |
# define CLKV(x) ((x) << 11) |
# define CLKV_MASK (0x7ff << 11) |
# define CLKV_SHIFT 11 |
#define CG_MPLL_SPREAD_SPECTRUM 0x830 |
#define CITF_CNTL 0x200c |
# define BLACKOUT_RD (1 << 0) |
# define BLACKOUT_WR (1 << 1) |
#define RAMCFG 0x2408 |
#define NOOFBANK_SHIFT 0 |
#define NOOFBANK_MASK 0x00000001 |
#define NOOFRANK_SHIFT 1 |
#define NOOFRANK_MASK 0x00000002 |
#define NOOFROWS_SHIFT 2 |
#define NOOFROWS_MASK 0x0000001C |
#define NOOFCOLS_SHIFT 5 |
#define NOOFCOLS_MASK 0x00000060 |
#define CHANSIZE_SHIFT 7 |
#define CHANSIZE_MASK 0x00000080 |
#define BURSTLENGTH_SHIFT 8 |
#define BURSTLENGTH_MASK 0x00000100 |
#define CHANSIZE_OVERRIDE (1 << 10) |
#define SQM_RATIO 0x2424 |
# define STATE0(x) ((x) << 0) |
# define STATE0_MASK (0xff << 0) |
# define STATE1(x) ((x) << 8) |
# define STATE1_MASK (0xff << 8) |
# define STATE2(x) ((x) << 16) |
# define STATE2_MASK (0xff << 16) |
# define STATE3(x) ((x) << 24) |
# define STATE3_MASK (0xff << 24) |
#define ARB_RFSH_CNTL 0x2460 |
# define ENABLE (1 << 0) |
#define ARB_RFSH_RATE 0x2464 |
# define POWERMODE0(x) ((x) << 0) |
# define POWERMODE0_MASK (0xff << 0) |
# define POWERMODE1(x) ((x) << 8) |
# define POWERMODE1_MASK (0xff << 8) |
# define POWERMODE2(x) ((x) << 16) |
# define POWERMODE2_MASK (0xff << 16) |
# define POWERMODE3(x) ((x) << 24) |
# define POWERMODE3_MASK (0xff << 24) |
#define MC_SEQ_DRAM 0x2608 |
# define CKE_DYN (1 << 12) |
#define MC_SEQ_CMD 0x26c4 |
#define MC_SEQ_RESERVE_S 0x2890 |
#define MC_SEQ_RESERVE_M 0x2894 |
#define LVTMA_DATA_SYNCHRONIZATION 0x7adc |
# define LVTMA_PFREQCHG (1 << 8) |
#define DCE3_LVTMA_DATA_SYNCHRONIZATION 0x7f98 |
/* PCIE indirect regs */ |
#define PCIE_P_CNTL 0x40 |
# define P_PLL_PWRDN_IN_L1L23 (1 << 3) |
# define P_PLL_BUF_PDNB (1 << 4) |
# define P_PLL_PDNB (1 << 9) |
# define P_ALLOW_PRX_FRONTEND_SHUTOFF (1 << 12) |
/* PCIE PORT indirect regs */ |
#define PCIE_LC_CNTL 0xa0 |
# define LC_L0S_INACTIVITY(x) ((x) << 8) |
# define LC_L0S_INACTIVITY_MASK (0xf << 8) |
# define LC_L0S_INACTIVITY_SHIFT 8 |
# define LC_L1_INACTIVITY(x) ((x) << 12) |
# define LC_L1_INACTIVITY_MASK (0xf << 12) |
# define LC_L1_INACTIVITY_SHIFT 12 |
# define LC_PMI_TO_L1_DIS (1 << 16) |
# define LC_ASPM_TO_L1_DIS (1 << 24) |
#define PCIE_LC_SPEED_CNTL 0xa4 |
# define LC_GEN2_EN (1 << 0) |
# define LC_INITIATE_LINK_SPEED_CHANGE (1 << 7) |
# define LC_CURRENT_DATA_RATE (1 << 11) |
# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12 |
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) |
# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) |
#endif |
/drivers/video/drm/radeon/rv730_dpm.c |
---|
0,0 → 1,508 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "rv730d.h" |
#include "r600_dpm.h" |
#include "rv770_dpm.h" |
#include "atom.h" |
#define MC_CG_ARB_FREQ_F0 0x0a |
#define MC_CG_ARB_FREQ_F1 0x0b |
#define MC_CG_ARB_FREQ_F2 0x0c |
#define MC_CG_ARB_FREQ_F3 0x0d |
struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps); |
struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev); |
int rv730_populate_sclk_value(struct radeon_device *rdev, |
u32 engine_clock, |
RV770_SMC_SCLK_VALUE *sclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct atom_clock_dividers dividers; |
u32 spll_func_cntl = pi->clk_regs.rv730.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = pi->clk_regs.rv730.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = pi->clk_regs.rv730.cg_spll_func_cntl_3; |
u32 cg_spll_spread_spectrum = pi->clk_regs.rv730.cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv730.cg_spll_spread_spectrum_2; |
u64 tmp; |
u32 reference_clock = rdev->clock.spll.reference_freq; |
u32 reference_divider, post_divider; |
u32 fbdiv; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
engine_clock, false, ÷rs); |
if (ret) |
return ret; |
reference_divider = 1 + dividers.ref_div; |
if (dividers.enable_post_div) |
post_divider = ((dividers.post_div >> 4) & 0xf) + |
(dividers.post_div & 0xf) + 2; |
else |
post_divider = 1; |
tmp = (u64) engine_clock * reference_divider * post_divider * 16384; |
do_div(tmp, reference_clock); |
fbdiv = (u32) tmp; |
/* set up registers */ |
if (dividers.enable_post_div) |
spll_func_cntl |= SPLL_DIVEN; |
else |
spll_func_cntl &= ~SPLL_DIVEN; |
spll_func_cntl &= ~(SPLL_HILEN_MASK | SPLL_LOLEN_MASK | SPLL_REF_DIV_MASK); |
spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div); |
spll_func_cntl |= SPLL_HILEN((dividers.post_div >> 4) & 0xf); |
spll_func_cntl |= SPLL_LOLEN(dividers.post_div & 0xf); |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(2); |
spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK; |
spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv); |
spll_func_cntl_3 |= SPLL_DITHEN; |
if (pi->sclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = engine_clock * post_divider; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, vco_freq)) { |
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); |
u32 clk_v = ss.percentage * fbdiv / (clk_s * 10000); |
cg_spll_spread_spectrum &= ~CLK_S_MASK; |
cg_spll_spread_spectrum |= CLK_S(clk_s); |
cg_spll_spread_spectrum |= SSEN; |
cg_spll_spread_spectrum_2 &= ~CLK_V_MASK; |
cg_spll_spread_spectrum_2 |= CLK_V(clk_v); |
} |
} |
sclk->sclk_value = cpu_to_be32(engine_clock); |
sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); |
sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); |
sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); |
sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum); |
sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2); |
return 0; |
} |
int rv730_populate_mclk_value(struct radeon_device *rdev, |
u32 engine_clock, u32 memory_clock, |
LPRV7XX_SMC_MCLK_VALUE mclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 mclk_pwrmgt_cntl = pi->clk_regs.rv730.mclk_pwrmgt_cntl; |
u32 dll_cntl = pi->clk_regs.rv730.dll_cntl; |
u32 mpll_func_cntl = pi->clk_regs.rv730.mpll_func_cntl; |
u32 mpll_func_cntl_2 = pi->clk_regs.rv730.mpll_func_cntl2; |
u32 mpll_func_cntl_3 = pi->clk_regs.rv730.mpll_func_cntl3; |
u32 mpll_ss = pi->clk_regs.rv730.mpll_ss; |
u32 mpll_ss2 = pi->clk_regs.rv730.mpll_ss2; |
struct atom_clock_dividers dividers; |
u32 post_divider, reference_divider; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, |
memory_clock, false, ÷rs); |
if (ret) |
return ret; |
reference_divider = dividers.ref_div + 1; |
if (dividers.enable_post_div) |
post_divider = ((dividers.post_div >> 4) & 0xf) + |
(dividers.post_div & 0xf) + 2; |
else |
post_divider = 1; |
/* setup the registers */ |
if (dividers.enable_post_div) |
mpll_func_cntl |= MPLL_DIVEN; |
else |
mpll_func_cntl &= ~MPLL_DIVEN; |
mpll_func_cntl &= ~(MPLL_REF_DIV_MASK | MPLL_HILEN_MASK | MPLL_LOLEN_MASK); |
mpll_func_cntl |= MPLL_REF_DIV(dividers.ref_div); |
mpll_func_cntl |= MPLL_HILEN((dividers.post_div >> 4) & 0xf); |
mpll_func_cntl |= MPLL_LOLEN(dividers.post_div & 0xf); |
mpll_func_cntl_3 &= ~MPLL_FB_DIV_MASK; |
mpll_func_cntl_3 |= MPLL_FB_DIV(dividers.fb_div); |
if (dividers.enable_dithen) |
mpll_func_cntl_3 |= MPLL_DITHEN; |
else |
mpll_func_cntl_3 &= ~MPLL_DITHEN; |
if (pi->mclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = memory_clock * post_divider; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, vco_freq)) { |
u32 reference_clock = rdev->clock.mpll.reference_freq; |
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); |
u32 clk_v = ss.percentage * dividers.fb_div / (clk_s * 10000); |
mpll_ss &= ~CLK_S_MASK; |
mpll_ss |= CLK_S(clk_s); |
mpll_ss |= SSEN; |
mpll_ss2 &= ~CLK_V_MASK; |
mpll_ss |= CLK_V(clk_v); |
} |
} |
mclk->mclk730.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
mclk->mclk730.vDLL_CNTL = cpu_to_be32(dll_cntl); |
mclk->mclk730.mclk_value = cpu_to_be32(memory_clock); |
mclk->mclk730.vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl); |
mclk->mclk730.vMPLL_FUNC_CNTL2 = cpu_to_be32(mpll_func_cntl_2); |
mclk->mclk730.vMPLL_FUNC_CNTL3 = cpu_to_be32(mpll_func_cntl_3); |
mclk->mclk730.vMPLL_SS = cpu_to_be32(mpll_ss); |
mclk->mclk730.vMPLL_SS2 = cpu_to_be32(mpll_ss2); |
return 0; |
} |
void rv730_read_clock_registers(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
pi->clk_regs.rv730.cg_spll_func_cntl = |
RREG32(CG_SPLL_FUNC_CNTL); |
pi->clk_regs.rv730.cg_spll_func_cntl_2 = |
RREG32(CG_SPLL_FUNC_CNTL_2); |
pi->clk_regs.rv730.cg_spll_func_cntl_3 = |
RREG32(CG_SPLL_FUNC_CNTL_3); |
pi->clk_regs.rv730.cg_spll_spread_spectrum = |
RREG32(CG_SPLL_SPREAD_SPECTRUM); |
pi->clk_regs.rv730.cg_spll_spread_spectrum_2 = |
RREG32(CG_SPLL_SPREAD_SPECTRUM_2); |
pi->clk_regs.rv730.mclk_pwrmgt_cntl = |
RREG32(TCI_MCLK_PWRMGT_CNTL); |
pi->clk_regs.rv730.dll_cntl = |
RREG32(TCI_DLL_CNTL); |
pi->clk_regs.rv730.mpll_func_cntl = |
RREG32(CG_MPLL_FUNC_CNTL); |
pi->clk_regs.rv730.mpll_func_cntl2 = |
RREG32(CG_MPLL_FUNC_CNTL_2); |
pi->clk_regs.rv730.mpll_func_cntl3 = |
RREG32(CG_MPLL_FUNC_CNTL_3); |
pi->clk_regs.rv730.mpll_ss = |
RREG32(CG_TCI_MPLL_SPREAD_SPECTRUM); |
pi->clk_regs.rv730.mpll_ss2 = |
RREG32(CG_TCI_MPLL_SPREAD_SPECTRUM_2); |
} |
int rv730_populate_smc_acpi_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 mpll_func_cntl = 0; |
u32 mpll_func_cntl_2 = 0 ; |
u32 mpll_func_cntl_3 = 0; |
u32 mclk_pwrmgt_cntl; |
u32 dll_cntl; |
u32 spll_func_cntl; |
u32 spll_func_cntl_2; |
u32 spll_func_cntl_3; |
table->ACPIState = table->initialState; |
table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC; |
if (pi->acpi_vddc) { |
rv770_populate_vddc_value(rdev, pi->acpi_vddc, |
&table->ACPIState.levels[0].vddc); |
table->ACPIState.levels[0].gen2PCIE = pi->pcie_gen2 ? |
pi->acpi_pcie_gen2 : 0; |
table->ACPIState.levels[0].gen2XSP = |
pi->acpi_pcie_gen2; |
} else { |
rv770_populate_vddc_value(rdev, pi->min_vddc_in_table, |
&table->ACPIState.levels[0].vddc); |
table->ACPIState.levels[0].gen2PCIE = 0; |
} |
mpll_func_cntl = pi->clk_regs.rv730.mpll_func_cntl; |
mpll_func_cntl_2 = pi->clk_regs.rv730.mpll_func_cntl2; |
mpll_func_cntl_3 = pi->clk_regs.rv730.mpll_func_cntl3; |
mpll_func_cntl |= MPLL_RESET | MPLL_BYPASS_EN; |
mpll_func_cntl &= ~MPLL_SLEEP; |
mpll_func_cntl_2 &= ~MCLK_MUX_SEL_MASK; |
mpll_func_cntl_2 |= MCLK_MUX_SEL(1); |
mclk_pwrmgt_cntl = (MRDCKA_RESET | |
MRDCKB_RESET | |
MRDCKC_RESET | |
MRDCKD_RESET | |
MRDCKE_RESET | |
MRDCKF_RESET | |
MRDCKG_RESET | |
MRDCKH_RESET | |
MRDCKA_SLEEP | |
MRDCKB_SLEEP | |
MRDCKC_SLEEP | |
MRDCKD_SLEEP | |
MRDCKE_SLEEP | |
MRDCKF_SLEEP | |
MRDCKG_SLEEP | |
MRDCKH_SLEEP); |
dll_cntl = 0xff000000; |
spll_func_cntl = pi->clk_regs.rv730.cg_spll_func_cntl; |
spll_func_cntl_2 = pi->clk_regs.rv730.cg_spll_func_cntl_2; |
spll_func_cntl_3 = pi->clk_regs.rv730.cg_spll_func_cntl_3; |
spll_func_cntl |= SPLL_RESET | SPLL_BYPASS_EN; |
spll_func_cntl &= ~SPLL_SLEEP; |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(4); |
table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl); |
table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL2 = cpu_to_be32(mpll_func_cntl_2); |
table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL3 = cpu_to_be32(mpll_func_cntl_3); |
table->ACPIState.levels[0].mclk.mclk730.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
table->ACPIState.levels[0].mclk.mclk730.vDLL_CNTL = cpu_to_be32(dll_cntl); |
table->ACPIState.levels[0].mclk.mclk730.mclk_value = 0; |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); |
table->ACPIState.levels[0].sclk.sclk_value = 0; |
rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd); |
table->ACPIState.levels[1] = table->ACPIState.levels[0]; |
table->ACPIState.levels[2] = table->ACPIState.levels[0]; |
return 0; |
} |
int rv730_populate_smc_initial_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_ps *initial_state = rv770_get_ps(radeon_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 a_t; |
table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL = |
cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl); |
table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL2 = |
cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl2); |
table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL3 = |
cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl3); |
table->initialState.levels[0].mclk.mclk730.vMCLK_PWRMGT_CNTL = |
cpu_to_be32(pi->clk_regs.rv730.mclk_pwrmgt_cntl); |
table->initialState.levels[0].mclk.mclk730.vDLL_CNTL = |
cpu_to_be32(pi->clk_regs.rv730.dll_cntl); |
table->initialState.levels[0].mclk.mclk730.vMPLL_SS = |
cpu_to_be32(pi->clk_regs.rv730.mpll_ss); |
table->initialState.levels[0].mclk.mclk730.vMPLL_SS2 = |
cpu_to_be32(pi->clk_regs.rv730.mpll_ss2); |
table->initialState.levels[0].mclk.mclk730.mclk_value = |
cpu_to_be32(initial_state->low.mclk); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = |
cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = |
cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl_2); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = |
cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl_3); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM = |
cpu_to_be32(pi->clk_regs.rv730.cg_spll_spread_spectrum); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 = |
cpu_to_be32(pi->clk_regs.rv730.cg_spll_spread_spectrum_2); |
table->initialState.levels[0].sclk.sclk_value = |
cpu_to_be32(initial_state->low.sclk); |
table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0; |
table->initialState.levels[0].seqValue = |
rv770_get_seq_value(rdev, &initial_state->low); |
rv770_populate_vddc_value(rdev, |
initial_state->low.vddc, |
&table->initialState.levels[0].vddc); |
rv770_populate_initial_mvdd_value(rdev, |
&table->initialState.levels[0].mvdd); |
a_t = CG_R(0xffff) | CG_L(0); |
table->initialState.levels[0].aT = cpu_to_be32(a_t); |
table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp); |
if (pi->boot_in_gen2) |
table->initialState.levels[0].gen2PCIE = 1; |
else |
table->initialState.levels[0].gen2PCIE = 0; |
if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) |
table->initialState.levels[0].gen2XSP = 1; |
else |
table->initialState.levels[0].gen2XSP = 0; |
table->initialState.levels[1] = table->initialState.levels[0]; |
table->initialState.levels[2] = table->initialState.levels[0]; |
table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC; |
return 0; |
} |
void rv730_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct rv7xx_ps *state = rv770_get_ps(radeon_state); |
u32 arb_refresh_rate = 0; |
u32 dram_timing = 0; |
u32 dram_timing2 = 0; |
u32 old_dram_timing = 0; |
u32 old_dram_timing2 = 0; |
arb_refresh_rate = RREG32(MC_ARB_RFSH_RATE) & |
~(POWERMODE1_MASK | POWERMODE2_MASK | POWERMODE3_MASK); |
arb_refresh_rate |= |
(POWERMODE1(rv770_calculate_memory_refresh_rate(rdev, state->low.sclk)) | |
POWERMODE2(rv770_calculate_memory_refresh_rate(rdev, state->medium.sclk)) | |
POWERMODE3(rv770_calculate_memory_refresh_rate(rdev, state->high.sclk))); |
WREG32(MC_ARB_RFSH_RATE, arb_refresh_rate); |
/* save the boot dram timings */ |
old_dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
old_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
radeon_atom_set_engine_dram_timings(rdev, |
state->high.sclk, |
state->high.mclk); |
dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
WREG32(MC_ARB_DRAM_TIMING_3, dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2_3, dram_timing2); |
radeon_atom_set_engine_dram_timings(rdev, |
state->medium.sclk, |
state->medium.mclk); |
dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
WREG32(MC_ARB_DRAM_TIMING_2, dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2_2, dram_timing2); |
radeon_atom_set_engine_dram_timings(rdev, |
state->low.sclk, |
state->low.mclk); |
dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
WREG32(MC_ARB_DRAM_TIMING_1, dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2_1, dram_timing2); |
/* restore the boot dram timings */ |
WREG32(MC_ARB_DRAM_TIMING, old_dram_timing); |
WREG32(MC_ARB_DRAM_TIMING2, old_dram_timing2); |
} |
void rv730_start_dpm(struct radeon_device *rdev) |
{ |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF); |
WREG32_P(TCI_MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF); |
WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN); |
} |
void rv730_stop_dpm(struct radeon_device *rdev) |
{ |
PPSMC_Result result; |
result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled); |
if (result != PPSMC_Result_OK) |
DRM_ERROR("Could not force DPM to low\n"); |
WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF); |
WREG32_P(TCI_MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF); |
} |
void rv730_program_dcodt(struct radeon_device *rdev, bool use_dcodt) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 i = use_dcodt ? 0 : 1; |
u32 mc4_io_pad_cntl; |
mc4_io_pad_cntl = RREG32(MC4_IO_DQ_PAD_CNTL_D0_I0); |
mc4_io_pad_cntl &= 0xFFFFFF00; |
mc4_io_pad_cntl |= pi->odt_value_0[i]; |
WREG32(MC4_IO_DQ_PAD_CNTL_D0_I0, mc4_io_pad_cntl); |
WREG32(MC4_IO_DQ_PAD_CNTL_D0_I1, mc4_io_pad_cntl); |
mc4_io_pad_cntl = RREG32(MC4_IO_QS_PAD_CNTL_D0_I0); |
mc4_io_pad_cntl &= 0xFFFFFF00; |
mc4_io_pad_cntl |= pi->odt_value_1[i]; |
WREG32(MC4_IO_QS_PAD_CNTL_D0_I0, mc4_io_pad_cntl); |
WREG32(MC4_IO_QS_PAD_CNTL_D0_I1, mc4_io_pad_cntl); |
} |
void rv730_get_odt_values(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 mc4_io_pad_cntl; |
pi->odt_value_0[0] = (u8)0; |
pi->odt_value_1[0] = (u8)0x80; |
mc4_io_pad_cntl = RREG32(MC4_IO_DQ_PAD_CNTL_D0_I0); |
pi->odt_value_0[1] = (u8)(mc4_io_pad_cntl & 0xff); |
mc4_io_pad_cntl = RREG32(MC4_IO_QS_PAD_CNTL_D0_I0); |
pi->odt_value_1[1] = (u8)(mc4_io_pad_cntl & 0xff); |
} |
/drivers/video/drm/radeon/rv730d.h |
---|
0,0 → 1,165 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef RV730_H |
#define RV730_H |
#define CG_SPLL_FUNC_CNTL 0x600 |
#define SPLL_RESET (1 << 0) |
#define SPLL_SLEEP (1 << 1) |
#define SPLL_DIVEN (1 << 2) |
#define SPLL_BYPASS_EN (1 << 3) |
#define SPLL_REF_DIV(x) ((x) << 4) |
#define SPLL_REF_DIV_MASK (0x3f << 4) |
#define SPLL_HILEN(x) ((x) << 12) |
#define SPLL_HILEN_MASK (0xf << 12) |
#define SPLL_LOLEN(x) ((x) << 16) |
#define SPLL_LOLEN_MASK (0xf << 16) |
#define CG_SPLL_FUNC_CNTL_2 0x604 |
#define SCLK_MUX_SEL(x) ((x) << 0) |
#define SCLK_MUX_SEL_MASK (0x1ff << 0) |
#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_MPLL_FUNC_CNTL 0x624 |
#define MPLL_RESET (1 << 0) |
#define MPLL_SLEEP (1 << 1) |
#define MPLL_DIVEN (1 << 2) |
#define MPLL_BYPASS_EN (1 << 3) |
#define MPLL_REF_DIV(x) ((x) << 4) |
#define MPLL_REF_DIV_MASK (0x3f << 4) |
#define MPLL_HILEN(x) ((x) << 12) |
#define MPLL_HILEN_MASK (0xf << 12) |
#define MPLL_LOLEN(x) ((x) << 16) |
#define MPLL_LOLEN_MASK (0xf << 16) |
#define CG_MPLL_FUNC_CNTL_2 0x628 |
#define MCLK_MUX_SEL(x) ((x) << 0) |
#define MCLK_MUX_SEL_MASK (0x1ff << 0) |
#define CG_MPLL_FUNC_CNTL_3 0x62c |
#define MPLL_FB_DIV(x) ((x) << 0) |
#define MPLL_FB_DIV_MASK (0x3ffffff << 0) |
#define MPLL_DITHEN (1 << 28) |
#define CG_TCI_MPLL_SPREAD_SPECTRUM 0x634 |
#define CG_TCI_MPLL_SPREAD_SPECTRUM_2 0x638 |
#define GENERAL_PWRMGT 0x63c |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define THERMAL_PROTECTION_DIS (1 << 2) |
# define THERMAL_PROTECTION_TYPE (1 << 3) |
# define ENABLE_GEN2PCIE (1 << 4) |
# define ENABLE_GEN2XSP (1 << 5) |
# define SW_SMIO_INDEX(x) ((x) << 6) |
# define SW_SMIO_INDEX_MASK (3 << 6) |
# define LOW_VOLT_D2_ACPI (1 << 8) |
# define LOW_VOLT_D3_ACPI (1 << 9) |
# define VOLT_PWRMGT_EN (1 << 10) |
# define BACKBIAS_PAD_EN (1 << 18) |
# define BACKBIAS_VALUE (1 << 19) |
# define DYN_SPREAD_SPECTRUM_EN (1 << 23) |
# define AC_DC_SW (1 << 24) |
#define SCLK_PWRMGT_CNTL 0x644 |
# define SCLK_PWRMGT_OFF (1 << 0) |
# define SCLK_LOW_D1 (1 << 1) |
# define FIR_RESET (1 << 4) |
# define FIR_FORCE_TREND_SEL (1 << 5) |
# define FIR_TREND_MODE (1 << 6) |
# define DYN_GFX_CLK_OFF_EN (1 << 7) |
# define GFX_CLK_FORCE_ON (1 << 8) |
# define GFX_CLK_REQUEST_OFF (1 << 9) |
# define GFX_CLK_FORCE_OFF (1 << 10) |
# define GFX_CLK_OFF_ACPI_D1 (1 << 11) |
# define GFX_CLK_OFF_ACPI_D2 (1 << 12) |
# define GFX_CLK_OFF_ACPI_D3 (1 << 13) |
#define TCI_MCLK_PWRMGT_CNTL 0x648 |
# define MPLL_PWRMGT_OFF (1 << 5) |
# define DLL_READY (1 << 6) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCKA_SLEEP (1 << 8) |
# define MRDCKB_SLEEP (1 << 9) |
# define MRDCKC_SLEEP (1 << 10) |
# define MRDCKD_SLEEP (1 << 11) |
# define MRDCKE_SLEEP (1 << 12) |
# define MRDCKF_SLEEP (1 << 13) |
# define MRDCKG_SLEEP (1 << 14) |
# define MRDCKH_SLEEP (1 << 15) |
# define MRDCKA_RESET (1 << 16) |
# define MRDCKB_RESET (1 << 17) |
# define MRDCKC_RESET (1 << 18) |
# define MRDCKD_RESET (1 << 19) |
# define MRDCKE_RESET (1 << 20) |
# define MRDCKF_RESET (1 << 21) |
# define MRDCKG_RESET (1 << 22) |
# define MRDCKH_RESET (1 << 23) |
# define DLL_READY_READ (1 << 24) |
# define USE_DISPLAY_GAP (1 << 25) |
# define USE_DISPLAY_URGENT_NORMAL (1 << 26) |
# define MPLL_TURNOFF_D2 (1 << 28) |
#define TCI_DLL_CNTL 0x64c |
#define CG_PG_CNTL 0x858 |
# define PWRGATE_ENABLE (1 << 0) |
#define CG_AT 0x6d4 |
#define CG_R(x) ((x) << 0) |
#define CG_R_MASK (0xffff << 0) |
#define CG_L(x) ((x) << 16) |
#define CG_L_MASK (0xffff << 16) |
#define CG_SPLL_SPREAD_SPECTRUM 0x790 |
#define SSEN (1 << 0) |
#define CLK_S(x) ((x) << 4) |
#define CLK_S_MASK (0xfff << 4) |
#define CG_SPLL_SPREAD_SPECTRUM_2 0x794 |
#define CLK_V(x) ((x) << 0) |
#define CLK_V_MASK (0x3ffffff << 0) |
#define MC_ARB_DRAM_TIMING 0x2774 |
#define MC_ARB_DRAM_TIMING2 0x2778 |
#define MC_ARB_RFSH_RATE 0x27b0 |
#define POWERMODE0(x) ((x) << 0) |
#define POWERMODE0_MASK (0xff << 0) |
#define POWERMODE1(x) ((x) << 8) |
#define POWERMODE1_MASK (0xff << 8) |
#define POWERMODE2(x) ((x) << 16) |
#define POWERMODE2_MASK (0xff << 16) |
#define POWERMODE3(x) ((x) << 24) |
#define POWERMODE3_MASK (0xff << 24) |
#define MC_ARB_DRAM_TIMING_1 0x27f0 |
#define MC_ARB_DRAM_TIMING_2 0x27f4 |
#define MC_ARB_DRAM_TIMING_3 0x27f8 |
#define MC_ARB_DRAM_TIMING2_1 0x27fc |
#define MC_ARB_DRAM_TIMING2_2 0x2800 |
#define MC_ARB_DRAM_TIMING2_3 0x2804 |
#define MC4_IO_DQ_PAD_CNTL_D0_I0 0x2978 |
#define MC4_IO_DQ_PAD_CNTL_D0_I1 0x297c |
#define MC4_IO_QS_PAD_CNTL_D0_I0 0x2980 |
#define MC4_IO_QS_PAD_CNTL_D0_I1 0x2984 |
#endif |
/drivers/video/drm/radeon/rv740_dpm.c |
---|
0,0 → 1,416 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "rv740d.h" |
#include "r600_dpm.h" |
#include "rv770_dpm.h" |
#include "atom.h" |
struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev); |
u32 rv740_get_decoded_reference_divider(u32 encoded_ref) |
{ |
u32 ref = 0; |
switch (encoded_ref) { |
case 0: |
ref = 1; |
break; |
case 16: |
ref = 2; |
break; |
case 17: |
ref = 3; |
break; |
case 18: |
ref = 2; |
break; |
case 19: |
ref = 3; |
break; |
case 20: |
ref = 4; |
break; |
case 21: |
ref = 5; |
break; |
default: |
DRM_ERROR("Invalid encoded Reference Divider\n"); |
ref = 0; |
break; |
} |
return ref; |
} |
struct dll_speed_setting { |
u16 min; |
u16 max; |
u32 dll_speed; |
}; |
static struct dll_speed_setting dll_speed_table[16] = |
{ |
{ 270, 320, 0x0f }, |
{ 240, 270, 0x0e }, |
{ 200, 240, 0x0d }, |
{ 180, 200, 0x0c }, |
{ 160, 180, 0x0b }, |
{ 140, 160, 0x0a }, |
{ 120, 140, 0x09 }, |
{ 110, 120, 0x08 }, |
{ 95, 110, 0x07 }, |
{ 85, 95, 0x06 }, |
{ 78, 85, 0x05 }, |
{ 70, 78, 0x04 }, |
{ 65, 70, 0x03 }, |
{ 60, 65, 0x02 }, |
{ 42, 60, 0x01 }, |
{ 00, 42, 0x00 } |
}; |
u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock) |
{ |
int i; |
u32 factor; |
u16 data_rate; |
if (is_gddr5) |
factor = 4; |
else |
factor = 2; |
data_rate = (u16)(memory_clock * factor / 1000); |
if (data_rate < dll_speed_table[0].max) { |
for (i = 0; i < 16; i++) { |
if (data_rate > dll_speed_table[i].min && |
data_rate <= dll_speed_table[i].max) |
return dll_speed_table[i].dll_speed; |
} |
} |
DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n"); |
return 0x0f; |
} |
int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock, |
RV770_SMC_SCLK_VALUE *sclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct atom_clock_dividers dividers; |
u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3; |
u32 cg_spll_spread_spectrum = pi->clk_regs.rv770.cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv770.cg_spll_spread_spectrum_2; |
u64 tmp; |
u32 reference_clock = rdev->clock.spll.reference_freq; |
u32 reference_divider; |
u32 fbdiv; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
engine_clock, false, ÷rs); |
if (ret) |
return ret; |
reference_divider = 1 + dividers.ref_div; |
tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16384; |
do_div(tmp, reference_clock); |
fbdiv = (u32) tmp; |
spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK); |
spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div); |
spll_func_cntl |= SPLL_PDIV_A(dividers.post_div); |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(2); |
spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK; |
spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv); |
spll_func_cntl_3 |= SPLL_DITHEN; |
if (pi->sclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = engine_clock * dividers.post_div; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, vco_freq)) { |
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); |
u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000); |
cg_spll_spread_spectrum &= ~CLK_S_MASK; |
cg_spll_spread_spectrum |= CLK_S(clk_s); |
cg_spll_spread_spectrum |= SSEN; |
cg_spll_spread_spectrum_2 &= ~CLK_V_MASK; |
cg_spll_spread_spectrum_2 |= CLK_V(clk_v); |
} |
} |
sclk->sclk_value = cpu_to_be32(engine_clock); |
sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); |
sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); |
sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); |
sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum); |
sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2); |
return 0; |
} |
int rv740_populate_mclk_value(struct radeon_device *rdev, |
u32 engine_clock, u32 memory_clock, |
RV7XX_SMC_MCLK_VALUE *mclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2; |
u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl; |
u32 dll_cntl = pi->clk_regs.rv770.dll_cntl; |
u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1; |
u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2; |
struct atom_clock_dividers dividers; |
u32 ibias; |
u32 dll_speed; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, |
memory_clock, false, ÷rs); |
if (ret) |
return ret; |
ibias = rv770_map_clkf_to_ibias(rdev, dividers.whole_fb_div); |
mpll_ad_func_cntl &= ~(CLKR_MASK | |
YCLK_POST_DIV_MASK | |
CLKF_MASK | |
CLKFRAC_MASK | |
IBIAS_MASK); |
mpll_ad_func_cntl |= CLKR(dividers.ref_div); |
mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div); |
mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div); |
mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div); |
mpll_ad_func_cntl |= IBIAS(ibias); |
if (dividers.vco_mode) |
mpll_ad_func_cntl_2 |= VCO_MODE; |
else |
mpll_ad_func_cntl_2 &= ~VCO_MODE; |
if (pi->mem_gddr5) { |
mpll_dq_func_cntl &= ~(CLKR_MASK | |
YCLK_POST_DIV_MASK | |
CLKF_MASK | |
CLKFRAC_MASK | |
IBIAS_MASK); |
mpll_dq_func_cntl |= CLKR(dividers.ref_div); |
mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div); |
mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div); |
mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div); |
mpll_dq_func_cntl |= IBIAS(ibias); |
if (dividers.vco_mode) |
mpll_dq_func_cntl_2 |= VCO_MODE; |
else |
mpll_dq_func_cntl_2 &= ~VCO_MODE; |
} |
if (pi->mclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = memory_clock * dividers.post_div; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, vco_freq)) { |
u32 reference_clock = rdev->clock.mpll.reference_freq; |
u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div); |
u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
u32 clk_v = 0x40000 * ss.percentage * |
(dividers.whole_fb_div + (dividers.frac_fb_div / 8)) / (clk_s * 10000); |
mpll_ss1 &= ~CLKV_MASK; |
mpll_ss1 |= CLKV(clk_v); |
mpll_ss2 &= ~CLKS_MASK; |
mpll_ss2 |= CLKS(clk_s); |
} |
} |
dll_speed = rv740_get_dll_speed(pi->mem_gddr5, |
memory_clock); |
mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK; |
mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed); |
mclk->mclk770.mclk_value = cpu_to_be32(memory_clock); |
mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); |
mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); |
mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); |
mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); |
mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl); |
mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1); |
mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2); |
return 0; |
} |
void rv740_read_clock_registers(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
pi->clk_regs.rv770.cg_spll_func_cntl = |
RREG32(CG_SPLL_FUNC_CNTL); |
pi->clk_regs.rv770.cg_spll_func_cntl_2 = |
RREG32(CG_SPLL_FUNC_CNTL_2); |
pi->clk_regs.rv770.cg_spll_func_cntl_3 = |
RREG32(CG_SPLL_FUNC_CNTL_3); |
pi->clk_regs.rv770.cg_spll_spread_spectrum = |
RREG32(CG_SPLL_SPREAD_SPECTRUM); |
pi->clk_regs.rv770.cg_spll_spread_spectrum_2 = |
RREG32(CG_SPLL_SPREAD_SPECTRUM_2); |
pi->clk_regs.rv770.mpll_ad_func_cntl = |
RREG32(MPLL_AD_FUNC_CNTL); |
pi->clk_regs.rv770.mpll_ad_func_cntl_2 = |
RREG32(MPLL_AD_FUNC_CNTL_2); |
pi->clk_regs.rv770.mpll_dq_func_cntl = |
RREG32(MPLL_DQ_FUNC_CNTL); |
pi->clk_regs.rv770.mpll_dq_func_cntl_2 = |
RREG32(MPLL_DQ_FUNC_CNTL_2); |
pi->clk_regs.rv770.mclk_pwrmgt_cntl = |
RREG32(MCLK_PWRMGT_CNTL); |
pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL); |
pi->clk_regs.rv770.mpll_ss1 = RREG32(MPLL_SS1); |
pi->clk_regs.rv770.mpll_ss2 = RREG32(MPLL_SS2); |
} |
int rv740_populate_smc_acpi_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2; |
u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3; |
u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl; |
u32 dll_cntl = pi->clk_regs.rv770.dll_cntl; |
table->ACPIState = table->initialState; |
table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC; |
if (pi->acpi_vddc) { |
rv770_populate_vddc_value(rdev, pi->acpi_vddc, |
&table->ACPIState.levels[0].vddc); |
table->ACPIState.levels[0].gen2PCIE = |
pi->pcie_gen2 ? |
pi->acpi_pcie_gen2 : 0; |
table->ACPIState.levels[0].gen2XSP = |
pi->acpi_pcie_gen2; |
} else { |
rv770_populate_vddc_value(rdev, pi->min_vddc_in_table, |
&table->ACPIState.levels[0].vddc); |
table->ACPIState.levels[0].gen2PCIE = 0; |
} |
mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN; |
mpll_dq_func_cntl_2 |= BYPASS | BIAS_GEN_PDNB | RESET_EN; |
mclk_pwrmgt_cntl |= (MRDCKA0_RESET | |
MRDCKA1_RESET | |
MRDCKB0_RESET | |
MRDCKB1_RESET | |
MRDCKC0_RESET | |
MRDCKC1_RESET | |
MRDCKD0_RESET | |
MRDCKD1_RESET); |
dll_cntl |= (MRDCKA0_BYPASS | |
MRDCKA1_BYPASS | |
MRDCKB0_BYPASS | |
MRDCKB1_BYPASS | |
MRDCKC0_BYPASS | |
MRDCKC1_BYPASS | |
MRDCKD0_BYPASS | |
MRDCKD1_BYPASS); |
spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN; |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(4); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); |
table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl); |
table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0; |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); |
table->ACPIState.levels[0].sclk.sclk_value = 0; |
table->ACPIState.levels[1] = table->ACPIState.levels[0]; |
table->ACPIState.levels[2] = table->ACPIState.levels[0]; |
rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd); |
return 0; |
} |
void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN); |
else |
WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN); |
} |
u8 rv740_get_mclk_frequency_ratio(u32 memory_clock) |
{ |
u8 mc_para_index; |
if ((memory_clock < 10000) || (memory_clock > 47500)) |
mc_para_index = 0x00; |
else |
mc_para_index = (u8)((memory_clock - 10000) / 2500); |
return mc_para_index; |
} |
/drivers/video/drm/radeon/rv740d.h |
---|
0,0 → 1,117 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef RV740_H |
#define RV740_H |
#define CG_SPLL_FUNC_CNTL 0x600 |
#define SPLL_RESET (1 << 0) |
#define SPLL_SLEEP (1 << 1) |
#define SPLL_BYPASS_EN (1 << 3) |
#define SPLL_REF_DIV(x) ((x) << 4) |
#define SPLL_REF_DIV_MASK (0x3f << 4) |
#define SPLL_PDIV_A(x) ((x) << 20) |
#define SPLL_PDIV_A_MASK (0x7f << 20) |
#define CG_SPLL_FUNC_CNTL_2 0x604 |
#define SCLK_MUX_SEL(x) ((x) << 0) |
#define SCLK_MUX_SEL_MASK (0x1ff << 0) |
#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 MPLL_CNTL_MODE 0x61c |
#define SS_SSEN (1 << 24) |
#define MPLL_AD_FUNC_CNTL 0x624 |
#define CLKF(x) ((x) << 0) |
#define CLKF_MASK (0x7f << 0) |
#define CLKR(x) ((x) << 7) |
#define CLKR_MASK (0x1f << 7) |
#define CLKFRAC(x) ((x) << 12) |
#define CLKFRAC_MASK (0x1f << 12) |
#define YCLK_POST_DIV(x) ((x) << 17) |
#define YCLK_POST_DIV_MASK (3 << 17) |
#define IBIAS(x) ((x) << 20) |
#define IBIAS_MASK (0x3ff << 20) |
#define RESET (1 << 30) |
#define PDNB (1 << 31) |
#define MPLL_AD_FUNC_CNTL_2 0x628 |
#define BYPASS (1 << 19) |
#define BIAS_GEN_PDNB (1 << 24) |
#define RESET_EN (1 << 25) |
#define VCO_MODE (1 << 29) |
#define MPLL_DQ_FUNC_CNTL 0x62c |
#define MPLL_DQ_FUNC_CNTL_2 0x630 |
#define MCLK_PWRMGT_CNTL 0x648 |
#define DLL_SPEED(x) ((x) << 0) |
#define DLL_SPEED_MASK (0x1f << 0) |
# define MPLL_PWRMGT_OFF (1 << 5) |
# define DLL_READY (1 << 6) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCKA0_SLEEP (1 << 8) |
# define MRDCKA1_SLEEP (1 << 9) |
# define MRDCKB0_SLEEP (1 << 10) |
# define MRDCKB1_SLEEP (1 << 11) |
# define MRDCKC0_SLEEP (1 << 12) |
# define MRDCKC1_SLEEP (1 << 13) |
# define MRDCKD0_SLEEP (1 << 14) |
# define MRDCKD1_SLEEP (1 << 15) |
# define MRDCKA0_RESET (1 << 16) |
# define MRDCKA1_RESET (1 << 17) |
# define MRDCKB0_RESET (1 << 18) |
# define MRDCKB1_RESET (1 << 19) |
# define MRDCKC0_RESET (1 << 20) |
# define MRDCKC1_RESET (1 << 21) |
# define MRDCKD0_RESET (1 << 22) |
# define MRDCKD1_RESET (1 << 23) |
# define DLL_READY_READ (1 << 24) |
# define USE_DISPLAY_GAP (1 << 25) |
# define USE_DISPLAY_URGENT_NORMAL (1 << 26) |
# define MPLL_TURNOFF_D2 (1 << 28) |
#define DLL_CNTL 0x64c |
# define MRDCKA0_BYPASS (1 << 24) |
# define MRDCKA1_BYPASS (1 << 25) |
# define MRDCKB0_BYPASS (1 << 26) |
# define MRDCKB1_BYPASS (1 << 27) |
# define MRDCKC0_BYPASS (1 << 28) |
# define MRDCKC1_BYPASS (1 << 29) |
# define MRDCKD0_BYPASS (1 << 30) |
# define MRDCKD1_BYPASS (1 << 31) |
#define CG_SPLL_SPREAD_SPECTRUM 0x790 |
#define SSEN (1 << 0) |
#define CLK_S(x) ((x) << 4) |
#define CLK_S_MASK (0xfff << 4) |
#define CG_SPLL_SPREAD_SPECTRUM_2 0x794 |
#define CLK_V(x) ((x) << 0) |
#define CLK_V_MASK (0x3ffffff << 0) |
#define MPLL_SS1 0x85c |
#define CLKV(x) ((x) << 0) |
#define CLKV_MASK (0x3ffffff << 0) |
#define MPLL_SS2 0x860 |
#define CLKS(x) ((x) << 0) |
#define CLKS_MASK (0xfff << 0) |
#endif |
/drivers/video/drm/radeon/rv770.c |
---|
744,10 → 744,10 |
(const u32)ARRAY_SIZE(r7xx_golden_dyn_gpr_registers)); |
radeon_program_register_sequence(rdev, |
rv730_golden_registers, |
(const u32)ARRAY_SIZE(rv770_golden_registers)); |
(const u32)ARRAY_SIZE(rv730_golden_registers)); |
radeon_program_register_sequence(rdev, |
rv730_mgcg_init, |
(const u32)ARRAY_SIZE(rv770_mgcg_init)); |
(const u32)ARRAY_SIZE(rv730_mgcg_init)); |
break; |
case CHIP_RV710: |
radeon_program_register_sequence(rdev, |
758,18 → 758,18 |
(const u32)ARRAY_SIZE(r7xx_golden_dyn_gpr_registers)); |
radeon_program_register_sequence(rdev, |
rv710_golden_registers, |
(const u32)ARRAY_SIZE(rv770_golden_registers)); |
(const u32)ARRAY_SIZE(rv710_golden_registers)); |
radeon_program_register_sequence(rdev, |
rv710_mgcg_init, |
(const u32)ARRAY_SIZE(rv770_mgcg_init)); |
(const u32)ARRAY_SIZE(rv710_mgcg_init)); |
break; |
case CHIP_RV740: |
radeon_program_register_sequence(rdev, |
rv740_golden_registers, |
(const u32)ARRAY_SIZE(rv770_golden_registers)); |
(const u32)ARRAY_SIZE(rv740_golden_registers)); |
radeon_program_register_sequence(rdev, |
rv740_mgcg_init, |
(const u32)ARRAY_SIZE(rv770_mgcg_init)); |
(const u32)ARRAY_SIZE(rv740_mgcg_init)); |
break; |
default: |
break; |
801,7 → 801,7 |
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 |
/* 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 */ |
894,7 → 900,6 |
r = radeon_gart_table_vram_pin(rdev); |
if (r) |
return r; |
radeon_gart_restore(rdev); |
/* Setup L2 cache */ |
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | |
ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE | |
1071,7 → 1076,8 |
*/ |
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; |
1115,7 → 1121,35 |
return 0; |
} |
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 |
*/ |
1135,7 → 1169,6 |
u32 hdp_host_path_cntl; |
u32 sq_dyn_gpr_size_simd_ab_0; |
u32 gb_tiling_config = 0; |
u32 cc_rb_backend_disable = 0; |
u32 cc_gc_shader_pipe_config = 0; |
u32 mc_arb_ramcfg; |
u32 db_debug4, tmp; |
1269,21 → 1302,10 |
WREG32(SPI_CONFIG_CNTL, 0); |
} |
cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; |
tmp = R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_rb_backend_disable >> 16); |
if (tmp < rdev->config.rv770.max_backends) { |
rdev->config.rv770.max_backends = tmp; |
} |
cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00; |
tmp = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R7XX_MAX_PIPES_MASK); |
if (tmp < rdev->config.rv770.max_pipes) { |
rdev->config.rv770.max_pipes = tmp; |
} |
tmp = R7XX_MAX_SIMDS - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R7XX_MAX_SIMDS_MASK); |
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: |
1303,6 → 1325,14 |
rdev->config.rv770.tiling_npipes = rdev->config.rv770.max_tile_pipes; |
disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R7XX_MAX_BACKENDS_MASK; |
tmp = 0; |
for (i = 0; i < rdev->config.rv770.max_backends; i++) |
tmp |= (1 << i); |
/* if all the backends are disabled, fix it up here */ |
if ((disabled_rb_mask & tmp) == tmp) { |
for (i = 0; i < rdev->config.rv770.max_backends; i++) |
disabled_rb_mask &= ~(1 << i); |
} |
tmp = (gb_tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; |
tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.rv770.max_backends, |
R7XX_MAX_BACKENDS, disabled_rb_mask); |
1643,80 → 1673,6 |
return 0; |
} |
/** |
* rv770_copy_dma - copy pages using the 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 DMA engine (r7xx). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int rv770_copy_dma(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.dma_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_dw, cur_size_in_dw; |
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_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; |
num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFF); |
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8); |
if (r) { |
DRM_ERROR("radeon: moving bo (%d).\n", r); |
radeon_semaphore_free(rdev, &sem, NULL); |
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); |
} |
for (i = 0; i < num_loops; i++) { |
cur_size_in_dw = size_in_dw; |
if (cur_size_in_dw > 0xFFFF) |
cur_size_in_dw = 0xFFFF; |
size_in_dw -= cur_size_in_dw; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw)); |
radeon_ring_write(ring, dst_offset & 0xfffffffc); |
radeon_ring_write(ring, src_offset & 0xfffffffc); |
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_dw * 4; |
dst_offset += cur_size_in_dw * 4; |
} |
r = radeon_fence_emit(rdev, fence, ring->idx); |
if (r) { |
radeon_ring_unlock_undo(rdev, ring); |
return r; |
} |
radeon_ring_unlock_commit(rdev, ring); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
static int rv770_startup(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring; |
1725,19 → 1681,13 |
/* enable pcie gen2 link */ |
rv770_pcie_gen2_enable(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; |
} |
} |
/* scratch needs to be initialized before MC */ |
r = r600_vram_scratch_init(rdev); |
if (r) |
return r; |
rv770_mc_program(rdev); |
if (rdev->flags & RADEON_IS_AGP) { |
rv770_agp_enable(rdev); |
} else { |
1747,12 → 1697,6 |
} |
rv770_gpu_init(rdev); |
r = r600_blit_init(rdev); |
if (r) { |
r600_blit_fini(rdev); |
rdev->asic->copy.copy = NULL; |
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); |
} |
/* allocate wb buffer */ |
r = radeon_wb_init(rdev); |
1799,15 → 1743,13 |
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, |
0, 0xfffff, RADEON_CP_PACKET2); |
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, |
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); |
if (r) |
return r; |
1841,6 → 1783,11 |
return r; |
} |
r = r600_audio_init(rdev); |
if (r) { |
DRM_ERROR("radeon: audio init failed\n"); |
return r; |
} |
return 0; |
} |
1909,6 → 1856,17 |
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); |
/drivers/video/drm/radeon/rv770_dma.c |
---|
0,0 → 1,97 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "radeon_asic.h" |
#include "rv770d.h" |
/** |
* rv770_copy_dma - copy pages using the 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 DMA engine (r7xx). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int rv770_copy_dma(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.dma_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_dw, cur_size_in_dw; |
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_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; |
num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFF); |
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8); |
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_dw = size_in_dw; |
if (cur_size_in_dw > 0xFFFF) |
cur_size_in_dw = 0xFFFF; |
size_in_dw -= cur_size_in_dw; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw)); |
radeon_ring_write(ring, dst_offset & 0xfffffffc); |
radeon_ring_write(ring, src_offset & 0xfffffffc); |
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_dw * 4; |
dst_offset += cur_size_in_dw * 4; |
} |
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, false); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
/drivers/video/drm/radeon/rv770_dpm.c |
---|
0,0 → 1,2537 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "rv770d.h" |
#include "r600_dpm.h" |
#include "rv770_dpm.h" |
#include "cypress_dpm.h" |
#include "atom.h" |
#include <linux/seq_file.h> |
#define MC_CG_ARB_FREQ_F0 0x0a |
#define MC_CG_ARB_FREQ_F1 0x0b |
#define MC_CG_ARB_FREQ_F2 0x0c |
#define MC_CG_ARB_FREQ_F3 0x0d |
#define MC_CG_SEQ_DRAMCONF_S0 0x05 |
#define MC_CG_SEQ_DRAMCONF_S1 0x06 |
#define PCIE_BUS_CLK 10000 |
#define TCLK (PCIE_BUS_CLK / 10) |
#define SMC_RAM_END 0xC000 |
struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps) |
{ |
struct rv7xx_ps *ps = rps->ps_priv; |
return ps; |
} |
struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
static void rv770_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if (enable) { |
tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); |
tmp |= LC_GEN2_EN_STRAP; |
} else { |
if (!pi->boot_in_gen2) { |
tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; |
tmp &= ~LC_GEN2_EN_STRAP; |
} |
} |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) || |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); |
} |
static void rv770_enable_l0s(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK; |
tmp |= LC_L0S_INACTIVITY(3); |
WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); |
} |
static void rv770_enable_l1(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL); |
tmp &= ~LC_L1_INACTIVITY_MASK; |
tmp |= LC_L1_INACTIVITY(4); |
tmp &= ~LC_PMI_TO_L1_DIS; |
tmp &= ~LC_ASPM_TO_L1_DIS; |
WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); |
} |
static void rv770_enable_pll_sleep_in_l1(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK; |
tmp |= LC_L1_INACTIVITY(8); |
WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); |
/* NOTE, this is a PCIE indirect reg, not PCIE PORT */ |
tmp = RREG32_PCIE(PCIE_P_CNTL); |
tmp |= P_PLL_PWRDN_IN_L1L23; |
tmp &= ~P_PLL_BUF_PDNB; |
tmp &= ~P_PLL_PDNB; |
tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF; |
WREG32_PCIE(PCIE_P_CNTL, tmp); |
} |
static void rv770_gfx_clock_gating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); |
else { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); |
RREG32(GB_TILING_CONFIG); |
} |
} |
static void rv770_mg_clock_gating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (enable) { |
u32 mgcg_cgtt_local0; |
if (rdev->family == CHIP_RV770) |
mgcg_cgtt_local0 = RV770_MGCGTTLOCAL0_DFLT; |
else |
mgcg_cgtt_local0 = RV7XX_MGCGTTLOCAL0_DFLT; |
WREG32(CG_CGTT_LOCAL_0, mgcg_cgtt_local0); |
WREG32(CG_CGTT_LOCAL_1, (RV770_MGCGTTLOCAL1_DFLT & 0xFFFFCFFF)); |
if (pi->mgcgtssm) |
WREG32(CGTS_SM_CTRL_REG, RV770_MGCGCGTSSMCTRL_DFLT); |
} else { |
WREG32(CG_CGTT_LOCAL_0, 0xFFFFFFFF); |
WREG32(CG_CGTT_LOCAL_1, 0xFFFFCFFF); |
} |
} |
void rv770_restore_cgcg(struct radeon_device *rdev) |
{ |
bool dpm_en = false, cg_en = false; |
if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN) |
dpm_en = true; |
if (RREG32(SCLK_PWRMGT_CNTL) & DYN_GFX_CLK_OFF_EN) |
cg_en = true; |
if (dpm_en && !cg_en) |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); |
} |
static void rv770_start_dpm(struct radeon_device *rdev) |
{ |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF); |
WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF); |
WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN); |
} |
void rv770_stop_dpm(struct radeon_device *rdev) |
{ |
PPSMC_Result result; |
result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled); |
if (result != PPSMC_Result_OK) |
DRM_ERROR("Could not force DPM to low.\n"); |
WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF); |
WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF); |
} |
bool rv770_dpm_enabled(struct radeon_device *rdev) |
{ |
if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN) |
return true; |
else |
return false; |
} |
void rv770_enable_thermal_protection(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); |
else |
WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); |
} |
void rv770_enable_acpi_pm(struct radeon_device *rdev) |
{ |
WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN); |
} |
u8 rv770_get_seq_value(struct radeon_device *rdev, |
struct rv7xx_pl *pl) |
{ |
return (pl->flags & ATOM_PPLIB_R600_FLAGS_LOWPOWER) ? |
MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1; |
} |
int rv770_read_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 *value) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
return rv770_read_smc_sram_dword(rdev, |
pi->soft_regs_start + reg_offset, |
value, pi->sram_end); |
} |
int rv770_write_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 value) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
return rv770_write_smc_sram_dword(rdev, |
pi->soft_regs_start + reg_offset, |
value, pi->sram_end); |
} |
int rv770_populate_smc_t(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
RV770_SMC_SWSTATE *smc_state) |
{ |
struct rv7xx_ps *state = rv770_get_ps(radeon_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int i; |
int a_n; |
int a_d; |
u8 l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE]; |
u8 r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE]; |
u32 a_t; |
l[0] = 0; |
r[2] = 100; |
a_n = (int)state->medium.sclk * pi->lmp + |
(int)state->low.sclk * (R600_AH_DFLT - pi->rlp); |
a_d = (int)state->low.sclk * (100 - (int)pi->rlp) + |
(int)state->medium.sclk * pi->lmp; |
l[1] = (u8)(pi->lmp - (int)pi->lmp * a_n / a_d); |
r[0] = (u8)(pi->rlp + (100 - (int)pi->rlp) * a_n / a_d); |
a_n = (int)state->high.sclk * pi->lhp + (int)state->medium.sclk * |
(R600_AH_DFLT - pi->rmp); |
a_d = (int)state->medium.sclk * (100 - (int)pi->rmp) + |
(int)state->high.sclk * pi->lhp; |
l[2] = (u8)(pi->lhp - (int)pi->lhp * a_n / a_d); |
r[1] = (u8)(pi->rmp + (100 - (int)pi->rmp) * a_n / a_d); |
for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++) { |
a_t = CG_R(r[i] * pi->bsp / 200) | CG_L(l[i] * pi->bsp / 200); |
smc_state->levels[i].aT = cpu_to_be32(a_t); |
} |
a_t = CG_R(r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200) | |
CG_L(l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200); |
smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].aT = |
cpu_to_be32(a_t); |
return 0; |
} |
int rv770_populate_smc_sp(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
RV770_SMC_SWSTATE *smc_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int i; |
for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++) |
smc_state->levels[i].bSP = cpu_to_be32(pi->dsp); |
smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].bSP = |
cpu_to_be32(pi->psp); |
return 0; |
} |
static void rv770_calculate_fractional_mpll_feedback_divider(u32 memory_clock, |
u32 reference_clock, |
bool gddr5, |
struct atom_clock_dividers *dividers, |
u32 *clkf, |
u32 *clkfrac) |
{ |
u32 post_divider, reference_divider, feedback_divider8; |
u32 fyclk; |
if (gddr5) |
fyclk = (memory_clock * 8) / 2; |
else |
fyclk = (memory_clock * 4) / 2; |
post_divider = dividers->post_div; |
reference_divider = dividers->ref_div; |
feedback_divider8 = |
(8 * fyclk * reference_divider * post_divider) / reference_clock; |
*clkf = feedback_divider8 / 8; |
*clkfrac = feedback_divider8 % 8; |
} |
static int rv770_encode_yclk_post_div(u32 postdiv, u32 *encoded_postdiv) |
{ |
int ret = 0; |
switch (postdiv) { |
case 1: |
*encoded_postdiv = 0; |
break; |
case 2: |
*encoded_postdiv = 1; |
break; |
case 4: |
*encoded_postdiv = 2; |
break; |
case 8: |
*encoded_postdiv = 3; |
break; |
case 16: |
*encoded_postdiv = 4; |
break; |
default: |
ret = -EINVAL; |
break; |
} |
return ret; |
} |
u32 rv770_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf) |
{ |
if (clkf <= 0x10) |
return 0x4B; |
if (clkf <= 0x19) |
return 0x5B; |
if (clkf <= 0x21) |
return 0x2B; |
if (clkf <= 0x27) |
return 0x6C; |
if (clkf <= 0x31) |
return 0x9D; |
return 0xC6; |
} |
static int rv770_populate_mclk_value(struct radeon_device *rdev, |
u32 engine_clock, u32 memory_clock, |
RV7XX_SMC_MCLK_VALUE *mclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u8 encoded_reference_dividers[] = { 0, 16, 17, 20, 21 }; |
u32 mpll_ad_func_cntl = |
pi->clk_regs.rv770.mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2 = |
pi->clk_regs.rv770.mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl = |
pi->clk_regs.rv770.mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2 = |
pi->clk_regs.rv770.mpll_dq_func_cntl_2; |
u32 mclk_pwrmgt_cntl = |
pi->clk_regs.rv770.mclk_pwrmgt_cntl; |
u32 dll_cntl = pi->clk_regs.rv770.dll_cntl; |
struct atom_clock_dividers dividers; |
u32 reference_clock = rdev->clock.mpll.reference_freq; |
u32 clkf, clkfrac; |
u32 postdiv_yclk; |
u32 ibias; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, |
memory_clock, false, ÷rs); |
if (ret) |
return ret; |
if ((dividers.ref_div < 1) || (dividers.ref_div > 5)) |
return -EINVAL; |
rv770_calculate_fractional_mpll_feedback_divider(memory_clock, reference_clock, |
pi->mem_gddr5, |
÷rs, &clkf, &clkfrac); |
ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk); |
if (ret) |
return ret; |
ibias = rv770_map_clkf_to_ibias(rdev, clkf); |
mpll_ad_func_cntl &= ~(CLKR_MASK | |
YCLK_POST_DIV_MASK | |
CLKF_MASK | |
CLKFRAC_MASK | |
IBIAS_MASK); |
mpll_ad_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]); |
mpll_ad_func_cntl |= YCLK_POST_DIV(postdiv_yclk); |
mpll_ad_func_cntl |= CLKF(clkf); |
mpll_ad_func_cntl |= CLKFRAC(clkfrac); |
mpll_ad_func_cntl |= IBIAS(ibias); |
if (dividers.vco_mode) |
mpll_ad_func_cntl_2 |= VCO_MODE; |
else |
mpll_ad_func_cntl_2 &= ~VCO_MODE; |
if (pi->mem_gddr5) { |
rv770_calculate_fractional_mpll_feedback_divider(memory_clock, |
reference_clock, |
pi->mem_gddr5, |
÷rs, &clkf, &clkfrac); |
ibias = rv770_map_clkf_to_ibias(rdev, clkf); |
ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk); |
if (ret) |
return ret; |
mpll_dq_func_cntl &= ~(CLKR_MASK | |
YCLK_POST_DIV_MASK | |
CLKF_MASK | |
CLKFRAC_MASK | |
IBIAS_MASK); |
mpll_dq_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]); |
mpll_dq_func_cntl |= YCLK_POST_DIV(postdiv_yclk); |
mpll_dq_func_cntl |= CLKF(clkf); |
mpll_dq_func_cntl |= CLKFRAC(clkfrac); |
mpll_dq_func_cntl |= IBIAS(ibias); |
if (dividers.vco_mode) |
mpll_dq_func_cntl_2 |= VCO_MODE; |
else |
mpll_dq_func_cntl_2 &= ~VCO_MODE; |
} |
mclk->mclk770.mclk_value = cpu_to_be32(memory_clock); |
mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); |
mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); |
mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); |
mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); |
mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl); |
return 0; |
} |
static int rv770_populate_sclk_value(struct radeon_device *rdev, |
u32 engine_clock, |
RV770_SMC_SCLK_VALUE *sclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct atom_clock_dividers dividers; |
u32 spll_func_cntl = |
pi->clk_regs.rv770.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = |
pi->clk_regs.rv770.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = |
pi->clk_regs.rv770.cg_spll_func_cntl_3; |
u32 cg_spll_spread_spectrum = |
pi->clk_regs.rv770.cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2 = |
pi->clk_regs.rv770.cg_spll_spread_spectrum_2; |
u64 tmp; |
u32 reference_clock = rdev->clock.spll.reference_freq; |
u32 reference_divider, post_divider; |
u32 fbdiv; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
engine_clock, false, ÷rs); |
if (ret) |
return ret; |
reference_divider = 1 + dividers.ref_div; |
if (dividers.enable_post_div) |
post_divider = (0x0f & (dividers.post_div >> 4)) + (0x0f & dividers.post_div) + 2; |
else |
post_divider = 1; |
tmp = (u64) engine_clock * reference_divider * post_divider * 16384; |
do_div(tmp, reference_clock); |
fbdiv = (u32) tmp; |
if (dividers.enable_post_div) |
spll_func_cntl |= SPLL_DIVEN; |
else |
spll_func_cntl &= ~SPLL_DIVEN; |
spll_func_cntl &= ~(SPLL_HILEN_MASK | SPLL_LOLEN_MASK | SPLL_REF_DIV_MASK); |
spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div); |
spll_func_cntl |= SPLL_HILEN((dividers.post_div >> 4) & 0xf); |
spll_func_cntl |= SPLL_LOLEN(dividers.post_div & 0xf); |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(2); |
spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK; |
spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv); |
spll_func_cntl_3 |= SPLL_DITHEN; |
if (pi->sclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = engine_clock * post_divider; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, vco_freq)) { |
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); |
u32 clk_v = ss.percentage * fbdiv / (clk_s * 10000); |
cg_spll_spread_spectrum &= ~CLKS_MASK; |
cg_spll_spread_spectrum |= CLKS(clk_s); |
cg_spll_spread_spectrum |= SSEN; |
cg_spll_spread_spectrum_2 &= ~CLKV_MASK; |
cg_spll_spread_spectrum_2 |= CLKV(clk_v); |
} |
} |
sclk->sclk_value = cpu_to_be32(engine_clock); |
sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); |
sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); |
sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); |
sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum); |
sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2); |
return 0; |
} |
int rv770_populate_vddc_value(struct radeon_device *rdev, u16 vddc, |
RV770_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int i; |
if (!pi->voltage_control) { |
voltage->index = 0; |
voltage->value = 0; |
return 0; |
} |
for (i = 0; i < pi->valid_vddc_entries; i++) { |
if (vddc <= pi->vddc_table[i].vddc) { |
voltage->index = pi->vddc_table[i].vddc_index; |
voltage->value = cpu_to_be16(vddc); |
break; |
} |
} |
if (i == pi->valid_vddc_entries) |
return -EINVAL; |
return 0; |
} |
int rv770_populate_mvdd_value(struct radeon_device *rdev, u32 mclk, |
RV770_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (!pi->mvdd_control) { |
voltage->index = MVDD_HIGH_INDEX; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
return 0; |
} |
if (mclk <= pi->mvdd_split_frequency) { |
voltage->index = MVDD_LOW_INDEX; |
voltage->value = cpu_to_be16(MVDD_LOW_VALUE); |
} else { |
voltage->index = MVDD_HIGH_INDEX; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
} |
return 0; |
} |
static int rv770_convert_power_level_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
RV770_SMC_HW_PERFORMANCE_LEVEL *level, |
u8 watermark_level) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int ret; |
level->gen2PCIE = pi->pcie_gen2 ? |
((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0; |
level->gen2XSP = (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0; |
level->backbias = (pl->flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? 1 : 0; |
level->displayWatermark = watermark_level; |
if (rdev->family == CHIP_RV740) |
ret = rv740_populate_sclk_value(rdev, pl->sclk, |
&level->sclk); |
else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
ret = rv730_populate_sclk_value(rdev, pl->sclk, |
&level->sclk); |
else |
ret = rv770_populate_sclk_value(rdev, pl->sclk, |
&level->sclk); |
if (ret) |
return ret; |
if (rdev->family == CHIP_RV740) { |
if (pi->mem_gddr5) { |
if (pl->mclk <= pi->mclk_strobe_mode_threshold) |
level->strobeMode = |
rv740_get_mclk_frequency_ratio(pl->mclk) | 0x10; |
else |
level->strobeMode = 0; |
if (pl->mclk > pi->mclk_edc_enable_threshold) |
level->mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG; |
else |
level->mcFlags = 0; |
} |
ret = rv740_populate_mclk_value(rdev, pl->sclk, |
pl->mclk, &level->mclk); |
} else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
ret = rv730_populate_mclk_value(rdev, pl->sclk, |
pl->mclk, &level->mclk); |
else |
ret = rv770_populate_mclk_value(rdev, pl->sclk, |
pl->mclk, &level->mclk); |
if (ret) |
return ret; |
ret = rv770_populate_vddc_value(rdev, pl->vddc, |
&level->vddc); |
if (ret) |
return ret; |
ret = rv770_populate_mvdd_value(rdev, pl->mclk, &level->mvdd); |
return ret; |
} |
static int rv770_convert_power_state_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
RV770_SMC_SWSTATE *smc_state) |
{ |
struct rv7xx_ps *state = rv770_get_ps(radeon_state); |
int ret; |
if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC)) |
smc_state->flags |= PPSMC_SWSTATE_FLAG_DC; |
ret = rv770_convert_power_level_to_smc(rdev, |
&state->low, |
&smc_state->levels[0], |
PPSMC_DISPLAY_WATERMARK_LOW); |
if (ret) |
return ret; |
ret = rv770_convert_power_level_to_smc(rdev, |
&state->medium, |
&smc_state->levels[1], |
PPSMC_DISPLAY_WATERMARK_LOW); |
if (ret) |
return ret; |
ret = rv770_convert_power_level_to_smc(rdev, |
&state->high, |
&smc_state->levels[2], |
PPSMC_DISPLAY_WATERMARK_HIGH); |
if (ret) |
return ret; |
smc_state->levels[0].arbValue = MC_CG_ARB_FREQ_F1; |
smc_state->levels[1].arbValue = MC_CG_ARB_FREQ_F2; |
smc_state->levels[2].arbValue = MC_CG_ARB_FREQ_F3; |
smc_state->levels[0].seqValue = rv770_get_seq_value(rdev, |
&state->low); |
smc_state->levels[1].seqValue = rv770_get_seq_value(rdev, |
&state->medium); |
smc_state->levels[2].seqValue = rv770_get_seq_value(rdev, |
&state->high); |
rv770_populate_smc_sp(rdev, radeon_state, smc_state); |
return rv770_populate_smc_t(rdev, radeon_state, smc_state); |
} |
u32 rv770_calculate_memory_refresh_rate(struct radeon_device *rdev, |
u32 engine_clock) |
{ |
u32 dram_rows; |
u32 dram_refresh_rate; |
u32 mc_arb_rfsh_rate; |
u32 tmp; |
tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; |
dram_rows = 1 << (tmp + 10); |
tmp = RREG32(MC_SEQ_MISC0) & 3; |
dram_refresh_rate = 1 << (tmp + 3); |
mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64; |
return mc_arb_rfsh_rate; |
} |
static void rv770_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct rv7xx_ps *state = rv770_get_ps(radeon_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 sqm_ratio; |
u32 arb_refresh_rate; |
u32 high_clock; |
if (state->high.sclk < (state->low.sclk * 0xFF / 0x40)) |
high_clock = state->high.sclk; |
else |
high_clock = (state->low.sclk * 0xFF / 0x40); |
radeon_atom_set_engine_dram_timings(rdev, high_clock, |
state->high.mclk); |
sqm_ratio = |
STATE0(64 * high_clock / pi->boot_sclk) | |
STATE1(64 * high_clock / state->low.sclk) | |
STATE2(64 * high_clock / state->medium.sclk) | |
STATE3(64 * high_clock / state->high.sclk); |
WREG32(MC_ARB_SQM_RATIO, sqm_ratio); |
arb_refresh_rate = |
POWERMODE0(rv770_calculate_memory_refresh_rate(rdev, pi->boot_sclk)) | |
POWERMODE1(rv770_calculate_memory_refresh_rate(rdev, state->low.sclk)) | |
POWERMODE2(rv770_calculate_memory_refresh_rate(rdev, state->medium.sclk)) | |
POWERMODE3(rv770_calculate_memory_refresh_rate(rdev, state->high.sclk)); |
WREG32(MC_ARB_RFSH_RATE, arb_refresh_rate); |
} |
void rv770_enable_backbias(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN, ~BACKBIAS_PAD_EN); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN)); |
} |
static void rv770_enable_spread_spectrum(struct radeon_device *rdev, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (enable) { |
if (pi->sclk_ss) |
WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); |
if (pi->mclk_ss) { |
if (rdev->family == CHIP_RV740) |
rv740_enable_mclk_spread_spectrum(rdev, true); |
} |
} else { |
WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN); |
WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); |
WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN); |
if (rdev->family == CHIP_RV740) |
rv740_enable_mclk_spread_spectrum(rdev, false); |
} |
} |
static void rv770_program_mpll_timing_parameters(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if ((rdev->family == CHIP_RV770) && !pi->mem_gddr5) { |
WREG32(MPLL_TIME, |
(MPLL_LOCK_TIME(R600_MPLLLOCKTIME_DFLT * pi->ref_div) | |
MPLL_RESET_TIME(R600_MPLLRESETTIME_DFLT))); |
} |
} |
void rv770_setup_bsp(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 xclk = radeon_get_xclk(rdev); |
r600_calculate_u_and_p(pi->asi, |
xclk, |
16, |
&pi->bsp, |
&pi->bsu); |
r600_calculate_u_and_p(pi->pasi, |
xclk, |
16, |
&pi->pbsp, |
&pi->pbsu); |
pi->dsp = BSP(pi->bsp) | BSU(pi->bsu); |
pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu); |
WREG32(CG_BSP, pi->dsp); |
} |
void rv770_program_git(struct radeon_device *rdev) |
{ |
WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK); |
} |
void rv770_program_tp(struct radeon_device *rdev) |
{ |
int i; |
enum r600_td td = R600_TD_DFLT; |
for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) |
WREG32(CG_FFCT_0 + (i * 4), (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i]))); |
if (td == R600_TD_AUTO) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL); |
else |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL); |
if (td == R600_TD_UP) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE); |
if (td == R600_TD_DOWN) |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE); |
} |
void rv770_program_tpp(struct radeon_device *rdev) |
{ |
WREG32(CG_TPC, R600_TPC_DFLT); |
} |
void rv770_program_sstp(struct radeon_device *rdev) |
{ |
WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT))); |
} |
void rv770_program_engine_speed_parameters(struct radeon_device *rdev) |
{ |
WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC); |
} |
static void rv770_enable_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); |
tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); |
tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | |
DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE)); |
WREG32(CG_DISPLAY_GAP_CNTL, tmp); |
} |
void rv770_program_vc(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
WREG32(CG_FTV, pi->vrc); |
} |
void rv770_clear_vc(struct radeon_device *rdev) |
{ |
WREG32(CG_FTV, 0); |
} |
int rv770_upload_firmware(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int ret; |
rv770_reset_smc(rdev); |
rv770_stop_smc_clock(rdev); |
ret = rv770_load_smc_ucode(rdev, pi->sram_end); |
if (ret) |
return ret; |
return 0; |
} |
static int rv770_populate_smc_acpi_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 mpll_ad_func_cntl = |
pi->clk_regs.rv770.mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2 = |
pi->clk_regs.rv770.mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl = |
pi->clk_regs.rv770.mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2 = |
pi->clk_regs.rv770.mpll_dq_func_cntl_2; |
u32 spll_func_cntl = |
pi->clk_regs.rv770.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = |
pi->clk_regs.rv770.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = |
pi->clk_regs.rv770.cg_spll_func_cntl_3; |
u32 mclk_pwrmgt_cntl; |
u32 dll_cntl; |
table->ACPIState = table->initialState; |
table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC; |
if (pi->acpi_vddc) { |
rv770_populate_vddc_value(rdev, pi->acpi_vddc, |
&table->ACPIState.levels[0].vddc); |
if (pi->pcie_gen2) { |
if (pi->acpi_pcie_gen2) |
table->ACPIState.levels[0].gen2PCIE = 1; |
else |
table->ACPIState.levels[0].gen2PCIE = 0; |
} else |
table->ACPIState.levels[0].gen2PCIE = 0; |
if (pi->acpi_pcie_gen2) |
table->ACPIState.levels[0].gen2XSP = 1; |
else |
table->ACPIState.levels[0].gen2XSP = 0; |
} else { |
rv770_populate_vddc_value(rdev, pi->min_vddc_in_table, |
&table->ACPIState.levels[0].vddc); |
table->ACPIState.levels[0].gen2PCIE = 0; |
} |
mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN; |
mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN; |
mclk_pwrmgt_cntl = (MRDCKA0_RESET | |
MRDCKA1_RESET | |
MRDCKB0_RESET | |
MRDCKB1_RESET | |
MRDCKC0_RESET | |
MRDCKC1_RESET | |
MRDCKD0_RESET | |
MRDCKD1_RESET); |
dll_cntl = 0xff000000; |
spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN; |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(4); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); |
table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl); |
table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0; |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); |
table->ACPIState.levels[0].sclk.sclk_value = 0; |
rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd); |
table->ACPIState.levels[1] = table->ACPIState.levels[0]; |
table->ACPIState.levels[2] = table->ACPIState.levels[0]; |
return 0; |
} |
int rv770_populate_initial_mvdd_value(struct radeon_device *rdev, |
RV770_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if ((pi->s0_vid_lower_smio_cntl & pi->mvdd_mask_low) == |
(pi->mvdd_low_smio[MVDD_LOW_INDEX] & pi->mvdd_mask_low) ) { |
voltage->index = MVDD_LOW_INDEX; |
voltage->value = cpu_to_be16(MVDD_LOW_VALUE); |
} else { |
voltage->index = MVDD_HIGH_INDEX; |
voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); |
} |
return 0; |
} |
static int rv770_populate_smc_initial_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_ps *initial_state = rv770_get_ps(radeon_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 a_t; |
table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl); |
table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = |
cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl_2); |
table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl); |
table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = |
cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl_2); |
table->initialState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.mclk_pwrmgt_cntl); |
table->initialState.levels[0].mclk.mclk770.vDLL_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.dll_cntl); |
table->initialState.levels[0].mclk.mclk770.vMPLL_SS = |
cpu_to_be32(pi->clk_regs.rv770.mpll_ss1); |
table->initialState.levels[0].mclk.mclk770.vMPLL_SS2 = |
cpu_to_be32(pi->clk_regs.rv770.mpll_ss2); |
table->initialState.levels[0].mclk.mclk770.mclk_value = |
cpu_to_be32(initial_state->low.mclk); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_2); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_3); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 = |
cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum_2); |
table->initialState.levels[0].sclk.sclk_value = |
cpu_to_be32(initial_state->low.sclk); |
table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0; |
table->initialState.levels[0].seqValue = |
rv770_get_seq_value(rdev, &initial_state->low); |
rv770_populate_vddc_value(rdev, |
initial_state->low.vddc, |
&table->initialState.levels[0].vddc); |
rv770_populate_initial_mvdd_value(rdev, |
&table->initialState.levels[0].mvdd); |
a_t = CG_R(0xffff) | CG_L(0); |
table->initialState.levels[0].aT = cpu_to_be32(a_t); |
table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp); |
if (pi->boot_in_gen2) |
table->initialState.levels[0].gen2PCIE = 1; |
else |
table->initialState.levels[0].gen2PCIE = 0; |
if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) |
table->initialState.levels[0].gen2XSP = 1; |
else |
table->initialState.levels[0].gen2XSP = 0; |
if (rdev->family == CHIP_RV740) { |
if (pi->mem_gddr5) { |
if (initial_state->low.mclk <= pi->mclk_strobe_mode_threshold) |
table->initialState.levels[0].strobeMode = |
rv740_get_mclk_frequency_ratio(initial_state->low.mclk) | 0x10; |
else |
table->initialState.levels[0].strobeMode = 0; |
if (initial_state->low.mclk >= pi->mclk_edc_enable_threshold) |
table->initialState.levels[0].mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG; |
else |
table->initialState.levels[0].mcFlags = 0; |
} |
} |
table->initialState.levels[1] = table->initialState.levels[0]; |
table->initialState.levels[2] = table->initialState.levels[0]; |
table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC; |
return 0; |
} |
static int rv770_populate_smc_vddc_table(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int i; |
for (i = 0; i < pi->valid_vddc_entries; i++) { |
table->highSMIO[pi->vddc_table[i].vddc_index] = |
pi->vddc_table[i].high_smio; |
table->lowSMIO[pi->vddc_table[i].vddc_index] = |
cpu_to_be32(pi->vddc_table[i].low_smio); |
} |
table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDC] = 0; |
table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDC] = |
cpu_to_be32(pi->vddc_mask_low); |
for (i = 0; |
((i < pi->valid_vddc_entries) && |
(pi->max_vddc_in_table > |
pi->vddc_table[i].vddc)); |
i++); |
table->maxVDDCIndexInPPTable = |
pi->vddc_table[i].vddc_index; |
return 0; |
} |
static int rv770_populate_smc_mvdd_table(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (pi->mvdd_control) { |
table->lowSMIO[MVDD_HIGH_INDEX] |= |
cpu_to_be32(pi->mvdd_low_smio[MVDD_HIGH_INDEX]); |
table->lowSMIO[MVDD_LOW_INDEX] |= |
cpu_to_be32(pi->mvdd_low_smio[MVDD_LOW_INDEX]); |
table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_MVDD] = 0; |
table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_MVDD] = |
cpu_to_be32(pi->mvdd_mask_low); |
} |
return 0; |
} |
static int rv770_init_smc_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state); |
RV770_SMC_STATETABLE *table = &pi->smc_statetable; |
int ret; |
memset(table, 0, sizeof(RV770_SMC_STATETABLE)); |
pi->boot_sclk = boot_state->low.sclk; |
rv770_populate_smc_vddc_table(rdev, table); |
rv770_populate_smc_mvdd_table(rdev, table); |
switch (rdev->pm.int_thermal_type) { |
case THERMAL_TYPE_RV770: |
case THERMAL_TYPE_ADT7473_WITH_INTERNAL: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL; |
break; |
case THERMAL_TYPE_NONE: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE; |
break; |
case THERMAL_TYPE_EXTERNAL_GPIO: |
default: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL; |
break; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) { |
table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT) |
table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT) |
table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; |
if (pi->mem_gddr5) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5; |
if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
ret = rv730_populate_smc_initial_state(rdev, radeon_boot_state, table); |
else |
ret = rv770_populate_smc_initial_state(rdev, radeon_boot_state, table); |
if (ret) |
return ret; |
if (rdev->family == CHIP_RV740) |
ret = rv740_populate_smc_acpi_state(rdev, table); |
else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
ret = rv730_populate_smc_acpi_state(rdev, table); |
else |
ret = rv770_populate_smc_acpi_state(rdev, table); |
if (ret) |
return ret; |
table->driverState = table->initialState; |
return rv770_copy_bytes_to_smc(rdev, |
pi->state_table_start, |
(const u8 *)table, |
sizeof(RV770_SMC_STATETABLE), |
pi->sram_end); |
} |
static int rv770_construct_vddc_table(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u16 min, max, step; |
u32 steps = 0; |
u8 vddc_index = 0; |
u32 i; |
radeon_atom_get_min_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &min); |
radeon_atom_get_max_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &max); |
radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &step); |
steps = (max - min) / step + 1; |
if (steps > MAX_NO_VREG_STEPS) |
return -EINVAL; |
for (i = 0; i < steps; i++) { |
u32 gpio_pins, gpio_mask; |
pi->vddc_table[i].vddc = (u16)(min + i * step); |
radeon_atom_get_voltage_gpio_settings(rdev, |
pi->vddc_table[i].vddc, |
SET_VOLTAGE_TYPE_ASIC_VDDC, |
&gpio_pins, &gpio_mask); |
pi->vddc_table[i].low_smio = gpio_pins & gpio_mask; |
pi->vddc_table[i].high_smio = 0; |
pi->vddc_mask_low = gpio_mask; |
if (i > 0) { |
if ((pi->vddc_table[i].low_smio != |
pi->vddc_table[i - 1].low_smio ) || |
(pi->vddc_table[i].high_smio != |
pi->vddc_table[i - 1].high_smio)) |
vddc_index++; |
} |
pi->vddc_table[i].vddc_index = vddc_index; |
} |
pi->valid_vddc_entries = (u8)steps; |
return 0; |
} |
static u32 rv770_get_mclk_split_point(struct atom_memory_info *memory_info) |
{ |
if (memory_info->mem_type == MEM_TYPE_GDDR3) |
return 30000; |
return 0; |
} |
static int rv770_get_mvdd_pin_configuration(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 gpio_pins, gpio_mask; |
radeon_atom_get_voltage_gpio_settings(rdev, |
MVDD_HIGH_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC, |
&gpio_pins, &gpio_mask); |
pi->mvdd_mask_low = gpio_mask; |
pi->mvdd_low_smio[MVDD_HIGH_INDEX] = |
gpio_pins & gpio_mask; |
radeon_atom_get_voltage_gpio_settings(rdev, |
MVDD_LOW_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC, |
&gpio_pins, &gpio_mask); |
pi->mvdd_low_smio[MVDD_LOW_INDEX] = |
gpio_pins & gpio_mask; |
return 0; |
} |
u8 rv770_get_memory_module_index(struct radeon_device *rdev) |
{ |
return (u8) ((RREG32(BIOS_SCRATCH_4) >> 16) & 0xff); |
} |
static int rv770_get_mvdd_configuration(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u8 memory_module_index; |
struct atom_memory_info memory_info; |
memory_module_index = rv770_get_memory_module_index(rdev); |
if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info)) { |
pi->mvdd_control = false; |
return 0; |
} |
pi->mvdd_split_frequency = |
rv770_get_mclk_split_point(&memory_info); |
if (pi->mvdd_split_frequency == 0) { |
pi->mvdd_control = false; |
return 0; |
} |
return rv770_get_mvdd_pin_configuration(rdev); |
} |
void rv770_enable_voltage_control(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN); |
} |
static void rv770_program_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); |
tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); |
if (rdev->pm.dpm.new_active_crtcs & 1) { |
tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); |
tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); |
} else if (rdev->pm.dpm.new_active_crtcs & 2) { |
tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); |
tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); |
} else { |
tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); |
tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); |
} |
WREG32(CG_DISPLAY_GAP_CNTL, tmp); |
} |
static void rv770_enable_dynamic_pcie_gen2(struct radeon_device *rdev, |
bool enable) |
{ |
rv770_enable_bif_dynamic_pcie_gen2(rdev, enable); |
if (enable) |
WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE); |
} |
static void r7xx_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
if ((rdev->family == CHIP_RV730) || |
(rdev->family == CHIP_RV710) || |
(rdev->family == CHIP_RV740)) |
rv730_program_memory_timing_parameters(rdev, radeon_new_state); |
else |
rv770_program_memory_timing_parameters(rdev, radeon_new_state); |
} |
static int rv770_upload_sw_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u16 address = pi->state_table_start + |
offsetof(RV770_SMC_STATETABLE, driverState); |
RV770_SMC_SWSTATE state = { 0 }; |
int ret; |
ret = rv770_convert_power_state_to_smc(rdev, radeon_new_state, &state); |
if (ret) |
return ret; |
return rv770_copy_bytes_to_smc(rdev, address, (const u8 *)&state, |
sizeof(RV770_SMC_SWSTATE), |
pi->sram_end); |
} |
int rv770_halt_smc(struct radeon_device *rdev) |
{ |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Halt) != PPSMC_Result_OK) |
return -EINVAL; |
if (rv770_wait_for_smc_inactive(rdev) != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
int rv770_resume_smc(struct radeon_device *rdev) |
{ |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Resume) != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
int rv770_set_sw_state(struct radeon_device *rdev) |
{ |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
int rv770_set_boot_state(struct radeon_device *rdev) |
{ |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv7xx_ps *new_state = rv770_get_ps(new_ps); |
struct rv7xx_ps *current_state = rv770_get_ps(old_ps); |
if ((new_ps->vclk == old_ps->vclk) && |
(new_ps->dclk == old_ps->dclk)) |
return; |
if (new_state->high.sclk >= current_state->high.sclk) |
return; |
radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); |
} |
void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps) |
{ |
struct rv7xx_ps *new_state = rv770_get_ps(new_ps); |
struct rv7xx_ps *current_state = rv770_get_ps(old_ps); |
if ((new_ps->vclk == old_ps->vclk) && |
(new_ps->dclk == old_ps->dclk)) |
return; |
if (new_state->high.sclk < current_state->high.sclk) |
return; |
radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); |
} |
int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev) |
{ |
if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_NoForcedLevel)) != PPSMC_Result_OK) |
return -EINVAL; |
if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled)) != PPSMC_Result_OK) |
return -EINVAL; |
return 0; |
} |
int rv770_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
PPSMC_Msg msg; |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ZeroLevelsDisabled) != PPSMC_Result_OK) |
return -EINVAL; |
msg = PPSMC_MSG_ForceHigh; |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK) |
return -EINVAL; |
msg = (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled); |
} else { |
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK) |
return -EINVAL; |
msg = (PPSMC_Msg)(PPSMC_MSG_ZeroLevelsDisabled); |
} |
if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK) |
return -EINVAL; |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
void r7xx_start_smc(struct radeon_device *rdev) |
{ |
rv770_start_smc(rdev); |
rv770_start_smc_clock(rdev); |
} |
void r7xx_stop_smc(struct radeon_device *rdev) |
{ |
rv770_reset_smc(rdev); |
rv770_stop_smc_clock(rdev); |
} |
static void rv770_read_clock_registers(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
pi->clk_regs.rv770.cg_spll_func_cntl = |
RREG32(CG_SPLL_FUNC_CNTL); |
pi->clk_regs.rv770.cg_spll_func_cntl_2 = |
RREG32(CG_SPLL_FUNC_CNTL_2); |
pi->clk_regs.rv770.cg_spll_func_cntl_3 = |
RREG32(CG_SPLL_FUNC_CNTL_3); |
pi->clk_regs.rv770.cg_spll_spread_spectrum = |
RREG32(CG_SPLL_SPREAD_SPECTRUM); |
pi->clk_regs.rv770.cg_spll_spread_spectrum_2 = |
RREG32(CG_SPLL_SPREAD_SPECTRUM_2); |
pi->clk_regs.rv770.mpll_ad_func_cntl = |
RREG32(MPLL_AD_FUNC_CNTL); |
pi->clk_regs.rv770.mpll_ad_func_cntl_2 = |
RREG32(MPLL_AD_FUNC_CNTL_2); |
pi->clk_regs.rv770.mpll_dq_func_cntl = |
RREG32(MPLL_DQ_FUNC_CNTL); |
pi->clk_regs.rv770.mpll_dq_func_cntl_2 = |
RREG32(MPLL_DQ_FUNC_CNTL_2); |
pi->clk_regs.rv770.mclk_pwrmgt_cntl = |
RREG32(MCLK_PWRMGT_CNTL); |
pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL); |
} |
static void r7xx_read_clock_registers(struct radeon_device *rdev) |
{ |
if (rdev->family == CHIP_RV740) |
rv740_read_clock_registers(rdev); |
else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
rv730_read_clock_registers(rdev); |
else |
rv770_read_clock_registers(rdev); |
} |
void rv770_read_voltage_smio_registers(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
pi->s0_vid_lower_smio_cntl = |
RREG32(S0_VID_LOWER_SMIO_CNTL); |
} |
void rv770_reset_smio_status(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 sw_smio_index, vid_smio_cntl; |
sw_smio_index = |
(RREG32(GENERAL_PWRMGT) & SW_SMIO_INDEX_MASK) >> SW_SMIO_INDEX_SHIFT; |
switch (sw_smio_index) { |
case 3: |
vid_smio_cntl = RREG32(S3_VID_LOWER_SMIO_CNTL); |
break; |
case 2: |
vid_smio_cntl = RREG32(S2_VID_LOWER_SMIO_CNTL); |
break; |
case 1: |
vid_smio_cntl = RREG32(S1_VID_LOWER_SMIO_CNTL); |
break; |
case 0: |
return; |
default: |
vid_smio_cntl = pi->s0_vid_lower_smio_cntl; |
break; |
} |
WREG32(S0_VID_LOWER_SMIO_CNTL, vid_smio_cntl); |
WREG32_P(GENERAL_PWRMGT, SW_SMIO_INDEX(0), ~SW_SMIO_INDEX_MASK); |
} |
void rv770_get_memory_type(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp; |
tmp = RREG32(MC_SEQ_MISC0); |
if (((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT) == |
MC_SEQ_MISC0_GDDR5_VALUE) |
pi->mem_gddr5 = true; |
else |
pi->mem_gddr5 = false; |
} |
void rv770_get_pcie_gen2_status(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 tmp; |
tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && |
(tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) |
pi->pcie_gen2 = true; |
else |
pi->pcie_gen2 = false; |
if (pi->pcie_gen2) { |
if (tmp & LC_CURRENT_DATA_RATE) |
pi->boot_in_gen2 = true; |
else |
pi->boot_in_gen2 = false; |
} else |
pi->boot_in_gen2 = false; |
} |
#if 0 |
static int rv770_enter_ulp_state(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (pi->gfx_clock_gating) { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); |
RREG32(GB_TILING_CONFIG); |
} |
WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower), |
~HOST_SMC_MSG_MASK); |
udelay(7000); |
return 0; |
} |
static int rv770_exit_ulp_state(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int i; |
WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_ResumeFromMinimumPower), |
~HOST_SMC_MSG_MASK); |
udelay(7000); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (((RREG32(SMC_MSG) & HOST_SMC_RESP_MASK) >> HOST_SMC_RESP_SHIFT) == 1) |
break; |
udelay(1000); |
} |
if (pi->gfx_clock_gating) |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); |
return 0; |
} |
#endif |
static void rv770_get_mclk_odt_threshold(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u8 memory_module_index; |
struct atom_memory_info memory_info; |
pi->mclk_odt_threshold = 0; |
if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) { |
memory_module_index = rv770_get_memory_module_index(rdev); |
if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info)) |
return; |
if (memory_info.mem_type == MEM_TYPE_DDR2 || |
memory_info.mem_type == MEM_TYPE_DDR3) |
pi->mclk_odt_threshold = 30000; |
} |
} |
void rv770_get_max_vddc(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u16 vddc; |
if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc)) |
pi->max_vddc = 0; |
else |
pi->max_vddc = vddc; |
} |
void rv770_program_response_times(struct radeon_device *rdev) |
{ |
u32 voltage_response_time, backbias_response_time; |
u32 acpi_delay_time, vbi_time_out; |
u32 vddc_dly, bb_dly, acpi_dly, vbi_dly; |
u32 reference_clock; |
voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time; |
backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time; |
if (voltage_response_time == 0) |
voltage_response_time = 1000; |
if (backbias_response_time == 0) |
backbias_response_time = 1000; |
acpi_delay_time = 15000; |
vbi_time_out = 100000; |
reference_clock = radeon_get_xclk(rdev); |
vddc_dly = (voltage_response_time * reference_clock) / 1600; |
bb_dly = (backbias_response_time * reference_clock) / 1600; |
acpi_dly = (acpi_delay_time * reference_clock) / 1600; |
vbi_dly = (vbi_time_out * reference_clock) / 1600; |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_delay_vreg, vddc_dly); |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_delay_bbias, bb_dly); |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_delay_acpi, acpi_dly); |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly); |
#if 0 |
/* XXX look up hw revision */ |
if (WEKIVA_A21) |
rv770_write_smc_soft_register(rdev, |
RV770_SMC_SOFT_REGISTER_baby_step_timer, |
0x10); |
#endif |
} |
static void rv770_program_dcodt_before_state_switch(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state); |
struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state); |
bool current_use_dc = false; |
bool new_use_dc = false; |
if (pi->mclk_odt_threshold == 0) |
return; |
if (current_state->high.mclk <= pi->mclk_odt_threshold) |
current_use_dc = true; |
if (new_state->high.mclk <= pi->mclk_odt_threshold) |
new_use_dc = true; |
if (current_use_dc == new_use_dc) |
return; |
if (!current_use_dc && new_use_dc) |
return; |
if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
rv730_program_dcodt(rdev, new_use_dc); |
} |
static void rv770_program_dcodt_after_state_switch(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state); |
struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state); |
bool current_use_dc = false; |
bool new_use_dc = false; |
if (pi->mclk_odt_threshold == 0) |
return; |
if (current_state->high.mclk <= pi->mclk_odt_threshold) |
current_use_dc = true; |
if (new_state->high.mclk <= pi->mclk_odt_threshold) |
new_use_dc = true; |
if (current_use_dc == new_use_dc) |
return; |
if (current_use_dc && !new_use_dc) |
return; |
if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
rv730_program_dcodt(rdev, new_use_dc); |
} |
static void rv770_retrieve_odt_values(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (pi->mclk_odt_threshold == 0) |
return; |
if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
rv730_get_odt_values(rdev); |
} |
static void rv770_set_dpm_event_sources(struct radeon_device *rdev, u32 sources) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
bool want_thermal_protection; |
enum radeon_dpm_event_src dpm_event_src; |
switch (sources) { |
case 0: |
default: |
want_thermal_protection = false; |
break; |
case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL; |
break; |
case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL; |
break; |
case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) | |
(1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL; |
break; |
} |
if (want_thermal_protection) { |
WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK); |
if (pi->thermal_protection) |
WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); |
} else { |
WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); |
} |
} |
void rv770_enable_auto_throttle_source(struct radeon_device *rdev, |
enum radeon_dpm_auto_throttle_src source, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (enable) { |
if (!(pi->active_auto_throttle_sources & (1 << source))) { |
pi->active_auto_throttle_sources |= 1 << source; |
rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); |
} |
} else { |
if (pi->active_auto_throttle_sources & (1 << source)) { |
pi->active_auto_throttle_sources &= ~(1 << source); |
rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); |
} |
} |
} |
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; |
if (low_temp < min_temp) |
low_temp = min_temp; |
if (high_temp > max_temp) |
high_temp = max_temp; |
if (high_temp < low_temp) { |
DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); |
return -EINVAL; |
} |
WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK); |
WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK); |
WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK); |
rdev->pm.dpm.thermal.min_temp = low_temp; |
rdev->pm.dpm.thermal.max_temp = high_temp; |
return 0; |
} |
int rv770_dpm_enable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
int ret; |
if (pi->gfx_clock_gating) |
rv770_restore_cgcg(rdev); |
if (rv770_dpm_enabled(rdev)) |
return -EINVAL; |
if (pi->voltage_control) { |
rv770_enable_voltage_control(rdev, true); |
ret = rv770_construct_vddc_table(rdev); |
if (ret) { |
DRM_ERROR("rv770_construct_vddc_table failed\n"); |
return ret; |
} |
} |
if (pi->dcodt) |
rv770_retrieve_odt_values(rdev); |
if (pi->mvdd_control) { |
ret = rv770_get_mvdd_configuration(rdev); |
if (ret) { |
DRM_ERROR("rv770_get_mvdd_configuration failed\n"); |
return ret; |
} |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) |
rv770_enable_backbias(rdev, true); |
rv770_enable_spread_spectrum(rdev, true); |
if (pi->thermal_protection) |
rv770_enable_thermal_protection(rdev, true); |
rv770_program_mpll_timing_parameters(rdev); |
rv770_setup_bsp(rdev); |
rv770_program_git(rdev); |
rv770_program_tp(rdev); |
rv770_program_tpp(rdev); |
rv770_program_sstp(rdev); |
rv770_program_engine_speed_parameters(rdev); |
rv770_enable_display_gap(rdev); |
rv770_program_vc(rdev); |
if (pi->dynamic_pcie_gen2) |
rv770_enable_dynamic_pcie_gen2(rdev, true); |
ret = rv770_upload_firmware(rdev); |
if (ret) { |
DRM_ERROR("rv770_upload_firmware failed\n"); |
return ret; |
} |
ret = rv770_init_smc_table(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("rv770_init_smc_table failed\n"); |
return ret; |
} |
rv770_program_response_times(rdev); |
r7xx_start_smc(rdev); |
if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
rv730_start_dpm(rdev); |
else |
rv770_start_dpm(rdev); |
if (pi->gfx_clock_gating) |
rv770_gfx_clock_gating_enable(rdev, true); |
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; |
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"); |
} |
return 0; |
} |
void rv770_dpm_disable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (!rv770_dpm_enabled(rdev)) |
return; |
rv770_clear_vc(rdev); |
if (pi->thermal_protection) |
rv770_enable_thermal_protection(rdev, false); |
rv770_enable_spread_spectrum(rdev, false); |
if (pi->dynamic_pcie_gen2) |
rv770_enable_dynamic_pcie_gen2(rdev, false); |
if (rdev->irq.installed && |
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { |
rdev->irq.dpm_thermal = false; |
radeon_irq_set(rdev); |
} |
if (pi->gfx_clock_gating) |
rv770_gfx_clock_gating_enable(rdev, false); |
if (pi->mg_clock_gating) |
rv770_mg_clock_gating_enable(rdev, false); |
if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) |
rv730_stop_dpm(rdev); |
else |
rv770_stop_dpm(rdev); |
r7xx_stop_smc(rdev); |
rv770_reset_smio_status(rdev); |
} |
int rv770_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; |
struct radeon_ps *old_ps = rdev->pm.dpm.current_ps; |
int ret; |
ret = rv770_restrict_performance_levels_before_switch(rdev); |
if (ret) { |
DRM_ERROR("rv770_restrict_performance_levels_before_switch failed\n"); |
return ret; |
} |
rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
ret = rv770_halt_smc(rdev); |
if (ret) { |
DRM_ERROR("rv770_halt_smc failed\n"); |
return ret; |
} |
ret = rv770_upload_sw_state(rdev, new_ps); |
if (ret) { |
DRM_ERROR("rv770_upload_sw_state failed\n"); |
return ret; |
} |
r7xx_program_memory_timing_parameters(rdev, new_ps); |
if (pi->dcodt) |
rv770_program_dcodt_before_state_switch(rdev, new_ps, old_ps); |
ret = rv770_resume_smc(rdev); |
if (ret) { |
DRM_ERROR("rv770_resume_smc failed\n"); |
return ret; |
} |
ret = rv770_set_sw_state(rdev); |
if (ret) { |
DRM_ERROR("rv770_set_sw_state failed\n"); |
return ret; |
} |
if (pi->dcodt) |
rv770_program_dcodt_after_state_switch(rdev, new_ps, old_ps); |
rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
return 0; |
} |
void rv770_dpm_reset_asic(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
rv770_restrict_performance_levels_before_switch(rdev); |
if (pi->dcodt) |
rv770_program_dcodt_before_state_switch(rdev, boot_ps, boot_ps); |
rv770_set_boot_state(rdev); |
if (pi->dcodt) |
rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps); |
} |
void rv770_dpm_setup_asic(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
r7xx_read_clock_registers(rdev); |
rv770_read_voltage_smio_registers(rdev); |
rv770_get_memory_type(rdev); |
if (pi->dcodt) |
rv770_get_mclk_odt_threshold(rdev); |
rv770_get_pcie_gen2_status(rdev); |
rv770_enable_acpi_pm(rdev); |
if (radeon_aspm != 0) { |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) |
rv770_enable_l0s(rdev); |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) |
rv770_enable_l1(rdev); |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) |
rv770_enable_pll_sleep_in_l1(rdev); |
} |
} |
void rv770_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
rv770_program_display_gap(rdev); |
} |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void rv7xx_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, |
u8 table_rev) |
{ |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { |
rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); |
rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (r600_is_uvd_state(rps->class, rps->class2)) { |
if ((rps->vclk == 0) || (rps->dclk == 0)) { |
rps->vclk = RV770_DEFAULT_VCLK_FREQ; |
rps->dclk = RV770_DEFAULT_DCLK_FREQ; |
} |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) |
rdev->pm.dpm.boot_ps = rps; |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, int index, |
union pplib_clock_info *clock_info) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct rv7xx_ps *ps = rv770_get_ps(rps); |
u32 sclk, mclk; |
struct rv7xx_pl *pl; |
switch (index) { |
case 0: |
pl = &ps->low; |
break; |
case 1: |
pl = &ps->medium; |
break; |
case 2: |
default: |
pl = &ps->high; |
break; |
} |
if (rdev->family >= CHIP_CEDAR) { |
sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); |
sclk |= clock_info->evergreen.ucEngineClockHigh << 16; |
mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow); |
mclk |= clock_info->evergreen.ucMemoryClockHigh << 16; |
pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC); |
pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI); |
pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags); |
} else { |
sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); |
sclk |= clock_info->r600.ucEngineClockHigh << 16; |
mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); |
mclk |= clock_info->r600.ucMemoryClockHigh << 16; |
pl->vddc = le16_to_cpu(clock_info->r600.usVDDC); |
pl->flags = le32_to_cpu(clock_info->r600.ulFlags); |
} |
pl->mclk = mclk; |
pl->sclk = sclk; |
/* patch up vddc if necessary */ |
if (pl->vddc == 0xff01) { |
if (pi->max_vddc) |
pl->vddc = pi->max_vddc; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { |
pi->acpi_vddc = pl->vddc; |
if (rdev->family >= CHIP_CEDAR) |
eg_pi->acpi_vddci = pl->vddci; |
if (ps->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) |
pi->acpi_pcie_gen2 = true; |
else |
pi->acpi_pcie_gen2 = false; |
} |
if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) { |
if (rdev->family >= CHIP_BARTS) { |
eg_pi->ulv.supported = true; |
eg_pi->ulv.pl = pl; |
} |
} |
if (pi->min_vddc_in_table > pl->vddc) |
pi->min_vddc_in_table = pl->vddc; |
if (pi->max_vddc_in_table < pl->vddc) |
pi->max_vddc_in_table = pl->vddc; |
/* patch up boot state */ |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
u16 vddc, vddci, mvdd; |
radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); |
pl->mclk = rdev->clock.default_mclk; |
pl->sclk = rdev->clock.default_sclk; |
pl->vddc = vddc; |
pl->vddci = 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; |
} |
} |
int rv7xx_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i, j; |
union pplib_clock_info *clock_info; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
struct rv7xx_ps *ps; |
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.ps = kzalloc(sizeof(struct radeon_ps) * |
power_info->pplib.ucNumStates, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
for (i = 0; i < power_info->pplib.ucNumStates; i++) { |
power_state = (union pplib_power_state *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset) + |
i * power_info->pplib.ucStateEntrySize); |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + |
(power_state->v1.ucNonClockStateIndex * |
power_info->pplib.ucNonClockSize)); |
if (power_info->pplib.ucStateEntrySize - 1) { |
u8 *idx; |
ps = kzalloc(sizeof(struct rv7xx_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
rv7xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info, |
power_info->pplib.ucNonClockSize); |
idx = (u8 *)&power_state->v1.ucClockStateIndices[0]; |
for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { |
clock_info = (union pplib_clock_info *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + |
(idx[j] * power_info->pplib.ucClockInfoSize)); |
rv7xx_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], j, |
clock_info); |
} |
} |
} |
rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates; |
return 0; |
} |
void rv770_get_engine_memory_ss(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct radeon_atom_ss ss; |
pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, 0); |
pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, 0); |
if (pi->sclk_ss || pi->mclk_ss) |
pi->dynamic_ss = true; |
else |
pi->dynamic_ss = false; |
} |
int rv770_dpm_init(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi; |
struct atom_clock_dividers dividers; |
int ret; |
pi = kzalloc(sizeof(struct rv7xx_power_info), GFP_KERNEL); |
if (pi == NULL) |
return -ENOMEM; |
rdev->pm.dpm.priv = pi; |
rv770_get_max_vddc(rdev); |
pi->acpi_vddc = 0; |
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; |
if (rdev->pm.dpm.voltage_response_time == 0) |
rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; |
if (rdev->pm.dpm.backbias_response_time == 0) |
rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
0, false, ÷rs); |
if (ret) |
pi->ref_div = dividers.ref_div + 1; |
else |
pi->ref_div = R600_REFERENCEDIVIDER_DFLT; |
pi->mclk_strobe_mode_threshold = 30000; |
pi->mclk_edc_enable_threshold = 30000; |
pi->rlp = RV770_RLP_DFLT; |
pi->rmp = RV770_RMP_DFLT; |
pi->lhp = RV770_LHP_DFLT; |
pi->lmp = RV770_LMP_DFLT; |
pi->voltage_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0); |
pi->mvdd_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0); |
rv770_get_engine_memory_ss(rdev); |
pi->asi = RV770_ASI_DFLT; |
pi->pasi = RV770_HASI_DFLT; |
pi->vrc = RV770_VRC_DFLT; |
pi->power_gating = false; |
pi->gfx_clock_gating = true; |
pi->mg_clock_gating = true; |
pi->mgcgtssm = true; |
pi->dynamic_pcie_gen2 = true; |
if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) |
pi->thermal_protection = true; |
else |
pi->thermal_protection = false; |
pi->display_gap = true; |
if (rdev->flags & RADEON_IS_MOBILITY) |
pi->dcodt = true; |
else |
pi->dcodt = false; |
pi->ulps = true; |
pi->mclk_stutter_mode_threshold = 0; |
pi->sram_end = SMC_RAM_END; |
pi->state_table_start = RV770_SMC_TABLE_ADDRESS; |
pi->soft_regs_start = RV770_SMC_SOFT_REGISTERS_START; |
return 0; |
} |
void rv770_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct rv7xx_ps *ps = rv770_get_ps(rps); |
struct rv7xx_pl *pl; |
r600_dpm_print_class_info(rps->class, rps->class2); |
r600_dpm_print_cap_info(rps->caps); |
printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
if (rdev->family >= CHIP_CEDAR) { |
pl = &ps->low; |
printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u vddci: %u\n", |
pl->sclk, pl->mclk, pl->vddc, pl->vddci); |
pl = &ps->medium; |
printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u vddci: %u\n", |
pl->sclk, pl->mclk, pl->vddc, pl->vddci); |
pl = &ps->high; |
printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u vddci: %u\n", |
pl->sclk, pl->mclk, pl->vddc, pl->vddci); |
} else { |
pl = &ps->low; |
printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n", |
pl->sclk, pl->mclk, pl->vddc); |
pl = &ps->medium; |
printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n", |
pl->sclk, pl->mclk, pl->vddc); |
pl = &ps->high; |
printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n", |
pl->sclk, pl->mclk, pl->vddc); |
} |
r600_dpm_print_ps_status(rdev, rps); |
} |
void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m) |
{ |
struct radeon_ps *rps = rdev->pm.dpm.current_ps; |
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); |
} |
} |
} |
void rv770_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
} |
u32 rv770_dpm_get_sclk(struct radeon_device *rdev, bool low) |
{ |
struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps); |
if (low) |
return requested_state->low.sclk; |
else |
return requested_state->high.sclk; |
} |
u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps); |
if (low) |
return requested_state->low.mclk; |
else |
return requested_state->high.mclk; |
} |
bool rv770_dpm_vblank_too_short(struct radeon_device *rdev) |
{ |
u32 vblank_time = r600_dpm_get_vblank_time(rdev); |
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; |
else |
return false; |
} |
/drivers/video/drm/radeon/rv770_dpm.h |
---|
0,0 → 1,286 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __RV770_DPM_H__ |
#define __RV770_DPM_H__ |
#include "rv770_smc.h" |
struct rv770_clock_registers { |
u32 cg_spll_func_cntl; |
u32 cg_spll_func_cntl_2; |
u32 cg_spll_func_cntl_3; |
u32 cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2; |
u32 mpll_ad_func_cntl; |
u32 mpll_ad_func_cntl_2; |
u32 mpll_dq_func_cntl; |
u32 mpll_dq_func_cntl_2; |
u32 mclk_pwrmgt_cntl; |
u32 dll_cntl; |
u32 mpll_ss1; |
u32 mpll_ss2; |
}; |
struct rv730_clock_registers { |
u32 cg_spll_func_cntl; |
u32 cg_spll_func_cntl_2; |
u32 cg_spll_func_cntl_3; |
u32 cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2; |
u32 mclk_pwrmgt_cntl; |
u32 dll_cntl; |
u32 mpll_func_cntl; |
u32 mpll_func_cntl2; |
u32 mpll_func_cntl3; |
u32 mpll_ss; |
u32 mpll_ss2; |
}; |
union r7xx_clock_registers { |
struct rv770_clock_registers rv770; |
struct rv730_clock_registers rv730; |
}; |
struct vddc_table_entry { |
u16 vddc; |
u8 vddc_index; |
u8 high_smio; |
u32 low_smio; |
}; |
#define MAX_NO_OF_MVDD_VALUES 2 |
#define MAX_NO_VREG_STEPS 32 |
struct rv7xx_power_info { |
/* flags */ |
bool mem_gddr5; |
bool pcie_gen2; |
bool dynamic_pcie_gen2; |
bool acpi_pcie_gen2; |
bool boot_in_gen2; |
bool voltage_control; /* vddc */ |
bool mvdd_control; |
bool sclk_ss; |
bool mclk_ss; |
bool dynamic_ss; |
bool gfx_clock_gating; |
bool mg_clock_gating; |
bool mgcgtssm; |
bool power_gating; |
bool thermal_protection; |
bool display_gap; |
bool dcodt; |
bool ulps; |
/* registers */ |
union r7xx_clock_registers clk_regs; |
u32 s0_vid_lower_smio_cntl; |
/* voltage */ |
u32 vddc_mask_low; |
u32 mvdd_mask_low; |
u32 mvdd_split_frequency; |
u32 mvdd_low_smio[MAX_NO_OF_MVDD_VALUES]; |
u16 max_vddc; |
u16 max_vddc_in_table; |
u16 min_vddc_in_table; |
struct vddc_table_entry vddc_table[MAX_NO_VREG_STEPS]; |
u8 valid_vddc_entries; |
/* dc odt */ |
u32 mclk_odt_threshold; |
u8 odt_value_0[2]; |
u8 odt_value_1[2]; |
/* stored values */ |
u32 boot_sclk; |
u16 acpi_vddc; |
u32 ref_div; |
u32 active_auto_throttle_sources; |
u32 mclk_stutter_mode_threshold; |
u32 mclk_strobe_mode_threshold; |
u32 mclk_edc_enable_threshold; |
u32 bsp; |
u32 bsu; |
u32 pbsp; |
u32 pbsu; |
u32 dsp; |
u32 psp; |
u32 asi; |
u32 pasi; |
u32 vrc; |
u32 restricted_levels; |
u32 rlp; |
u32 rmp; |
u32 lhp; |
u32 lmp; |
/* smc offsets */ |
u16 state_table_start; |
u16 soft_regs_start; |
u16 sram_end; |
/* scratch structs */ |
RV770_SMC_STATETABLE smc_statetable; |
}; |
struct rv7xx_pl { |
u32 sclk; |
u32 mclk; |
u16 vddc; |
u16 vddci; /* eg+ only */ |
u32 flags; |
enum radeon_pcie_gen pcie_gen; /* si+ only */ |
}; |
struct rv7xx_ps { |
struct rv7xx_pl high; |
struct rv7xx_pl medium; |
struct rv7xx_pl low; |
bool dc_compatible; |
}; |
#define RV770_RLP_DFLT 10 |
#define RV770_RMP_DFLT 25 |
#define RV770_LHP_DFLT 25 |
#define RV770_LMP_DFLT 10 |
#define RV770_VRC_DFLT 0x003f |
#define RV770_ASI_DFLT 1000 |
#define RV770_HASI_DFLT 200000 |
#define RV770_MGCGTTLOCAL0_DFLT 0x00100000 |
#define RV7XX_MGCGTTLOCAL0_DFLT 0 |
#define RV770_MGCGTTLOCAL1_DFLT 0xFFFF0000 |
#define RV770_MGCGCGTSSMCTRL_DFLT 0x55940000 |
#define MVDD_LOW_INDEX 0 |
#define MVDD_HIGH_INDEX 1 |
#define MVDD_LOW_VALUE 0 |
#define MVDD_HIGH_VALUE 0xffff |
#define RV770_DEFAULT_VCLK_FREQ 53300 /* 10 khz */ |
#define RV770_DEFAULT_DCLK_FREQ 40000 /* 10 khz */ |
/* rv730/rv710 */ |
int rv730_populate_sclk_value(struct radeon_device *rdev, |
u32 engine_clock, |
RV770_SMC_SCLK_VALUE *sclk); |
int rv730_populate_mclk_value(struct radeon_device *rdev, |
u32 engine_clock, u32 memory_clock, |
LPRV7XX_SMC_MCLK_VALUE mclk); |
void rv730_read_clock_registers(struct radeon_device *rdev); |
int rv730_populate_smc_acpi_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table); |
int rv730_populate_smc_initial_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_initial_state, |
RV770_SMC_STATETABLE *table); |
void rv730_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_state); |
void rv730_power_gating_enable(struct radeon_device *rdev, |
bool enable); |
void rv730_start_dpm(struct radeon_device *rdev); |
void rv730_stop_dpm(struct radeon_device *rdev); |
void rv730_program_dcodt(struct radeon_device *rdev, bool use_dcodt); |
void rv730_get_odt_values(struct radeon_device *rdev); |
/* rv740 */ |
int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock, |
RV770_SMC_SCLK_VALUE *sclk); |
int rv740_populate_mclk_value(struct radeon_device *rdev, |
u32 engine_clock, u32 memory_clock, |
RV7XX_SMC_MCLK_VALUE *mclk); |
void rv740_read_clock_registers(struct radeon_device *rdev); |
int rv740_populate_smc_acpi_state(struct radeon_device *rdev, |
RV770_SMC_STATETABLE *table); |
void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev, |
bool enable); |
u8 rv740_get_mclk_frequency_ratio(u32 memory_clock); |
u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock); |
u32 rv740_get_decoded_reference_divider(u32 encoded_ref); |
/* rv770 */ |
u32 rv770_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf); |
int rv770_populate_vddc_value(struct radeon_device *rdev, u16 vddc, |
RV770_SMC_VOLTAGE_VALUE *voltage); |
int rv770_populate_mvdd_value(struct radeon_device *rdev, u32 mclk, |
RV770_SMC_VOLTAGE_VALUE *voltage); |
u8 rv770_get_seq_value(struct radeon_device *rdev, |
struct rv7xx_pl *pl); |
int rv770_populate_initial_mvdd_value(struct radeon_device *rdev, |
RV770_SMC_VOLTAGE_VALUE *voltage); |
u32 rv770_calculate_memory_refresh_rate(struct radeon_device *rdev, |
u32 engine_clock); |
void rv770_program_response_times(struct radeon_device *rdev); |
int rv770_populate_smc_sp(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
RV770_SMC_SWSTATE *smc_state); |
int rv770_populate_smc_t(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
RV770_SMC_SWSTATE *smc_state); |
void rv770_read_voltage_smio_registers(struct radeon_device *rdev); |
void rv770_get_memory_type(struct radeon_device *rdev); |
void r7xx_start_smc(struct radeon_device *rdev); |
u8 rv770_get_memory_module_index(struct radeon_device *rdev); |
void rv770_get_max_vddc(struct radeon_device *rdev); |
void rv770_get_pcie_gen2_status(struct radeon_device *rdev); |
void rv770_enable_acpi_pm(struct radeon_device *rdev); |
void rv770_restore_cgcg(struct radeon_device *rdev); |
bool rv770_dpm_enabled(struct radeon_device *rdev); |
void rv770_enable_voltage_control(struct radeon_device *rdev, |
bool enable); |
void rv770_enable_backbias(struct radeon_device *rdev, |
bool enable); |
void rv770_enable_thermal_protection(struct radeon_device *rdev, |
bool enable); |
void rv770_enable_auto_throttle_source(struct radeon_device *rdev, |
enum radeon_dpm_auto_throttle_src source, |
bool enable); |
void rv770_setup_bsp(struct radeon_device *rdev); |
void rv770_program_git(struct radeon_device *rdev); |
void rv770_program_tp(struct radeon_device *rdev); |
void rv770_program_tpp(struct radeon_device *rdev); |
void rv770_program_sstp(struct radeon_device *rdev); |
void rv770_program_engine_speed_parameters(struct radeon_device *rdev); |
void rv770_program_vc(struct radeon_device *rdev); |
void rv770_clear_vc(struct radeon_device *rdev); |
int rv770_upload_firmware(struct radeon_device *rdev); |
void rv770_stop_dpm(struct radeon_device *rdev); |
void r7xx_stop_smc(struct radeon_device *rdev); |
void rv770_reset_smio_status(struct radeon_device *rdev); |
int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev); |
int rv770_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level); |
int rv770_halt_smc(struct radeon_device *rdev); |
int rv770_resume_smc(struct radeon_device *rdev); |
int rv770_set_sw_state(struct radeon_device *rdev); |
int rv770_set_boot_state(struct radeon_device *rdev); |
int rv7xx_parse_power_table(struct radeon_device *rdev); |
void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps); |
void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_ps, |
struct radeon_ps *old_ps); |
void rv770_get_engine_memory_ss(struct radeon_device *rdev); |
/* smc */ |
int rv770_read_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 *value); |
int rv770_write_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 value); |
#endif |
/drivers/video/drm/radeon/rv770_smc.c |
---|
0,0 → 1,631 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include <linux/firmware.h> |
#include "drmP.h" |
#include "radeon.h" |
#include "rv770d.h" |
#include "rv770_dpm.h" |
#include "rv770_smc.h" |
#include "atom.h" |
#include "radeon_ucode.h" |
#define FIRST_SMC_INT_VECT_REG 0xFFD8 |
#define FIRST_INT_VECT_S19 0xFFC0 |
static const u8 rv770_smc_int_vectors[] = |
{ |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x0C, 0xD7, |
0x08, 0x2B, 0x08, 0x10, |
0x03, 0x51, 0x03, 0x51, |
0x03, 0x51, 0x03, 0x51 |
}; |
static const u8 rv730_smc_int_vectors[] = |
{ |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x08, 0x15, |
0x08, 0x15, 0x0C, 0xBB, |
0x08, 0x30, 0x08, 0x15, |
0x03, 0x56, 0x03, 0x56, |
0x03, 0x56, 0x03, 0x56 |
}; |
static const u8 rv710_smc_int_vectors[] = |
{ |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x08, 0x04, |
0x08, 0x04, 0x0C, 0xCB, |
0x08, 0x1F, 0x08, 0x04, |
0x03, 0x51, 0x03, 0x51, |
0x03, 0x51, 0x03, 0x51 |
}; |
static const u8 rv740_smc_int_vectors[] = |
{ |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x08, 0x10, |
0x08, 0x10, 0x0C, 0xD7, |
0x08, 0x2B, 0x08, 0x10, |
0x03, 0x51, 0x03, 0x51, |
0x03, 0x51, 0x03, 0x51 |
}; |
static const u8 cedar_smc_int_vectors[] = |
{ |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x11, 0x8B, |
0x0B, 0x20, 0x0B, 0x05, |
0x04, 0xF6, 0x04, 0xF6, |
0x04, 0xF6, 0x04, 0xF6 |
}; |
static const u8 redwood_smc_int_vectors[] = |
{ |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x11, 0x8B, |
0x0B, 0x20, 0x0B, 0x05, |
0x04, 0xF6, 0x04, 0xF6, |
0x04, 0xF6, 0x04, 0xF6 |
}; |
static const u8 juniper_smc_int_vectors[] = |
{ |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x11, 0x8B, |
0x0B, 0x20, 0x0B, 0x05, |
0x04, 0xF6, 0x04, 0xF6, |
0x04, 0xF6, 0x04, 0xF6 |
}; |
static const u8 cypress_smc_int_vectors[] = |
{ |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x0B, 0x05, |
0x0B, 0x05, 0x11, 0x8B, |
0x0B, 0x20, 0x0B, 0x05, |
0x04, 0xF6, 0x04, 0xF6, |
0x04, 0xF6, 0x04, 0xF6 |
}; |
static const u8 barts_smc_int_vectors[] = |
{ |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x12, 0xAA, |
0x0C, 0x2F, 0x15, 0xF6, |
0x15, 0xF6, 0x05, 0x0A, |
0x05, 0x0A, 0x05, 0x0A |
}; |
static const u8 turks_smc_int_vectors[] = |
{ |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x12, 0xAA, |
0x0C, 0x2F, 0x15, 0xF6, |
0x15, 0xF6, 0x05, 0x0A, |
0x05, 0x0A, 0x05, 0x0A |
}; |
static const u8 caicos_smc_int_vectors[] = |
{ |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x0C, 0x14, |
0x0C, 0x14, 0x12, 0xAA, |
0x0C, 0x2F, 0x15, 0xF6, |
0x15, 0xF6, 0x05, 0x0A, |
0x05, 0x0A, 0x05, 0x0A |
}; |
static const u8 cayman_smc_int_vectors[] = |
{ |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x12, 0x05, |
0x12, 0x05, 0x18, 0xEA, |
0x12, 0x20, 0x1C, 0x34, |
0x1C, 0x34, 0x08, 0x72, |
0x08, 0x72, 0x08, 0x72 |
}; |
static int rv770_set_smc_sram_address(struct radeon_device *rdev, |
u16 smc_address, u16 limit) |
{ |
u32 addr; |
if (smc_address & 3) |
return -EINVAL; |
if ((smc_address + 3) > limit) |
return -EINVAL; |
addr = smc_address; |
addr |= SMC_SRAM_AUTO_INC_DIS; |
WREG32(SMC_SRAM_ADDR, addr); |
return 0; |
} |
int rv770_copy_bytes_to_smc(struct radeon_device *rdev, |
u16 smc_start_address, const u8 *src, |
u16 byte_count, u16 limit) |
{ |
unsigned long flags; |
u32 data, original_data, extra_shift; |
u16 addr; |
int ret = 0; |
if (smc_start_address & 3) |
return -EINVAL; |
if ((smc_start_address + byte_count) > limit) |
return -EINVAL; |
addr = smc_start_address; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
while (byte_count >= 4) { |
/* SMC address space is BE */ |
data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; |
ret = rv770_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
WREG32(SMC_SRAM_DATA, data); |
src += 4; |
byte_count -= 4; |
addr += 4; |
} |
/* RMW for final bytes */ |
if (byte_count > 0) { |
data = 0; |
ret = rv770_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
original_data = RREG32(SMC_SRAM_DATA); |
extra_shift = 8 * (4 - byte_count); |
while (byte_count > 0) { |
/* SMC address space is BE */ |
data = (data << 8) + *src++; |
byte_count--; |
} |
data <<= extra_shift; |
data |= (original_data & ~((~0UL) << extra_shift)); |
ret = rv770_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
WREG32(SMC_SRAM_DATA, data); |
} |
done: |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
static int rv770_program_interrupt_vectors(struct radeon_device *rdev, |
u32 smc_first_vector, const u8 *src, |
u32 byte_count) |
{ |
u32 tmp, i; |
if (byte_count % 4) |
return -EINVAL; |
if (smc_first_vector < FIRST_SMC_INT_VECT_REG) { |
tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector; |
if (tmp > byte_count) |
return 0; |
byte_count -= tmp; |
src += tmp; |
smc_first_vector = FIRST_SMC_INT_VECT_REG; |
} |
for (i = 0; i < byte_count; i += 4) { |
/* SMC address space is BE */ |
tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3]; |
WREG32(SMC_ISR_FFD8_FFDB + i, tmp); |
} |
return 0; |
} |
void rv770_start_smc(struct radeon_device *rdev) |
{ |
WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N); |
} |
void rv770_reset_smc(struct radeon_device *rdev) |
{ |
WREG32_P(SMC_IO, 0, ~SMC_RST_N); |
} |
void rv770_stop_smc_clock(struct radeon_device *rdev) |
{ |
WREG32_P(SMC_IO, 0, ~SMC_CLK_EN); |
} |
void rv770_start_smc_clock(struct radeon_device *rdev) |
{ |
WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN); |
} |
bool rv770_is_smc_running(struct radeon_device *rdev) |
{ |
u32 tmp; |
tmp = RREG32(SMC_IO); |
if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN)) |
return true; |
else |
return false; |
} |
PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg) |
{ |
u32 tmp; |
int i; |
PPSMC_Result result; |
if (!rv770_is_smc_running(rdev)) |
return PPSMC_Result_Failed; |
WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK; |
tmp >>= HOST_SMC_RESP_SHIFT; |
if (tmp != 0) |
break; |
udelay(1); |
} |
tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK; |
tmp >>= HOST_SMC_RESP_SHIFT; |
result = (PPSMC_Result)tmp; |
return result; |
} |
PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev) |
{ |
int i; |
PPSMC_Result result = PPSMC_Result_OK; |
if (!rv770_is_smc_running(rdev)) |
return result; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(SMC_IO) & SMC_STOP_MODE) |
break; |
udelay(1); |
} |
return result; |
} |
static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit) |
{ |
unsigned long flags; |
u16 i; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
for (i = 0; i < limit; i += 4) { |
rv770_set_smc_sram_address(rdev, i, limit); |
WREG32(SMC_SRAM_DATA, 0); |
} |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
} |
int rv770_load_smc_ucode(struct radeon_device *rdev, |
u16 limit) |
{ |
int ret; |
const u8 *int_vect; |
u16 int_vect_start_address; |
u16 int_vect_size; |
const u8 *ucode_data; |
u16 ucode_start_address; |
u16 ucode_size; |
if (!rdev->smc_fw) |
return -EINVAL; |
rv770_clear_smc_sram(rdev, limit); |
switch (rdev->family) { |
case CHIP_RV770: |
ucode_start_address = RV770_SMC_UCODE_START; |
ucode_size = RV770_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&rv770_smc_int_vectors; |
int_vect_start_address = RV770_SMC_INT_VECTOR_START; |
int_vect_size = RV770_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_RV730: |
ucode_start_address = RV730_SMC_UCODE_START; |
ucode_size = RV730_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&rv730_smc_int_vectors; |
int_vect_start_address = RV730_SMC_INT_VECTOR_START; |
int_vect_size = RV730_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_RV710: |
ucode_start_address = RV710_SMC_UCODE_START; |
ucode_size = RV710_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&rv710_smc_int_vectors; |
int_vect_start_address = RV710_SMC_INT_VECTOR_START; |
int_vect_size = RV710_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_RV740: |
ucode_start_address = RV740_SMC_UCODE_START; |
ucode_size = RV740_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&rv740_smc_int_vectors; |
int_vect_start_address = RV740_SMC_INT_VECTOR_START; |
int_vect_size = RV740_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_CEDAR: |
ucode_start_address = CEDAR_SMC_UCODE_START; |
ucode_size = CEDAR_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&cedar_smc_int_vectors; |
int_vect_start_address = CEDAR_SMC_INT_VECTOR_START; |
int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_REDWOOD: |
ucode_start_address = REDWOOD_SMC_UCODE_START; |
ucode_size = REDWOOD_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&redwood_smc_int_vectors; |
int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START; |
int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_JUNIPER: |
ucode_start_address = JUNIPER_SMC_UCODE_START; |
ucode_size = JUNIPER_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&juniper_smc_int_vectors; |
int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START; |
int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_CYPRESS: |
case CHIP_HEMLOCK: |
ucode_start_address = CYPRESS_SMC_UCODE_START; |
ucode_size = CYPRESS_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&cypress_smc_int_vectors; |
int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START; |
int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_BARTS: |
ucode_start_address = BARTS_SMC_UCODE_START; |
ucode_size = BARTS_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&barts_smc_int_vectors; |
int_vect_start_address = BARTS_SMC_INT_VECTOR_START; |
int_vect_size = BARTS_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_TURKS: |
ucode_start_address = TURKS_SMC_UCODE_START; |
ucode_size = TURKS_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&turks_smc_int_vectors; |
int_vect_start_address = TURKS_SMC_INT_VECTOR_START; |
int_vect_size = TURKS_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_CAICOS: |
ucode_start_address = CAICOS_SMC_UCODE_START; |
ucode_size = CAICOS_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&caicos_smc_int_vectors; |
int_vect_start_address = CAICOS_SMC_INT_VECTOR_START; |
int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE; |
break; |
case CHIP_CAYMAN: |
ucode_start_address = CAYMAN_SMC_UCODE_START; |
ucode_size = CAYMAN_SMC_UCODE_SIZE; |
int_vect = (const u8 *)&cayman_smc_int_vectors; |
int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START; |
int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE; |
break; |
default: |
DRM_ERROR("unknown asic in smc ucode loader\n"); |
BUG(); |
} |
/* load the ucode */ |
ucode_data = (const u8 *)rdev->smc_fw->data; |
ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address, |
ucode_data, ucode_size, limit); |
if (ret) |
return ret; |
/* set up the int vectors */ |
ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address, |
int_vect, int_vect_size); |
if (ret) |
return ret; |
return 0; |
} |
int rv770_read_smc_sram_dword(struct radeon_device *rdev, |
u16 smc_address, u32 *value, u16 limit) |
{ |
unsigned long flags; |
int ret; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
ret = rv770_set_smc_sram_address(rdev, smc_address, limit); |
if (ret == 0) |
*value = RREG32(SMC_SRAM_DATA); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
int rv770_write_smc_sram_dword(struct radeon_device *rdev, |
u16 smc_address, u32 value, u16 limit) |
{ |
unsigned long flags; |
int ret; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
ret = rv770_set_smc_sram_address(rdev, smc_address, limit); |
if (ret == 0) |
WREG32(SMC_SRAM_DATA, value); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
/drivers/video/drm/radeon/rv770_smc.h |
---|
0,0 → 1,207 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __RV770_SMC_H__ |
#define __RV770_SMC_H__ |
#include "ppsmc.h" |
#pragma pack(push, 1) |
#define RV770_SMC_TABLE_ADDRESS 0xB000 |
#define RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 3 |
struct RV770_SMC_SCLK_VALUE |
{ |
uint32_t vCG_SPLL_FUNC_CNTL; |
uint32_t vCG_SPLL_FUNC_CNTL_2; |
uint32_t vCG_SPLL_FUNC_CNTL_3; |
uint32_t vCG_SPLL_SPREAD_SPECTRUM; |
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2; |
uint32_t sclk_value; |
}; |
typedef struct RV770_SMC_SCLK_VALUE RV770_SMC_SCLK_VALUE; |
struct RV770_SMC_MCLK_VALUE |
{ |
uint32_t vMPLL_AD_FUNC_CNTL; |
uint32_t vMPLL_AD_FUNC_CNTL_2; |
uint32_t vMPLL_DQ_FUNC_CNTL; |
uint32_t vMPLL_DQ_FUNC_CNTL_2; |
uint32_t vMCLK_PWRMGT_CNTL; |
uint32_t vDLL_CNTL; |
uint32_t vMPLL_SS; |
uint32_t vMPLL_SS2; |
uint32_t mclk_value; |
}; |
typedef struct RV770_SMC_MCLK_VALUE RV770_SMC_MCLK_VALUE; |
struct RV730_SMC_MCLK_VALUE |
{ |
uint32_t vMCLK_PWRMGT_CNTL; |
uint32_t vDLL_CNTL; |
uint32_t vMPLL_FUNC_CNTL; |
uint32_t vMPLL_FUNC_CNTL2; |
uint32_t vMPLL_FUNC_CNTL3; |
uint32_t vMPLL_SS; |
uint32_t vMPLL_SS2; |
uint32_t mclk_value; |
}; |
typedef struct RV730_SMC_MCLK_VALUE RV730_SMC_MCLK_VALUE; |
struct RV770_SMC_VOLTAGE_VALUE |
{ |
uint16_t value; |
uint8_t index; |
uint8_t padding; |
}; |
typedef struct RV770_SMC_VOLTAGE_VALUE RV770_SMC_VOLTAGE_VALUE; |
union RV7XX_SMC_MCLK_VALUE |
{ |
RV770_SMC_MCLK_VALUE mclk770; |
RV730_SMC_MCLK_VALUE mclk730; |
}; |
typedef union RV7XX_SMC_MCLK_VALUE RV7XX_SMC_MCLK_VALUE, *LPRV7XX_SMC_MCLK_VALUE; |
struct RV770_SMC_HW_PERFORMANCE_LEVEL |
{ |
uint8_t arbValue; |
union{ |
uint8_t seqValue; |
uint8_t ACIndex; |
}; |
uint8_t displayWatermark; |
uint8_t gen2PCIE; |
uint8_t gen2XSP; |
uint8_t backbias; |
uint8_t strobeMode; |
uint8_t mcFlags; |
uint32_t aT; |
uint32_t bSP; |
RV770_SMC_SCLK_VALUE sclk; |
RV7XX_SMC_MCLK_VALUE mclk; |
RV770_SMC_VOLTAGE_VALUE vddc; |
RV770_SMC_VOLTAGE_VALUE mvdd; |
RV770_SMC_VOLTAGE_VALUE vddci; |
uint8_t reserved1; |
uint8_t reserved2; |
uint8_t stateFlags; |
uint8_t padding; |
}; |
#define SMC_STROBE_RATIO 0x0F |
#define SMC_STROBE_ENABLE 0x10 |
#define SMC_MC_EDC_RD_FLAG 0x01 |
#define SMC_MC_EDC_WR_FLAG 0x02 |
#define SMC_MC_RTT_ENABLE 0x04 |
#define SMC_MC_STUTTER_EN 0x08 |
typedef struct RV770_SMC_HW_PERFORMANCE_LEVEL RV770_SMC_HW_PERFORMANCE_LEVEL; |
struct RV770_SMC_SWSTATE |
{ |
uint8_t flags; |
uint8_t padding1; |
uint8_t padding2; |
uint8_t padding3; |
RV770_SMC_HW_PERFORMANCE_LEVEL levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE]; |
}; |
typedef struct RV770_SMC_SWSTATE RV770_SMC_SWSTATE; |
#define RV770_SMC_VOLTAGEMASK_VDDC 0 |
#define RV770_SMC_VOLTAGEMASK_MVDD 1 |
#define RV770_SMC_VOLTAGEMASK_VDDCI 2 |
#define RV770_SMC_VOLTAGEMASK_MAX 4 |
struct RV770_SMC_VOLTAGEMASKTABLE |
{ |
uint8_t highMask[RV770_SMC_VOLTAGEMASK_MAX]; |
uint32_t lowMask[RV770_SMC_VOLTAGEMASK_MAX]; |
}; |
typedef struct RV770_SMC_VOLTAGEMASKTABLE RV770_SMC_VOLTAGEMASKTABLE; |
#define MAX_NO_VREG_STEPS 32 |
struct RV770_SMC_STATETABLE |
{ |
uint8_t thermalProtectType; |
uint8_t systemFlags; |
uint8_t maxVDDCIndexInPPTable; |
uint8_t extraFlags; |
uint8_t highSMIO[MAX_NO_VREG_STEPS]; |
uint32_t lowSMIO[MAX_NO_VREG_STEPS]; |
RV770_SMC_VOLTAGEMASKTABLE voltageMaskTable; |
RV770_SMC_SWSTATE initialState; |
RV770_SMC_SWSTATE ACPIState; |
RV770_SMC_SWSTATE driverState; |
RV770_SMC_SWSTATE ULVState; |
}; |
typedef struct RV770_SMC_STATETABLE RV770_SMC_STATETABLE; |
#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01 |
#pragma pack(pop) |
#define RV770_SMC_SOFT_REGISTERS_START 0x104 |
#define RV770_SMC_SOFT_REGISTER_mclk_chg_timeout 0x0 |
#define RV770_SMC_SOFT_REGISTER_baby_step_timer 0x8 |
#define RV770_SMC_SOFT_REGISTER_delay_bbias 0xC |
#define RV770_SMC_SOFT_REGISTER_delay_vreg 0x10 |
#define RV770_SMC_SOFT_REGISTER_delay_acpi 0x2C |
#define RV770_SMC_SOFT_REGISTER_seq_index 0x64 |
#define RV770_SMC_SOFT_REGISTER_mvdd_chg_time 0x68 |
#define RV770_SMC_SOFT_REGISTER_mclk_switch_lim 0x78 |
#define RV770_SMC_SOFT_REGISTER_mc_block_delay 0x90 |
#define RV770_SMC_SOFT_REGISTER_uvd_enabled 0x9C |
#define RV770_SMC_SOFT_REGISTER_is_asic_lombok 0xA0 |
int rv770_copy_bytes_to_smc(struct radeon_device *rdev, |
u16 smc_start_address, const u8 *src, |
u16 byte_count, u16 limit); |
void rv770_start_smc(struct radeon_device *rdev); |
void rv770_reset_smc(struct radeon_device *rdev); |
void rv770_stop_smc_clock(struct radeon_device *rdev); |
void rv770_start_smc_clock(struct radeon_device *rdev); |
bool rv770_is_smc_running(struct radeon_device *rdev); |
PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg); |
PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev); |
int rv770_read_smc_sram_dword(struct radeon_device *rdev, |
u16 smc_address, u32 *value, u16 limit); |
int rv770_write_smc_sram_dword(struct radeon_device *rdev, |
u16 smc_address, u32 value, u16 limit); |
int rv770_load_smc_ucode(struct radeon_device *rdev, |
u16 limit); |
#endif |
/drivers/video/drm/radeon/rv770d.h |
---|
62,6 → 62,253 |
# define UPLL_FB_DIV(x) ((x) << 0) |
# define UPLL_FB_DIV_MASK 0x01FFFFFF |
/* pm registers */ |
#define SMC_SRAM_ADDR 0x200 |
#define SMC_SRAM_AUTO_INC_DIS (1 << 16) |
#define SMC_SRAM_DATA 0x204 |
#define SMC_IO 0x208 |
#define SMC_RST_N (1 << 0) |
#define SMC_STOP_MODE (1 << 2) |
#define SMC_CLK_EN (1 << 11) |
#define SMC_MSG 0x20c |
#define HOST_SMC_MSG(x) ((x) << 0) |
#define HOST_SMC_MSG_MASK (0xff << 0) |
#define HOST_SMC_MSG_SHIFT 0 |
#define HOST_SMC_RESP(x) ((x) << 8) |
#define HOST_SMC_RESP_MASK (0xff << 8) |
#define HOST_SMC_RESP_SHIFT 8 |
#define SMC_HOST_MSG(x) ((x) << 16) |
#define SMC_HOST_MSG_MASK (0xff << 16) |
#define SMC_HOST_MSG_SHIFT 16 |
#define SMC_HOST_RESP(x) ((x) << 24) |
#define SMC_HOST_RESP_MASK (0xff << 24) |
#define SMC_HOST_RESP_SHIFT 24 |
#define SMC_ISR_FFD8_FFDB 0x218 |
#define CG_SPLL_FUNC_CNTL 0x600 |
#define SPLL_RESET (1 << 0) |
#define SPLL_SLEEP (1 << 1) |
#define SPLL_DIVEN (1 << 2) |
#define SPLL_BYPASS_EN (1 << 3) |
#define SPLL_REF_DIV(x) ((x) << 4) |
#define SPLL_REF_DIV_MASK (0x3f << 4) |
#define SPLL_HILEN(x) ((x) << 12) |
#define SPLL_HILEN_MASK (0xf << 12) |
#define SPLL_LOLEN(x) ((x) << 16) |
#define SPLL_LOLEN_MASK (0xf << 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 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) |
#define CLKR(x) ((x) << 7) |
#define CLKR_MASK (0x1f << 7) |
#define CLKFRAC(x) ((x) << 12) |
#define CLKFRAC_MASK (0x1f << 12) |
#define YCLK_POST_DIV(x) ((x) << 17) |
#define YCLK_POST_DIV_MASK (3 << 17) |
#define IBIAS(x) ((x) << 20) |
#define IBIAS_MASK (0x3ff << 20) |
#define RESET (1 << 30) |
#define PDNB (1 << 31) |
#define MPLL_AD_FUNC_CNTL_2 0x628 |
#define BYPASS (1 << 19) |
#define BIAS_GEN_PDNB (1 << 24) |
#define RESET_EN (1 << 25) |
#define VCO_MODE (1 << 29) |
#define MPLL_DQ_FUNC_CNTL 0x62c |
#define MPLL_DQ_FUNC_CNTL_2 0x630 |
#define GENERAL_PWRMGT 0x63c |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define THERMAL_PROTECTION_DIS (1 << 2) |
# define THERMAL_PROTECTION_TYPE (1 << 3) |
# define ENABLE_GEN2PCIE (1 << 4) |
# define ENABLE_GEN2XSP (1 << 5) |
# define SW_SMIO_INDEX(x) ((x) << 6) |
# define SW_SMIO_INDEX_MASK (3 << 6) |
# define SW_SMIO_INDEX_SHIFT 6 |
# define LOW_VOLT_D2_ACPI (1 << 8) |
# define LOW_VOLT_D3_ACPI (1 << 9) |
# define VOLT_PWRMGT_EN (1 << 10) |
# define BACKBIAS_PAD_EN (1 << 18) |
# define BACKBIAS_VALUE (1 << 19) |
# define DYN_SPREAD_SPECTRUM_EN (1 << 23) |
# define AC_DC_SW (1 << 24) |
#define CG_TPC 0x640 |
#define SCLK_PWRMGT_CNTL 0x644 |
# define SCLK_PWRMGT_OFF (1 << 0) |
# define SCLK_LOW_D1 (1 << 1) |
# define FIR_RESET (1 << 4) |
# define FIR_FORCE_TREND_SEL (1 << 5) |
# define FIR_TREND_MODE (1 << 6) |
# define DYN_GFX_CLK_OFF_EN (1 << 7) |
# define GFX_CLK_FORCE_ON (1 << 8) |
# define GFX_CLK_REQUEST_OFF (1 << 9) |
# define GFX_CLK_FORCE_OFF (1 << 10) |
# define GFX_CLK_OFF_ACPI_D1 (1 << 11) |
# define GFX_CLK_OFF_ACPI_D2 (1 << 12) |
# define GFX_CLK_OFF_ACPI_D3 (1 << 13) |
#define MCLK_PWRMGT_CNTL 0x648 |
# define DLL_SPEED(x) ((x) << 0) |
# define DLL_SPEED_MASK (0x1f << 0) |
# define MPLL_PWRMGT_OFF (1 << 5) |
# define DLL_READY (1 << 6) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCKA0_SLEEP (1 << 8) |
# define MRDCKA1_SLEEP (1 << 9) |
# define MRDCKB0_SLEEP (1 << 10) |
# define MRDCKB1_SLEEP (1 << 11) |
# define MRDCKC0_SLEEP (1 << 12) |
# define MRDCKC1_SLEEP (1 << 13) |
# define MRDCKD0_SLEEP (1 << 14) |
# define MRDCKD1_SLEEP (1 << 15) |
# define MRDCKA0_RESET (1 << 16) |
# define MRDCKA1_RESET (1 << 17) |
# define MRDCKB0_RESET (1 << 18) |
# define MRDCKB1_RESET (1 << 19) |
# define MRDCKC0_RESET (1 << 20) |
# define MRDCKC1_RESET (1 << 21) |
# define MRDCKD0_RESET (1 << 22) |
# define MRDCKD1_RESET (1 << 23) |
# define DLL_READY_READ (1 << 24) |
# define USE_DISPLAY_GAP (1 << 25) |
# define USE_DISPLAY_URGENT_NORMAL (1 << 26) |
# define MPLL_TURNOFF_D2 (1 << 28) |
#define DLL_CNTL 0x64c |
# define MRDCKA0_BYPASS (1 << 24) |
# define MRDCKA1_BYPASS (1 << 25) |
# define MRDCKB0_BYPASS (1 << 26) |
# define MRDCKB1_BYPASS (1 << 27) |
# define MRDCKC0_BYPASS (1 << 28) |
# define MRDCKC1_BYPASS (1 << 29) |
# define MRDCKD0_BYPASS (1 << 30) |
# define MRDCKD1_BYPASS (1 << 31) |
#define MPLL_TIME 0x654 |
# define MPLL_LOCK_TIME(x) ((x) << 0) |
# define MPLL_LOCK_TIME_MASK (0xffff << 0) |
# define MPLL_RESET_TIME(x) ((x) << 16) |
# define MPLL_RESET_TIME_MASK (0xffff << 16) |
#define CG_CLKPIN_CNTL 0x660 |
# define MUX_TCLK_TO_XCLK (1 << 8) |
# define XTALIN_DIVIDE (1 << 9) |
#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c |
# define CURRENT_PROFILE_INDEX_MASK (0xf << 4) |
# define CURRENT_PROFILE_INDEX_SHIFT 4 |
#define S0_VID_LOWER_SMIO_CNTL 0x678 |
#define S1_VID_LOWER_SMIO_CNTL 0x67c |
#define S2_VID_LOWER_SMIO_CNTL 0x680 |
#define S3_VID_LOWER_SMIO_CNTL 0x684 |
#define CG_FTV 0x690 |
#define CG_FFCT_0 0x694 |
# define UTC_0(x) ((x) << 0) |
# define UTC_0_MASK (0x3ff << 0) |
# define DTC_0(x) ((x) << 10) |
# define DTC_0_MASK (0x3ff << 10) |
#define CG_BSP 0x6d0 |
# define BSP(x) ((x) << 0) |
# define BSP_MASK (0xffff << 0) |
# define BSU(x) ((x) << 16) |
# define BSU_MASK (0xf << 16) |
#define CG_AT 0x6d4 |
# define CG_R(x) ((x) << 0) |
# define CG_R_MASK (0xffff << 0) |
# define CG_L(x) ((x) << 16) |
# define CG_L_MASK (0xffff << 16) |
#define CG_GIT 0x6d8 |
# define CG_GICST(x) ((x) << 0) |
# define CG_GICST_MASK (0xffff << 0) |
# define CG_GIPOT(x) ((x) << 16) |
# define CG_GIPOT_MASK (0xffff << 16) |
#define CG_SSP 0x6e8 |
# define SST(x) ((x) << 0) |
# define SST_MASK (0xffff << 0) |
# define SSTU(x) ((x) << 16) |
# define SSTU_MASK (0xf << 16) |
#define CG_DISPLAY_GAP_CNTL 0x714 |
# define DISP1_GAP(x) ((x) << 0) |
# define DISP1_GAP_MASK (3 << 0) |
# define DISP2_GAP(x) ((x) << 2) |
# define DISP2_GAP_MASK (3 << 2) |
# define VBI_TIMER_COUNT(x) ((x) << 4) |
# define VBI_TIMER_COUNT_MASK (0x3fff << 4) |
# define VBI_TIMER_UNIT(x) ((x) << 20) |
# define VBI_TIMER_UNIT_MASK (7 << 20) |
# define DISP1_GAP_MCHG(x) ((x) << 24) |
# define DISP1_GAP_MCHG_MASK (3 << 24) |
# define DISP2_GAP_MCHG(x) ((x) << 26) |
# define DISP2_GAP_MCHG_MASK (3 << 26) |
#define CG_SPLL_SPREAD_SPECTRUM 0x790 |
#define SSEN (1 << 0) |
#define CLKS(x) ((x) << 4) |
#define CLKS_MASK (0xfff << 4) |
#define CG_SPLL_SPREAD_SPECTRUM_2 0x794 |
#define CLKV(x) ((x) << 0) |
#define CLKV_MASK (0x3ffffff << 0) |
#define CG_MPLL_SPREAD_SPECTRUM 0x798 |
#define CG_UPLL_SPREAD_SPECTRUM 0x79c |
# define SSEN_MASK 0x00000001 |
#define CG_CGTT_LOCAL_0 0x7d0 |
#define CG_CGTT_LOCAL_1 0x7d4 |
#define BIOS_SCRATCH_4 0x1734 |
#define MC_SEQ_MISC0 0x2a00 |
#define MC_SEQ_MISC0_GDDR5_SHIFT 28 |
#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000 |
#define MC_SEQ_MISC0_GDDR5_VALUE 5 |
#define MC_ARB_SQM_RATIO 0x2770 |
#define STATE0(x) ((x) << 0) |
#define STATE0_MASK (0xff << 0) |
#define STATE1(x) ((x) << 8) |
#define STATE1_MASK (0xff << 8) |
#define STATE2(x) ((x) << 16) |
#define STATE2_MASK (0xff << 16) |
#define STATE3(x) ((x) << 24) |
#define STATE3_MASK (0xff << 24) |
#define MC_ARB_RFSH_RATE 0x27b0 |
#define POWERMODE0(x) ((x) << 0) |
#define POWERMODE0_MASK (0xff << 0) |
#define POWERMODE1(x) ((x) << 8) |
#define POWERMODE1_MASK (0xff << 8) |
#define POWERMODE2(x) ((x) << 16) |
#define POWERMODE2_MASK (0xff << 16) |
#define POWERMODE3(x) ((x) << 24) |
#define POWERMODE3_MASK (0xff << 24) |
#define CGTS_SM_CTRL_REG 0x9150 |
/* Registers */ |
#define CB_COLOR0_BASE 0x28040 |
#define CB_COLOR1_BASE 0x28044 |
157,10 → 404,23 |
#define GUI_ACTIVE (1<<31) |
#define GRBM_STATUS2 0x8014 |
#define CG_CLKPIN_CNTL 0x660 |
# define MUX_TCLK_TO_XCLK (1 << 8) |
# define XTALIN_DIVIDE (1 << 9) |
#define CG_THERMAL_CTRL 0x72C |
#define DPM_EVENT_SRC(x) ((x) << 0) |
#define DPM_EVENT_SRC_MASK (7 << 0) |
#define DIG_THERM_DPM(x) ((x) << 14) |
#define DIG_THERM_DPM_MASK 0x003FC000 |
#define DIG_THERM_DPM_SHIFT 14 |
#define CG_THERMAL_INT 0x734 |
#define DIG_THERM_INTH(x) ((x) << 8) |
#define DIG_THERM_INTH_MASK 0x0000FF00 |
#define DIG_THERM_INTH_SHIFT 8 |
#define DIG_THERM_INTL(x) ((x) << 16) |
#define DIG_THERM_INTL_MASK 0x00FF0000 |
#define DIG_THERM_INTL_SHIFT 16 |
#define THERM_INT_MASK_HIGH (1 << 24) |
#define THERM_INT_MASK_LOW (1 << 25) |
#define CG_MULT_THERMAL_STATUS 0x740 |
#define ASIC_T(x) ((x) << 16) |
#define ASIC_T_MASK 0x3FF0000 |
599,7 → 859,7 |
#define AFMT_VBI_PACKET_CONTROL 0x7608 |
# define AFMT_GENERIC0_UPDATE (1 << 2) |
#define AFMT_INFOFRAME_CONTROL0 0x760c |
# define AFMT_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hmdi regs */ |
# define AFMT_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hdmi regs */ |
# define AFMT_AUDIO_INFO_UPDATE (1 << 7) |
# define AFMT_MPEG_INFO_UPDATE (1 << 10) |
#define AFMT_GENERIC0_7 0x7610 |
662,7 → 922,22 |
#define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c |
#define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c |
/* PCIE link stuff */ |
/* PCIE indirect regs */ |
#define PCIE_P_CNTL 0x40 |
# define P_PLL_PWRDN_IN_L1L23 (1 << 3) |
# define P_PLL_BUF_PDNB (1 << 4) |
# define P_PLL_PDNB (1 << 9) |
# define P_ALLOW_PRX_FRONTEND_SHUTOFF (1 << 12) |
/* PCIE PORT regs */ |
#define PCIE_LC_CNTL 0xa0 |
# define LC_L0S_INACTIVITY(x) ((x) << 8) |
# define LC_L0S_INACTIVITY_MASK (0xf << 8) |
# define LC_L0S_INACTIVITY_SHIFT 8 |
# define LC_L1_INACTIVITY(x) ((x) << 12) |
# define LC_L1_INACTIVITY_MASK (0xf << 12) |
# define LC_L1_INACTIVITY_SHIFT 12 |
# define LC_PMI_TO_L1_DIS (1 << 16) |
# define LC_ASPM_TO_L1_DIS (1 << 24) |
#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */ |
#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ |
# define LC_LINK_WIDTH_SHIFT 0 |
690,6 → 965,9 |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 |
# define LC_CURRENT_DATA_RATE (1 << 11) |
# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12) |
# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12 |
# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) |
# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) |
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) |
700,7 → 978,21 |
# define TARGET_LINK_SPEED_MASK (0xf << 0) |
# define SELECTABLE_DEEMPHASIS (1 << 6) |
/* |
* PM4 |
*/ |
#define PACKET0(reg, n) ((RADEON_PACKET_TYPE0 << 30) | \ |
(((reg) >> 2) & 0xFFFF) | \ |
((n) & 0x3FFF) << 16) |
#define PACKET3(op, n) ((RADEON_PACKET_TYPE3 << 30) | \ |
(((op) & 0xFF) << 8) | \ |
((n) & 0x3FFF) << 16) |
/* UVD */ |
#define UVD_GPCOM_VCPU_CMD 0xef0c |
#define UVD_GPCOM_VCPU_DATA0 0xef10 |
#define UVD_GPCOM_VCPU_DATA1 0xef14 |
#define UVD_LMI_EXT40_ADDR 0xf498 |
#define UVD_VCPU_CHIP_ID 0xf4d4 |
#define UVD_VCPU_CACHE_OFFSET0 0xf4d8 |
714,4 → 1006,6 |
#define UVD_RBC_RB_RPTR 0xf690 |
#define UVD_RBC_RB_WPTR 0xf694 |
#define UVD_CONTEXT_ID 0xf6f4 |
#endif |
/drivers/video/drm/radeon/si.c |
---|
22,7 → 22,6 |
* Authors: Alex Deucher |
*/ |
#include <linux/firmware.h> |
//#include <linux/platform_device.h> |
#include <linux/slab.h> |
#include <linux/module.h> |
#include <drm/drmP.h> |
32,40 → 31,90 |
#include "sid.h" |
#include "atom.h" |
#include "si_blit_shaders.h" |
#include "clearstate_si.h" |
#include "radeon_ucode.h" |
#define SI_PFP_UCODE_SIZE 2144 |
#define SI_PM4_UCODE_SIZE 2144 |
#define SI_CE_UCODE_SIZE 2144 |
#define SI_RLC_UCODE_SIZE 2048 |
#define SI_MC_UCODE_SIZE 7769 |
#define OLAND_MC_UCODE_SIZE 7863 |
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/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_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/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_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/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_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/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_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"); |
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_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); |
extern int sumo_rlc_init(struct radeon_device *rdev); |
extern int r600_ih_ring_alloc(struct radeon_device *rdev); |
extern void r600_ih_ring_fini(struct radeon_device *rdev); |
extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev); |
74,7 → 123,236 |
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); |
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[] = |
{ |
(0x8000 << 16) | (0x98f4 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x98f4 >> 2), |
0x00000000, |
(0x8000 << 16) | (0xe80 >> 2), |
0x00000000, |
(0x8040 << 16) | (0xe80 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x89bc >> 2), |
0x00000000, |
(0x8040 << 16) | (0x89bc >> 2), |
0x00000000, |
(0x8000 << 16) | (0x8c1c >> 2), |
0x00000000, |
(0x8040 << 16) | (0x8c1c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x98f0 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0xe7c >> 2), |
0x00000000, |
(0x8000 << 16) | (0x9148 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x9148 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9150 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x897c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8d8c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0xac54 >> 2), |
0X00000000, |
0x3, |
(0x9c00 << 16) | (0x98f8 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9910 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9914 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9918 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x991c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9920 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9924 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9928 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x992c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9930 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9934 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9938 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x993c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9940 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9944 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9948 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x994c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9950 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9954 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9958 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x995c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9960 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9964 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9968 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x996c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9970 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9974 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9978 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x997c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9980 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9984 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9988 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x998c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8c00 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8c14 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8c04 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8c08 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x9b7c >> 2), |
0x00000000, |
(0x8040 << 16) | (0x9b7c >> 2), |
0x00000000, |
(0x8000 << 16) | (0xe84 >> 2), |
0x00000000, |
(0x8040 << 16) | (0xe84 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x89c0 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x89c0 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x914c >> 2), |
0x00000000, |
(0x8040 << 16) | (0x914c >> 2), |
0x00000000, |
(0x8000 << 16) | (0x8c20 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x8c20 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x9354 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x9354 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9060 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9364 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9100 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x913c >> 2), |
0x00000000, |
(0x8000 << 16) | (0x90e0 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x90e4 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x90e8 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x90e0 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x90e4 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x90e8 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8bcc >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8b24 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x88c4 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8e50 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8c0c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8e58 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8e5c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9508 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x950c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9494 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0xac0c >> 2), |
0x00000000, |
(0x9c00 << 16) | (0xac10 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0xac14 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0xae00 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0xac08 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x88d4 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x88c8 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x88cc >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x89b0 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8b10 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x8a14 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9830 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9834 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9838 >> 2), |
0x00000000, |
(0x9c00 << 16) | (0x9a10 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x9870 >> 2), |
0x00000000, |
(0x8000 << 16) | (0x9874 >> 2), |
0x00000000, |
(0x8001 << 16) | (0x9870 >> 2), |
0x00000000, |
(0x8001 << 16) | (0x9874 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x9870 >> 2), |
0x00000000, |
(0x8040 << 16) | (0x9874 >> 2), |
0x00000000, |
(0x8041 << 16) | (0x9870 >> 2), |
0x00000000, |
(0x8041 << 16) | (0x9874 >> 2), |
0x00000000, |
0x00000000 |
}; |
static const u32 tahiti_golden_rlc_registers[] = |
{ |
0xc424, 0xffffffff, 0x00601005, |
1229,44 → 1507,57 |
}; |
/* 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; |
const __be32 *fw_data = NULL; |
const __le32 *new_fw_data = NULL; |
u32 running, blackout = 0; |
u32 *io_mc_regs; |
int i, ucode_size, regs_size; |
u32 *io_mc_regs = NULL; |
const __le32 *new_io_mc_regs = NULL; |
int i, regs_size, ucode_size; |
if (!rdev->mc_fw) |
return -EINVAL; |
if (rdev->new_fw) { |
const struct mc_firmware_header_v1_0 *hdr = |
(const struct mc_firmware_header_v1_0 *)rdev->mc_fw->data; |
radeon_ucode_print_mc_hdr(&hdr->header); |
regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2); |
new_io_mc_regs = (const __le32 *) |
(rdev->mc_fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); |
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; |
new_fw_data = (const __le32 *) |
(rdev->mc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
} else { |
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; |
} |
fw_data = (const __be32 *)rdev->mc_fw->data; |
} |
running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; |
1282,13 → 1573,21 |
/* load mc io regs */ |
for (i = 0; i < regs_size; i++) { |
if (rdev->new_fw) { |
WREG32(MC_SEQ_IO_DEBUG_INDEX, le32_to_cpup(new_io_mc_regs++)); |
WREG32(MC_SEQ_IO_DEBUG_DATA, le32_to_cpup(new_io_mc_regs++)); |
} else { |
WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]); |
WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); |
} |
} |
/* load the MC ucode */ |
fw_data = (const __be32 *)rdev->mc_fw->data; |
for (i = 0; i < ucode_size; i++) |
for (i = 0; i < ucode_size; i++) { |
if (rdev->new_fw) |
WREG32(MC_SEQ_SUP_PGM, le32_to_cpup(new_fw_data++)); |
else |
WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++)); |
} |
/* put the engine back into the active state */ |
WREG32(MC_SEQ_SUP_CNTL, 0x00000008); |
1316,75 → 1615,80 |
static int si_init_microcode(struct radeon_device *rdev) |
{ |
struct platform_device *pdev; |
const char *chip_name; |
const char *rlc_chip_name; |
const char *new_chip_name; |
size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size; |
size_t smc_req_size, mc2_req_size; |
char fw_name[30]; |
int err; |
int new_fw = 0; |
DRM_DEBUG("\n"); |
pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); |
err = IS_ERR(pdev); |
if (err) { |
printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); |
return -EINVAL; |
} |
switch (rdev->family) { |
case CHIP_TAHITI: |
chip_name = "TAHITI"; |
rlc_chip_name = "TAHITI"; |
new_chip_name = "tahiti"; |
pfp_req_size = SI_PFP_UCODE_SIZE * 4; |
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 = 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: |
chip_name = "PITCAIRN"; |
rlc_chip_name = "PITCAIRN"; |
new_chip_name = "pitcairn"; |
pfp_req_size = SI_PFP_UCODE_SIZE * 4; |
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 = 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: |
chip_name = "VERDE"; |
rlc_chip_name = "VERDE"; |
new_chip_name = "verde"; |
pfp_req_size = SI_PFP_UCODE_SIZE * 4; |
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 = 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: |
chip_name = "OLAND"; |
rlc_chip_name = "OLAND"; |
new_chip_name = "oland"; |
pfp_req_size = SI_PFP_UCODE_SIZE * 4; |
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: |
chip_name = "HAINAN"; |
rlc_chip_name = "HAINAN"; |
new_chip_name = "hainan"; |
pfp_req_size = SI_PFP_UCODE_SIZE * 4; |
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(); |
} |
DRM_INFO("Loading %s Microcode\n", chip_name); |
DRM_INFO("Loading %s Microcode\n", new_chip_name); |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", new_chip_name); |
err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); |
err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->pfp_fw->size != pfp_req_size) { |
1394,9 → 1698,23 |
err = -EINVAL; |
goto out; |
} |
} else { |
err = radeon_ucode_validate(rdev->pfp_fw); |
if (err) { |
printk(KERN_ERR |
"si_cp: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", new_chip_name); |
err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); |
err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->me_fw->size != me_req_size) { |
1405,9 → 1723,23 |
rdev->me_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->me_fw); |
if (err) { |
printk(KERN_ERR |
"si_cp: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", new_chip_name); |
err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); |
err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->ce_fw->size != ce_req_size) { |
1416,9 → 1748,23 |
rdev->ce_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->ce_fw); |
if (err) { |
printk(KERN_ERR |
"si_cp: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); |
err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", new_chip_name); |
err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); |
err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->rlc_fw->size != rlc_req_size) { |
1427,21 → 1773,88 |
rdev->rlc_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->rlc_fw); |
if (err) { |
printk(KERN_ERR |
"si_cp: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name); |
err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name); |
err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); |
err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); |
err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); |
if (err) |
goto out; |
if (rdev->mc_fw->size != mc_req_size) { |
} |
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); |
} else { |
err = radeon_ucode_validate(rdev->mc_fw); |
if (err) { |
printk(KERN_ERR |
"si_cp: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", new_chip_name); |
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); |
if (err) { |
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); |
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); |
if (err) { |
printk(KERN_ERR |
"smc: error loading firmware \"%s\"\n", |
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", |
rdev->smc_fw->size, fw_name); |
err = -EINVAL; |
} |
} else { |
err = radeon_ucode_validate(rdev->smc_fw); |
if (err) { |
printk(KERN_ERR |
"si_cp: validation failed for firmware \"%s\"\n", |
fw_name); |
goto out; |
} else { |
new_fw++; |
} |
} |
if (new_fw == 0) { |
rdev->new_fw = false; |
} else if (new_fw < 6) { |
printk(KERN_ERR "si_fw: mixing new and old firmware!\n"); |
err = -EINVAL; |
} else { |
rdev->new_fw = true; |
} |
out: |
platform_device_unregister(pdev); |
if (err) { |
if (err != -EINVAL) |
printk(KERN_ERR |
1457,6 → 1870,8 |
rdev->rlc_fw = NULL; |
release_firmware(rdev->mc_fw); |
rdev->mc_fw = NULL; |
release_firmware(rdev->smc_fw); |
rdev->smc_fw = NULL; |
} |
return err; |
} |
1467,7 → 1882,8 |
struct drm_display_mode *mode, |
struct drm_display_mode *other_mode) |
{ |
u32 tmp; |
u32 tmp, buffer_alloc, i; |
u32 pipe_offset = radeon_crtc->crtc_id * 0x20; |
/* |
* Line Buffer Setup |
* There are 3 line buffers, each one shared by 2 display controllers. |
1482,16 → 1898,30 |
* non-linked crtcs for maximum line buffer allocation. |
*/ |
if (radeon_crtc->base.enabled && mode) { |
if (other_mode) |
if (other_mode) { |
tmp = 0; /* 1/2 */ |
else |
buffer_alloc = 1; |
} else { |
tmp = 2; /* whole */ |
} else |
buffer_alloc = 2; |
} |
} else { |
tmp = 0; |
buffer_alloc = 0; |
} |
WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, |
DC_LB_MEMORY_CONFIG(tmp)); |
WREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset, |
DMIF_BUFFERS_ALLOCATED(buffer_alloc)); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(PIPE0_DMIF_BUFFER_CONTROL + pipe_offset) & |
DMIF_BUFFERS_ALLOCATED_COMPLETED) |
break; |
udelay(1); |
} |
if (radeon_crtc->base.enabled && mode) { |
switch (tmp) { |
case 0: |
1792,7 → 2222,8 |
u32 lb_size, u32 num_heads) |
{ |
struct drm_display_mode *mode = &radeon_crtc->base.mode; |
struct dce6_wm_params wm; |
struct dce6_wm_params wm_low, wm_high; |
u32 dram_channels; |
u32 pixel_period; |
u32 line_time = 0; |
u32 latency_watermark_a = 0, latency_watermark_b = 0; |
1808,43 → 2239,88 |
priority_a_cnt = 0; |
priority_b_cnt = 0; |
wm.yclk = rdev->pm.current_mclk * 10; |
wm.sclk = rdev->pm.current_sclk * 10; |
wm.disp_clk = mode->clock; |
wm.src_width = mode->crtc_hdisplay; |
wm.active_time = mode->crtc_hdisplay * pixel_period; |
wm.blank_time = line_time - wm.active_time; |
wm.interlaced = false; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
wm.interlaced = true; |
wm.vsc = radeon_crtc->vsc; |
wm.vtaps = 1; |
if (radeon_crtc->rmx_type != RMX_OFF) |
wm.vtaps = 2; |
wm.bytes_per_pixel = 4; /* XXX: get this from fb config */ |
wm.lb_size = lb_size; |
if (rdev->family == CHIP_ARUBA) |
wm.dram_channels = evergreen_get_number_of_dram_channels(rdev); |
dram_channels = evergreen_get_number_of_dram_channels(rdev); |
else |
wm.dram_channels = si_get_number_of_dram_channels(rdev); |
wm.num_heads = num_heads; |
dram_channels = si_get_number_of_dram_channels(rdev); |
/* watermark for high clocks */ |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { |
wm_high.yclk = |
radeon_dpm_get_mclk(rdev, false) * 10; |
wm_high.sclk = |
radeon_dpm_get_sclk(rdev, false) * 10; |
} else { |
wm_high.yclk = rdev->pm.current_mclk * 10; |
wm_high.sclk = rdev->pm.current_sclk * 10; |
} |
wm_high.disp_clk = mode->clock; |
wm_high.src_width = mode->crtc_hdisplay; |
wm_high.active_time = mode->crtc_hdisplay * pixel_period; |
wm_high.blank_time = line_time - wm_high.active_time; |
wm_high.interlaced = false; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
wm_high.interlaced = true; |
wm_high.vsc = radeon_crtc->vsc; |
wm_high.vtaps = 1; |
if (radeon_crtc->rmx_type != RMX_OFF) |
wm_high.vtaps = 2; |
wm_high.bytes_per_pixel = 4; /* XXX: get this from fb config */ |
wm_high.lb_size = lb_size; |
wm_high.dram_channels = dram_channels; |
wm_high.num_heads = num_heads; |
/* watermark for low clocks */ |
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { |
wm_low.yclk = |
radeon_dpm_get_mclk(rdev, true) * 10; |
wm_low.sclk = |
radeon_dpm_get_sclk(rdev, true) * 10; |
} else { |
wm_low.yclk = rdev->pm.current_mclk * 10; |
wm_low.sclk = rdev->pm.current_sclk * 10; |
} |
wm_low.disp_clk = mode->clock; |
wm_low.src_width = mode->crtc_hdisplay; |
wm_low.active_time = mode->crtc_hdisplay * pixel_period; |
wm_low.blank_time = line_time - wm_low.active_time; |
wm_low.interlaced = false; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
wm_low.interlaced = true; |
wm_low.vsc = radeon_crtc->vsc; |
wm_low.vtaps = 1; |
if (radeon_crtc->rmx_type != RMX_OFF) |
wm_low.vtaps = 2; |
wm_low.bytes_per_pixel = 4; /* XXX: get this from fb config */ |
wm_low.lb_size = lb_size; |
wm_low.dram_channels = dram_channels; |
wm_low.num_heads = num_heads; |
/* set for high clocks */ |
latency_watermark_a = min(dce6_latency_watermark(&wm), (u32)65535); |
latency_watermark_a = min(dce6_latency_watermark(&wm_high), (u32)65535); |
/* set for low clocks */ |
/* wm.yclk = low clk; wm.sclk = low clk */ |
latency_watermark_b = min(dce6_latency_watermark(&wm), (u32)65535); |
latency_watermark_b = min(dce6_latency_watermark(&wm_low), (u32)65535); |
/* possibly force display priority to high */ |
/* should really do this at mode validation time... */ |
if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm) || |
!dce6_average_bandwidth_vs_available_bandwidth(&wm) || |
!dce6_check_latency_hiding(&wm) || |
if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) || |
!dce6_average_bandwidth_vs_available_bandwidth(&wm_high) || |
!dce6_check_latency_hiding(&wm_high) || |
(rdev->disp_priority == 2)) { |
DRM_DEBUG_KMS("force priority to high\n"); |
priority_a_cnt |= PRIORITY_ALWAYS_ON; |
priority_b_cnt |= PRIORITY_ALWAYS_ON; |
} |
if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) || |
!dce6_average_bandwidth_vs_available_bandwidth(&wm_low) || |
!dce6_check_latency_hiding(&wm_low) || |
(rdev->disp_priority == 2)) { |
DRM_DEBUG_KMS("force priority to high\n"); |
priority_a_cnt |= PRIORITY_ALWAYS_ON; |
priority_b_cnt |= PRIORITY_ALWAYS_ON; |
} |
a.full = dfixed_const(1000); |
b.full = dfixed_const(mode->clock); |
1895,6 → 2371,10 |
WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt); |
WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt); |
/* save values for DPM */ |
radeon_crtc->line_time = line_time; |
radeon_crtc->wm_high = latency_watermark_a; |
radeon_crtc->wm_low = latency_watermark_b; |
} |
void dce6_bandwidth_update(struct radeon_device *rdev) |
2501,7 → 2981,7 |
} |
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; |
2515,7 → 2995,7 |
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; |
} |
2522,7 → 3002,7 |
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; |
2532,7 → 3012,7 |
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); |
} |
} |
2539,12 → 3019,14 |
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; |
2773,6 → 3255,13 |
rdev->config.si.max_sh_per_se, |
rdev->config.si.max_cu_per_sh); |
rdev->config.si.active_cus = 0; |
for (i = 0; i < rdev->config.si.max_shader_engines; i++) { |
for (j = 0; j < rdev->config.si.max_sh_per_se; j++) { |
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) | |
2861,7 → 3350,7 |
/* 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); |
2894,7 → 3383,7 |
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); |
} |
2935,6 → 3424,7 |
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)); |
WREG32(SCRATCH_UMSK, 0); |
2947,15 → 3437,57 |
static int si_cp_load_microcode(struct radeon_device *rdev) |
{ |
const __be32 *fw_data; |
int i; |
if (!rdev->me_fw || !rdev->pfp_fw) |
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw) |
return -EINVAL; |
si_cp_enable(rdev, false); |
if (rdev->new_fw) { |
const struct gfx_firmware_header_v1_0 *pfp_hdr = |
(const struct gfx_firmware_header_v1_0 *)rdev->pfp_fw->data; |
const struct gfx_firmware_header_v1_0 *ce_hdr = |
(const struct gfx_firmware_header_v1_0 *)rdev->ce_fw->data; |
const struct gfx_firmware_header_v1_0 *me_hdr = |
(const struct gfx_firmware_header_v1_0 *)rdev->me_fw->data; |
const __le32 *fw_data; |
u32 fw_size; |
radeon_ucode_print_gfx_hdr(&pfp_hdr->header); |
radeon_ucode_print_gfx_hdr(&ce_hdr->header); |
radeon_ucode_print_gfx_hdr(&me_hdr->header); |
/* PFP */ |
fw_data = (const __le32 *) |
(rdev->pfp_fw->data + le32_to_cpu(pfp_hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(pfp_hdr->header.ucode_size_bytes) / 4; |
WREG32(CP_PFP_UCODE_ADDR, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(CP_PFP_UCODE_DATA, le32_to_cpup(fw_data++)); |
WREG32(CP_PFP_UCODE_ADDR, 0); |
/* CE */ |
fw_data = (const __le32 *) |
(rdev->ce_fw->data + le32_to_cpu(ce_hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(ce_hdr->header.ucode_size_bytes) / 4; |
WREG32(CP_CE_UCODE_ADDR, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(CP_CE_UCODE_DATA, le32_to_cpup(fw_data++)); |
WREG32(CP_CE_UCODE_ADDR, 0); |
/* ME */ |
fw_data = (const __be32 *) |
(rdev->me_fw->data + le32_to_cpu(me_hdr->header.ucode_array_offset_bytes)); |
fw_size = le32_to_cpu(me_hdr->header.ucode_size_bytes) / 4; |
WREG32(CP_ME_RAM_WADDR, 0); |
for (i = 0; i < fw_size; i++) |
WREG32(CP_ME_RAM_DATA, le32_to_cpup(fw_data++)); |
WREG32(CP_ME_RAM_WADDR, 0); |
} else { |
const __be32 *fw_data; |
/* PFP */ |
fw_data = (const __be32 *)rdev->pfp_fw->data; |
WREG32(CP_PFP_UCODE_ADDR, 0); |
for (i = 0; i < SI_PFP_UCODE_SIZE; i++) |
2975,6 → 3507,7 |
for (i = 0; i < SI_PM4_UCODE_SIZE; i++) |
WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); |
WREG32(CP_ME_RAM_WADDR, 0); |
} |
WREG32(CP_PFP_UCODE_ADDR, 0); |
WREG32(CP_CE_UCODE_ADDR, 0); |
3007,7 → 3540,7 |
radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE)); |
radeon_ring_write(ring, 0xc000); |
radeon_ring_write(ring, 0xe000); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
si_cp_enable(rdev, true); |
3036,7 → 3569,7 |
radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ |
radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */ |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
for (i = RADEON_RING_TYPE_GFX_INDEX; i <= CAYMAN_RING_TYPE_CP2_INDEX; ++i) { |
ring = &rdev->ring[i]; |
3046,7 → 3579,7 |
radeon_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0)); |
radeon_ring_write(ring, 0); |
radeon_ring_unlock_commit(rdev, ring); |
radeon_ring_unlock_commit(rdev, ring, false); |
} |
return 0; |
3057,17 → 3590,17 |
struct radeon_ring *ring; |
si_cp_enable(rdev, false); |
// ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
// radeon_ring_fini(rdev, ring); |
// radeon_scratch_free(rdev, ring->rptr_save_reg); |
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
radeon_ring_fini(rdev, ring); |
radeon_scratch_free(rdev, ring->rptr_save_reg); |
// ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; |
// radeon_ring_fini(rdev, ring); |
// radeon_scratch_free(rdev, ring->rptr_save_reg); |
ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; |
radeon_ring_fini(rdev, ring); |
radeon_scratch_free(rdev, ring->rptr_save_reg); |
// ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; |
// radeon_ring_fini(rdev, ring); |
// radeon_scratch_free(rdev, ring->rptr_save_reg); |
ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; |
radeon_ring_fini(rdev, ring); |
radeon_scratch_free(rdev, ring->rptr_save_reg); |
} |
static int si_cp_resume(struct radeon_device *rdev) |
3077,16 → 3610,7 |
u32 rb_bufsz; |
int r; |
/* Reset cp; if cp is reset, then PA, SH, VGT also need to be reset */ |
WREG32(GRBM_SOFT_RESET, (SOFT_RESET_CP | |
SOFT_RESET_PA | |
SOFT_RESET_VGT | |
SOFT_RESET_SPI | |
SOFT_RESET_SX)); |
RREG32(GRBM_SOFT_RESET); |
mdelay(15); |
WREG32(GRBM_SOFT_RESET, 0); |
RREG32(GRBM_SOFT_RESET); |
si_enable_gui_idle_interrupt(rdev, false); |
WREG32(CP_SEM_WAIT_TIMER, 0x0); |
WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0); |
3100,8 → 3624,8 |
/* ring 0 - compute and gfx */ |
/* Set ring buffer size */ |
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
rb_bufsz = drm_order(ring->ring_size / 8); |
tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
rb_bufsz = order_base_2(ring->ring_size / 8); |
tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
#ifdef __BIG_ENDIAN |
tmp |= BUF_SWAP_32BIT; |
#endif |
3128,13 → 3652,11 |
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]; |
rb_bufsz = drm_order(ring->ring_size / 8); |
tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
rb_bufsz = order_base_2(ring->ring_size / 8); |
tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
#ifdef __BIG_ENDIAN |
tmp |= BUF_SWAP_32BIT; |
#endif |
3154,13 → 3676,11 |
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]; |
rb_bufsz = drm_order(ring->ring_size / 8); |
tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
rb_bufsz = order_base_2(ring->ring_size / 8); |
tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; |
#ifdef __BIG_ENDIAN |
tmp |= BUF_SWAP_32BIT; |
#endif |
3180,8 → 3700,6 |
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; |
3203,10 → 3721,15 |
rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false; |
} |
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; |
} |
static u32 si_gpu_check_soft_reset(struct radeon_device *rdev) |
u32 si_gpu_check_soft_reset(struct radeon_device *rdev) |
{ |
u32 reset_mask = 0; |
u32 tmp; |
3304,6 → 3827,13 |
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); |
3412,6 → 3942,106 |
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; |
3421,10 → 4051,17 |
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); |
3447,42 → 4084,12 |
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); |
} |
/** |
* si_dma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up. |
* Returns true if the engine appears to be locked up, false if not. |
*/ |
bool si_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
u32 reset_mask = si_gpu_check_soft_reset(rdev); |
u32 mask; |
if (ring->idx == R600_RING_TYPE_DMA_INDEX) |
mask = RADEON_RESET_DMA; |
else |
mask = RADEON_RESET_DMA1; |
if (!(reset_mask & mask)) { |
radeon_ring_lockup_update(ring); |
return false; |
} |
/* force ring activities */ |
radeon_ring_force_activity(rdev, ring); |
return radeon_ring_test_lockup(rdev, ring); |
} |
/* MC */ |
static void si_mc_program(struct radeon_device *rdev) |
{ |
3535,7 → 4142,7 |
} |
} |
static void si_vram_gtt_location(struct radeon_device *rdev, |
void si_vram_gtt_location(struct radeon_device *rdev, |
struct radeon_mc *mc) |
{ |
if (mc->mc_vram_size > 0xFFC0000000ULL) { |
3600,8 → 4207,15 |
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); |
3632,16 → 4246,17 |
r = radeon_gart_table_vram_pin(rdev); |
if (r) |
return r; |
radeon_gart_restore(rdev); |
/* Setup TLB control */ |
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) | |
3648,7 → 4263,8 |
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); |
3674,10 → 4290,10 |
for (i = 1; i < 16; i++) { |
if (i < 8) |
WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), |
rdev->gart.table_addr >> 12); |
rdev->vm_manager.saved_table_addr[i]); |
else |
WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2), |
rdev->gart.table_addr >> 12); |
rdev->vm_manager.saved_table_addr[i]); |
} |
/* enable context1-15 */ |
3685,6 → 4301,7 |
(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 | |
3708,6 → 4325,17 |
static void si_pcie_gart_disable(struct radeon_device *rdev) |
{ |
unsigned i; |
for (i = 1; i < 16; ++i) { |
uint32_t reg; |
if (i < 8) |
reg = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2); |
else |
reg = VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2); |
rdev->vm_manager.saved_table_addr[i] = RREG32(reg); |
} |
/* Disable all tables */ |
WREG32(VM_CONTEXT0_CNTL, 0); |
WREG32(VM_CONTEXT1_CNTL, 0); |
3796,13 → 4424,64 |
return 0; |
} |
static int si_vm_packet3_cp_dma_check(u32 *ib, u32 idx) |
{ |
u32 start_reg, reg, i; |
u32 command = ib[idx + 4]; |
u32 info = ib[idx + 1]; |
u32 idx_value = ib[idx]; |
if (command & PACKET3_CP_DMA_CMD_SAS) { |
/* src address space is register */ |
if (((info & 0x60000000) >> 29) == 0) { |
start_reg = idx_value << 2; |
if (command & PACKET3_CP_DMA_CMD_SAIC) { |
reg = start_reg; |
if (!si_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad SRC register\n"); |
return -EINVAL; |
} |
} else { |
for (i = 0; i < (command & 0x1fffff); i++) { |
reg = start_reg + (4 * i); |
if (!si_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad SRC register\n"); |
return -EINVAL; |
} |
} |
} |
} |
} |
if (command & PACKET3_CP_DMA_CMD_DAS) { |
/* dst address space is register */ |
if (((info & 0x00300000) >> 20) == 0) { |
start_reg = ib[idx + 2]; |
if (command & PACKET3_CP_DMA_CMD_DAIC) { |
reg = start_reg; |
if (!si_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad DST register\n"); |
return -EINVAL; |
} |
} else { |
for (i = 0; i < (command & 0x1fffff); i++) { |
reg = start_reg + (4 * i); |
if (!si_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad DST register\n"); |
return -EINVAL; |
} |
} |
} |
} |
} |
return 0; |
} |
static int si_vm_packet3_gfx_check(struct radeon_device *rdev, |
u32 *ib, struct radeon_cs_packet *pkt) |
{ |
int r; |
u32 idx = pkt->idx + 1; |
u32 idx_value = ib[idx]; |
u32 start_reg, end_reg, reg, i; |
u32 command, info; |
switch (pkt->opcode) { |
case PACKET3_NOP: |
3903,50 → 4582,9 |
} |
break; |
case PACKET3_CP_DMA: |
command = ib[idx + 4]; |
info = ib[idx + 1]; |
if (command & PACKET3_CP_DMA_CMD_SAS) { |
/* src address space is register */ |
if (((info & 0x60000000) >> 29) == 0) { |
start_reg = idx_value << 2; |
if (command & PACKET3_CP_DMA_CMD_SAIC) { |
reg = start_reg; |
if (!si_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad SRC register\n"); |
return -EINVAL; |
} |
} else { |
for (i = 0; i < (command & 0x1fffff); i++) { |
reg = start_reg + (4 * i); |
if (!si_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad SRC register\n"); |
return -EINVAL; |
} |
} |
} |
} |
} |
if (command & PACKET3_CP_DMA_CMD_DAS) { |
/* dst address space is register */ |
if (((info & 0x00300000) >> 20) == 0) { |
start_reg = ib[idx + 2]; |
if (command & PACKET3_CP_DMA_CMD_DAIC) { |
reg = start_reg; |
if (!si_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad DST register\n"); |
return -EINVAL; |
} |
} else { |
for (i = 0; i < (command & 0x1fffff); i++) { |
reg = start_reg + (4 * i); |
if (!si_vm_reg_valid(reg)) { |
DRM_ERROR("CP DMA Bad DST register\n"); |
return -EINVAL; |
} |
} |
} |
} |
} |
r = si_vm_packet3_cp_dma_check(ib, idx); |
if (r) |
return r; |
break; |
default: |
DRM_ERROR("Invalid GFX packet3: 0x%x\n", pkt->opcode); |
3958,6 → 4596,7 |
static int si_vm_packet3_compute_check(struct radeon_device *rdev, |
u32 *ib, struct radeon_cs_packet *pkt) |
{ |
int r; |
u32 idx = pkt->idx + 1; |
u32 idx_value = ib[idx]; |
u32 start_reg, reg, i; |
4030,6 → 4669,11 |
return -EINVAL; |
} |
break; |
case PACKET3_CP_DMA: |
r = si_vm_packet3_cp_dma_check(ib, idx); |
if (r) |
return r; |
break; |
default: |
DRM_ERROR("Invalid Compute packet3: 0x%x\n", pkt->opcode); |
return -EINVAL; |
4107,110 → 4751,268 |
} |
/** |
* si_vm_set_page - update the page tables using the CP |
* si_vm_decode_fault - print human readable fault info |
* |
* @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 |
* @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value |
* @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value |
* |
* Update the page tables using the CP (SI). |
* Print human readable fault information (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) |
static void si_vm_decode_fault(struct radeon_device *rdev, |
u32 status, u32 addr) |
{ |
uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); |
uint64_t value; |
unsigned ndw; |
u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; |
u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT; |
u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT; |
char *block; |
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; |
if (rdev->family == CHIP_TAHITI) { |
switch (mc_id) { |
case 160: |
case 144: |
case 96: |
case 80: |
case 224: |
case 208: |
case 32: |
case 16: |
block = "CB"; |
break; |
case 161: |
case 145: |
case 97: |
case 81: |
case 225: |
case 209: |
case 33: |
case 17: |
block = "CB_FMASK"; |
break; |
case 162: |
case 146: |
case 98: |
case 82: |
case 226: |
case 210: |
case 34: |
case 18: |
block = "CB_CMASK"; |
break; |
case 163: |
case 147: |
case 99: |
case 83: |
case 227: |
case 211: |
case 35: |
case 19: |
block = "CB_IMMED"; |
break; |
case 164: |
case 148: |
case 100: |
case 84: |
case 228: |
case 212: |
case 36: |
case 20: |
block = "DB"; |
break; |
case 165: |
case 149: |
case 101: |
case 85: |
case 229: |
case 213: |
case 37: |
case 21: |
block = "DB_HTILE"; |
break; |
case 167: |
case 151: |
case 103: |
case 87: |
case 231: |
case 215: |
case 39: |
case 23: |
block = "DB_STEN"; |
break; |
case 72: |
case 68: |
case 64: |
case 8: |
case 4: |
case 0: |
case 136: |
case 132: |
case 128: |
case 200: |
case 196: |
case 192: |
block = "TC"; |
break; |
case 112: |
case 48: |
block = "CP"; |
break; |
case 49: |
case 177: |
case 50: |
case 178: |
block = "SH"; |
break; |
case 53: |
case 190: |
block = "VGT"; |
break; |
case 117: |
block = "IH"; |
break; |
case 51: |
case 115: |
block = "RLC"; |
break; |
case 119: |
case 183: |
block = "DMA0"; |
break; |
case 61: |
block = "DMA1"; |
break; |
case 248: |
case 120: |
block = "HDP"; |
break; |
default: |
block = "unknown"; |
break; |
} |
addr += incr; |
value |= r600_flags; |
ib->ptr[ib->length_dw++] = value; |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
} |
} |
} else { |
/* DMA */ |
if (flags & RADEON_VM_PAGE_SYSTEM) { |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
/* for non-physically contiguous pages (system) */ |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, ndw); |
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; |
switch (mc_id) { |
case 32: |
case 16: |
case 96: |
case 80: |
case 160: |
case 144: |
case 224: |
case 208: |
block = "CB"; |
break; |
case 33: |
case 17: |
case 97: |
case 81: |
case 161: |
case 145: |
case 225: |
case 209: |
block = "CB_FMASK"; |
break; |
case 34: |
case 18: |
case 98: |
case 82: |
case 162: |
case 146: |
case 226: |
case 210: |
block = "CB_CMASK"; |
break; |
case 35: |
case 19: |
case 99: |
case 83: |
case 163: |
case 147: |
case 227: |
case 211: |
block = "CB_IMMED"; |
break; |
case 36: |
case 20: |
case 100: |
case 84: |
case 164: |
case 148: |
case 228: |
case 212: |
block = "DB"; |
break; |
case 37: |
case 21: |
case 101: |
case 85: |
case 165: |
case 149: |
case 229: |
case 213: |
block = "DB_HTILE"; |
break; |
case 39: |
case 23: |
case 103: |
case 87: |
case 167: |
case 151: |
case 231: |
case 215: |
block = "DB_STEN"; |
break; |
case 72: |
case 68: |
case 8: |
case 4: |
case 136: |
case 132: |
case 200: |
case 196: |
block = "TC"; |
break; |
case 112: |
case 48: |
block = "CP"; |
break; |
case 49: |
case 177: |
case 50: |
case 178: |
block = "SH"; |
break; |
case 53: |
block = "VGT"; |
break; |
case 117: |
block = "IH"; |
break; |
case 51: |
case 115: |
block = "RLC"; |
break; |
case 119: |
case 183: |
block = "DMA0"; |
break; |
case 61: |
block = "DMA1"; |
break; |
case 248: |
case 120: |
block = "HDP"; |
break; |
default: |
block = "unknown"; |
break; |
} |
addr += incr; |
value |= r600_flags; |
ib->ptr[ib->length_dw++] = value; |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
} |
} |
} else { |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
if (flags & RADEON_VM_PAGE_VALID) |
value = addr; |
else |
value = 0; |
/* for physically contiguous pages (vram) */ |
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++] = 0; |
ib->ptr[ib->length_dw++] = value; /* value */ |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
ib->ptr[ib->length_dw++] = incr; /* increment size */ |
ib->ptr[ib->length_dw++] = 0; |
pe += ndw * 4; |
addr += (ndw / 2) * incr; |
count -= ndw / 2; |
printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n", |
protections, vmid, addr, |
(status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", |
block, mc_id); |
} |
} |
while (ib->length_dw & 0x7) |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0); |
} |
} |
void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) |
{ |
4221,7 → 5023,7 |
/* write new base address */ |
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | |
WRITE_DATA_DST_SEL(0))); |
if (vm->id < 8) { |
4236,7 → 5038,7 |
/* flush hdp cache */ |
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | |
WRITE_DATA_DST_SEL(0))); |
radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); |
radeon_ring_write(ring, 0); |
4244,7 → 5046,7 |
/* bits 0-15 are the VM contexts0-15 */ |
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | |
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | |
WRITE_DATA_DST_SEL(0))); |
radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); |
radeon_ring_write(ring, 0); |
4255,135 → 5057,749 |
radeon_ring_write(ring, 0x0); |
} |
void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) |
/* |
* Power and clock gating |
*/ |
static void si_wait_for_rlc_serdes(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[ridx]; |
int i; |
if (vm == NULL) |
return; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(RLC_SERDES_MASTER_BUSY_0) == 0) |
break; |
udelay(1); |
} |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); |
if (vm->id < 8) { |
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2)); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(RLC_SERDES_MASTER_BUSY_1) == 0) |
break; |
udelay(1); |
} |
} |
static void si_enable_gui_idle_interrupt(struct radeon_device *rdev, |
bool enable) |
{ |
u32 tmp = RREG32(CP_INT_CNTL_RING0); |
u32 mask; |
int i; |
if (enable) |
tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
else |
tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
WREG32(CP_INT_CNTL_RING0, tmp); |
if (!enable) { |
/* read a gfx register */ |
tmp = RREG32(DB_DEPTH_INFO); |
mask = RLC_BUSY_STATUS | GFX_POWER_STATUS | GFX_CLOCK_STATUS | GFX_LS_STATUS; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(RLC_STAT) & mask) == (GFX_CLOCK_STATUS | GFX_POWER_STATUS)) |
break; |
udelay(1); |
} |
} |
} |
static void si_set_uvd_dcm(struct radeon_device *rdev, |
bool sw_mode) |
{ |
u32 tmp, tmp2; |
tmp = RREG32(UVD_CGC_CTRL); |
tmp &= ~(CLK_OD_MASK | CG_DT_MASK); |
tmp |= DCM | CG_DT(1) | CLK_OD(4); |
if (sw_mode) { |
tmp &= ~0x7ffff800; |
tmp2 = DYN_OR_EN | DYN_RR_EN | G_DIV_ID(7); |
} else { |
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2)); |
tmp |= 0x7ffff800; |
tmp2 = 0; |
} |
radeon_ring_write(ring, vm->pd_gpu_addr >> 12); |
/* flush hdp cache */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2)); |
radeon_ring_write(ring, 1); |
WREG32(UVD_CGC_CTRL, tmp); |
WREG32_UVD_CTX(UVD_CGC_CTRL2, tmp2); |
} |
/* bits 0-7 are the VM contexts0-7 */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); |
radeon_ring_write(ring, 1 << vm->id); |
void si_init_uvd_internal_cg(struct radeon_device *rdev) |
{ |
bool hw_mode = true; |
if (hw_mode) { |
si_set_uvd_dcm(rdev, false); |
} else { |
u32 tmp = RREG32(UVD_CGC_CTRL); |
tmp &= ~DCM; |
WREG32(UVD_CGC_CTRL, tmp); |
} |
} |
/* |
* RLC |
*/ |
void si_rlc_fini(struct radeon_device *rdev) |
static u32 si_halt_rlc(struct radeon_device *rdev) |
{ |
int r; |
u32 data, orig; |
/* save restore block */ |
if (rdev->rlc.save_restore_obj) { |
r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false); |
if (unlikely(r != 0)) |
dev_warn(rdev->dev, "(%d) reserve RLC sr bo failed\n", r); |
radeon_bo_unpin(rdev->rlc.save_restore_obj); |
radeon_bo_unreserve(rdev->rlc.save_restore_obj); |
orig = data = RREG32(RLC_CNTL); |
radeon_bo_unref(&rdev->rlc.save_restore_obj); |
rdev->rlc.save_restore_obj = NULL; |
if (data & RLC_ENABLE) { |
data &= ~RLC_ENABLE; |
WREG32(RLC_CNTL, data); |
si_wait_for_rlc_serdes(rdev); |
} |
/* clear state block */ |
if (rdev->rlc.clear_state_obj) { |
r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false); |
if (unlikely(r != 0)) |
dev_warn(rdev->dev, "(%d) reserve RLC c bo failed\n", r); |
radeon_bo_unpin(rdev->rlc.clear_state_obj); |
radeon_bo_unreserve(rdev->rlc.clear_state_obj); |
return orig; |
} |
radeon_bo_unref(&rdev->rlc.clear_state_obj); |
rdev->rlc.clear_state_obj = NULL; |
static void si_update_rlc(struct radeon_device *rdev, u32 rlc) |
{ |
u32 tmp; |
tmp = RREG32(RLC_CNTL); |
if (tmp != rlc) |
WREG32(RLC_CNTL, rlc); |
} |
static void si_enable_dma_pg(struct radeon_device *rdev, bool enable) |
{ |
u32 data, orig; |
orig = data = RREG32(DMA_PG); |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_SDMA)) |
data |= PG_CNTL_ENABLE; |
else |
data &= ~PG_CNTL_ENABLE; |
if (orig != data) |
WREG32(DMA_PG, data); |
} |
int si_rlc_init(struct radeon_device *rdev) |
static void si_init_dma_pg(struct radeon_device *rdev) |
{ |
int r; |
u32 tmp; |
/* save restore block */ |
if (rdev->rlc.save_restore_obj == NULL) { |
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, NULL, |
&rdev->rlc.save_restore_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r); |
return r; |
WREG32(DMA_PGFSM_WRITE, 0x00002000); |
WREG32(DMA_PGFSM_CONFIG, 0x100010ff); |
for (tmp = 0; tmp < 5; tmp++) |
WREG32(DMA_PGFSM_WRITE, 0); |
} |
static void si_enable_gfx_cgpg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 tmp; |
if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG)) { |
tmp = RLC_PUD(0x10) | RLC_PDD(0x10) | RLC_TTPD(0x10) | RLC_MSD(0x10); |
WREG32(RLC_TTOP_D, tmp); |
tmp = RREG32(RLC_PG_CNTL); |
tmp |= GFX_PG_ENABLE; |
WREG32(RLC_PG_CNTL, tmp); |
tmp = RREG32(RLC_AUTO_PG_CTRL); |
tmp |= AUTO_PG_EN; |
WREG32(RLC_AUTO_PG_CTRL, tmp); |
} else { |
tmp = RREG32(RLC_AUTO_PG_CTRL); |
tmp &= ~AUTO_PG_EN; |
WREG32(RLC_AUTO_PG_CTRL, tmp); |
tmp = RREG32(DB_RENDER_CONTROL); |
} |
} |
r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false); |
if (unlikely(r != 0)) { |
si_rlc_fini(rdev); |
return r; |
static void si_init_gfx_cgpg(struct radeon_device *rdev) |
{ |
u32 tmp; |
WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8); |
tmp = RREG32(RLC_PG_CNTL); |
tmp |= GFX_PG_SRC; |
WREG32(RLC_PG_CNTL, tmp); |
WREG32(RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8); |
tmp = RREG32(RLC_AUTO_PG_CTRL); |
tmp &= ~GRBM_REG_SGIT_MASK; |
tmp |= GRBM_REG_SGIT(0x700); |
tmp &= ~PG_AFTER_GRBM_REG_ST_MASK; |
WREG32(RLC_AUTO_PG_CTRL, tmp); |
} |
r = radeon_bo_pin(rdev->rlc.save_restore_obj, RADEON_GEM_DOMAIN_VRAM, |
&rdev->rlc.save_restore_gpu_addr); |
radeon_bo_unreserve(rdev->rlc.save_restore_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) pin RLC sr bo failed\n", r); |
si_rlc_fini(rdev); |
return r; |
static u32 si_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh) |
{ |
u32 mask = 0, tmp, tmp1; |
int i; |
si_select_se_sh(rdev, se, sh); |
tmp = RREG32(CC_GC_SHADER_ARRAY_CONFIG); |
tmp1 = RREG32(GC_USER_SHADER_ARRAY_CONFIG); |
si_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
tmp &= 0xffff0000; |
tmp |= tmp1; |
tmp >>= 16; |
for (i = 0; i < rdev->config.si.max_cu_per_sh; i ++) { |
mask <<= 1; |
mask |= 1; |
} |
/* clear state block */ |
if (rdev->rlc.clear_state_obj == NULL) { |
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, |
RADEON_GEM_DOMAIN_VRAM, NULL, |
&rdev->rlc.clear_state_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r); |
si_rlc_fini(rdev); |
return r; |
return (~tmp) & mask; |
} |
static void si_init_ao_cu_mask(struct radeon_device *rdev) |
{ |
u32 i, j, k, active_cu_number = 0; |
u32 mask, counter, cu_bitmap; |
u32 tmp = 0; |
for (i = 0; i < rdev->config.si.max_shader_engines; i++) { |
for (j = 0; j < rdev->config.si.max_sh_per_se; j++) { |
mask = 1; |
cu_bitmap = 0; |
counter = 0; |
for (k = 0; k < rdev->config.si.max_cu_per_sh; k++) { |
if (si_get_cu_active_bitmap(rdev, i, j) & mask) { |
if (counter < 2) |
cu_bitmap |= mask; |
counter++; |
} |
r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false); |
if (unlikely(r != 0)) { |
si_rlc_fini(rdev); |
return r; |
mask <<= 1; |
} |
r = radeon_bo_pin(rdev->rlc.clear_state_obj, RADEON_GEM_DOMAIN_VRAM, |
&rdev->rlc.clear_state_gpu_addr); |
radeon_bo_unreserve(rdev->rlc.clear_state_obj); |
if (r) { |
dev_warn(rdev->dev, "(%d) pin RLC c bo failed\n", r); |
si_rlc_fini(rdev); |
return r; |
active_cu_number += counter; |
tmp |= (cu_bitmap << (i * 16 + j * 8)); |
} |
} |
WREG32(RLC_PG_AO_CU_MASK, tmp); |
tmp = RREG32(RLC_MAX_PG_CU); |
tmp &= ~MAX_PU_CU_MASK; |
tmp |= MAX_PU_CU(active_cu_number); |
WREG32(RLC_MAX_PG_CU, tmp); |
} |
static void si_enable_cgcg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 data, orig, tmp; |
orig = data = RREG32(RLC_CGCG_CGLS_CTRL); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_GFX_CGCG)) { |
si_enable_gui_idle_interrupt(rdev, true); |
WREG32(RLC_GCPM_GENERAL_3, 0x00000080); |
tmp = si_halt_rlc(rdev); |
WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff); |
WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff); |
WREG32(RLC_SERDES_WR_CTRL, 0x00b000ff); |
si_wait_for_rlc_serdes(rdev); |
si_update_rlc(rdev, tmp); |
WREG32(RLC_SERDES_WR_CTRL, 0x007000ff); |
data |= CGCG_EN | CGLS_EN; |
} else { |
si_enable_gui_idle_interrupt(rdev, false); |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
data &= ~(CGCG_EN | CGLS_EN); |
} |
if (orig != data) |
WREG32(RLC_CGCG_CGLS_CTRL, data); |
} |
static void si_enable_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 data, orig, tmp = 0; |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_GFX_MGCG)) { |
orig = data = RREG32(CGTS_SM_CTRL_REG); |
data = 0x96940200; |
if (orig != data) |
WREG32(CGTS_SM_CTRL_REG, data); |
if (rdev->cg_flags & RADEON_CG_SUPPORT_GFX_CP_LS) { |
orig = data = RREG32(CP_MEM_SLP_CNTL); |
data |= CP_MEM_LS_EN; |
if (orig != data) |
WREG32(CP_MEM_SLP_CNTL, data); |
} |
orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE); |
data &= 0xffffffc0; |
if (orig != data) |
WREG32(RLC_CGTT_MGCG_OVERRIDE, data); |
tmp = si_halt_rlc(rdev); |
WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff); |
WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff); |
WREG32(RLC_SERDES_WR_CTRL, 0x00d000ff); |
si_update_rlc(rdev, tmp); |
} else { |
orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE); |
data |= 0x00000003; |
if (orig != data) |
WREG32(RLC_CGTT_MGCG_OVERRIDE, data); |
data = RREG32(CP_MEM_SLP_CNTL); |
if (data & CP_MEM_LS_EN) { |
data &= ~CP_MEM_LS_EN; |
WREG32(CP_MEM_SLP_CNTL, data); |
} |
orig = data = RREG32(CGTS_SM_CTRL_REG); |
data |= LS_OVERRIDE | OVERRIDE; |
if (orig != data) |
WREG32(CGTS_SM_CTRL_REG, data); |
tmp = si_halt_rlc(rdev); |
WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff); |
WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff); |
WREG32(RLC_SERDES_WR_CTRL, 0x00e000ff); |
si_update_rlc(rdev, tmp); |
} |
} |
static void si_enable_uvd_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data, tmp; |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_UVD_MGCG)) { |
tmp = RREG32_UVD_CTX(UVD_CGC_MEM_CTRL); |
tmp |= 0x3fff; |
WREG32_UVD_CTX(UVD_CGC_MEM_CTRL, tmp); |
orig = data = RREG32(UVD_CGC_CTRL); |
data |= DCM; |
if (orig != data) |
WREG32(UVD_CGC_CTRL, data); |
WREG32_SMC(SMC_CG_IND_START + CG_CGTT_LOCAL_0, 0); |
WREG32_SMC(SMC_CG_IND_START + CG_CGTT_LOCAL_1, 0); |
} else { |
tmp = RREG32_UVD_CTX(UVD_CGC_MEM_CTRL); |
tmp &= ~0x3fff; |
WREG32_UVD_CTX(UVD_CGC_MEM_CTRL, tmp); |
orig = data = RREG32(UVD_CGC_CTRL); |
data &= ~DCM; |
if (orig != data) |
WREG32(UVD_CGC_CTRL, data); |
WREG32_SMC(SMC_CG_IND_START + CG_CGTT_LOCAL_0, 0xffffffff); |
WREG32_SMC(SMC_CG_IND_START + CG_CGTT_LOCAL_1, 0xffffffff); |
} |
} |
static const u32 mc_cg_registers[] = |
{ |
MC_HUB_MISC_HUB_CG, |
MC_HUB_MISC_SIP_CG, |
MC_HUB_MISC_VM_CG, |
MC_XPB_CLK_GAT, |
ATC_MISC_CG, |
MC_CITF_MISC_WR_CG, |
MC_CITF_MISC_RD_CG, |
MC_CITF_MISC_VM_CG, |
VM_L2_CG, |
}; |
static void si_enable_mc_ls(struct radeon_device *rdev, |
bool enable) |
{ |
int i; |
u32 orig, data; |
for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) { |
orig = data = RREG32(mc_cg_registers[i]); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_MC_LS)) |
data |= MC_LS_ENABLE; |
else |
data &= ~MC_LS_ENABLE; |
if (data != orig) |
WREG32(mc_cg_registers[i], data); |
} |
} |
static void si_enable_mc_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
int i; |
u32 orig, data; |
for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) { |
orig = data = RREG32(mc_cg_registers[i]); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_MC_MGCG)) |
data |= MC_CG_ENABLE; |
else |
data &= ~MC_CG_ENABLE; |
if (data != orig) |
WREG32(mc_cg_registers[i], data); |
} |
} |
static void si_enable_dma_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data, offset; |
int i; |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_SDMA_MGCG)) { |
for (i = 0; i < 2; i++) { |
if (i == 0) |
offset = DMA0_REGISTER_OFFSET; |
else |
offset = DMA1_REGISTER_OFFSET; |
orig = data = RREG32(DMA_POWER_CNTL + offset); |
data &= ~MEM_POWER_OVERRIDE; |
if (data != orig) |
WREG32(DMA_POWER_CNTL + offset, data); |
WREG32(DMA_CLK_CTRL + offset, 0x00000100); |
} |
} else { |
for (i = 0; i < 2; i++) { |
if (i == 0) |
offset = DMA0_REGISTER_OFFSET; |
else |
offset = DMA1_REGISTER_OFFSET; |
orig = data = RREG32(DMA_POWER_CNTL + offset); |
data |= MEM_POWER_OVERRIDE; |
if (data != orig) |
WREG32(DMA_POWER_CNTL + offset, data); |
orig = data = RREG32(DMA_CLK_CTRL + offset); |
data = 0xff000000; |
if (data != orig) |
WREG32(DMA_CLK_CTRL + offset, data); |
} |
} |
} |
static void si_enable_bif_mgls(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
orig = data = RREG32_PCIE(PCIE_CNTL2); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_BIF_LS)) |
data |= SLV_MEM_LS_EN | MST_MEM_LS_EN | |
REPLAY_MEM_LS_EN | SLV_MEM_AGGRESSIVE_LS_EN; |
else |
data &= ~(SLV_MEM_LS_EN | MST_MEM_LS_EN | |
REPLAY_MEM_LS_EN | SLV_MEM_AGGRESSIVE_LS_EN); |
if (orig != data) |
WREG32_PCIE(PCIE_CNTL2, data); |
} |
static void si_enable_hdp_mgcg(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
orig = data = RREG32(HDP_HOST_PATH_CNTL); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_HDP_MGCG)) |
data &= ~CLOCK_GATING_DIS; |
else |
data |= CLOCK_GATING_DIS; |
if (orig != data) |
WREG32(HDP_HOST_PATH_CNTL, data); |
} |
static void si_enable_hdp_ls(struct radeon_device *rdev, |
bool enable) |
{ |
u32 orig, data; |
orig = data = RREG32(HDP_MEM_POWER_LS); |
if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_HDP_LS)) |
data |= HDP_LS_ENABLE; |
else |
data &= ~HDP_LS_ENABLE; |
if (orig != data) |
WREG32(HDP_MEM_POWER_LS, data); |
} |
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); |
/* order matters! */ |
if (enable) { |
si_enable_mgcg(rdev, true); |
si_enable_cgcg(rdev, true); |
} else { |
si_enable_cgcg(rdev, false); |
si_enable_mgcg(rdev, false); |
} |
si_enable_gui_idle_interrupt(rdev, true); |
} |
if (block & RADEON_CG_BLOCK_MC) { |
si_enable_mc_mgcg(rdev, enable); |
si_enable_mc_ls(rdev, enable); |
} |
if (block & RADEON_CG_BLOCK_SDMA) { |
si_enable_dma_mgcg(rdev, enable); |
} |
if (block & RADEON_CG_BLOCK_BIF) { |
si_enable_bif_mgls(rdev, enable); |
} |
if (block & RADEON_CG_BLOCK_UVD) { |
if (rdev->has_uvd) { |
si_enable_uvd_mgcg(rdev, enable); |
} |
} |
if (block & RADEON_CG_BLOCK_HDP) { |
si_enable_hdp_mgcg(rdev, enable); |
si_enable_hdp_ls(rdev, enable); |
} |
} |
static void si_init_cg(struct radeon_device *rdev) |
{ |
si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | |
RADEON_CG_BLOCK_MC | |
RADEON_CG_BLOCK_SDMA | |
RADEON_CG_BLOCK_BIF | |
RADEON_CG_BLOCK_HDP), true); |
if (rdev->has_uvd) { |
si_update_cg(rdev, RADEON_CG_BLOCK_UVD, true); |
si_init_uvd_internal_cg(rdev); |
} |
} |
static void si_fini_cg(struct radeon_device *rdev) |
{ |
if (rdev->has_uvd) { |
si_update_cg(rdev, RADEON_CG_BLOCK_UVD, false); |
} |
si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | |
RADEON_CG_BLOCK_MC | |
RADEON_CG_BLOCK_SDMA | |
RADEON_CG_BLOCK_BIF | |
RADEON_CG_BLOCK_HDP), false); |
} |
u32 si_get_csb_size(struct radeon_device *rdev) |
{ |
u32 count = 0; |
const struct cs_section_def *sect = NULL; |
const struct cs_extent_def *ext = NULL; |
if (rdev->rlc.cs_data == NULL) |
return 0; |
/* begin clear state */ |
count += 2; |
/* context control state */ |
count += 3; |
for (sect = rdev->rlc.cs_data; sect->section != NULL; ++sect) { |
for (ext = sect->section; ext->extent != NULL; ++ext) { |
if (sect->id == SECT_CONTEXT) |
count += 2 + ext->reg_count; |
else |
return 0; |
} |
} |
/* pa_sc_raster_config */ |
count += 3; |
/* end clear state */ |
count += 2; |
/* clear state */ |
count += 2; |
return count; |
} |
void si_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer) |
{ |
u32 count = 0, i; |
const struct cs_section_def *sect = NULL; |
const struct cs_extent_def *ext = NULL; |
if (rdev->rlc.cs_data == NULL) |
return; |
if (buffer == NULL) |
return; |
buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0)); |
buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_BEGIN_CLEAR_STATE); |
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++] = |
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++] = cpu_to_le32(ext->extent[i]); |
} else { |
return; |
} |
} |
} |
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++] = cpu_to_le32(0x2a00126a); |
break; |
case CHIP_VERDE: |
buffer[count++] = cpu_to_le32(0x0000124a); |
break; |
case CHIP_OLAND: |
buffer[count++] = cpu_to_le32(0x00000082); |
break; |
case CHIP_HAINAN: |
buffer[count++] = cpu_to_le32(0x00000000); |
break; |
default: |
buffer[count++] = cpu_to_le32(0x00000000); |
break; |
} |
buffer[count++] = cpu_to_le32(PACKET3(PACKET3_PREAMBLE_CNTL, 0)); |
buffer[count++] = cpu_to_le32(PACKET3_PREAMBLE_END_CLEAR_STATE); |
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) |
{ |
if (rdev->pg_flags) { |
if (rdev->pg_flags & RADEON_PG_SUPPORT_SDMA) { |
si_init_dma_pg(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); |
} 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); |
} |
} |
static void si_fini_pg(struct radeon_device *rdev) |
{ |
if (rdev->pg_flags) { |
si_enable_dma_pg(rdev, false); |
si_enable_gfx_cgpg(rdev, false); |
} |
} |
/* |
* RLC |
*/ |
void si_rlc_reset(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32(GRBM_SOFT_RESET); |
tmp |= SOFT_RESET_RLC; |
WREG32(GRBM_SOFT_RESET, tmp); |
udelay(50); |
tmp &= ~SOFT_RESET_RLC; |
WREG32(GRBM_SOFT_RESET, tmp); |
udelay(50); |
} |
static void si_rlc_stop(struct radeon_device *rdev) |
{ |
WREG32(RLC_CNTL, 0); |
si_enable_gui_idle_interrupt(rdev, false); |
si_wait_for_rlc_serdes(rdev); |
} |
static void si_rlc_start(struct radeon_device *rdev) |
{ |
WREG32(RLC_CNTL, RLC_ENABLE); |
si_enable_gui_idle_interrupt(rdev, true); |
udelay(50); |
} |
static bool si_lbpw_supported(struct radeon_device *rdev) |
{ |
u32 tmp; |
/* Enable LBPW only for DDR3 */ |
tmp = RREG32(MC_SEQ_MISC0); |
if ((tmp & 0xF0000000) == 0xB0000000) |
return true; |
return false; |
} |
static void si_enable_lbpw(struct radeon_device *rdev, bool enable) |
{ |
u32 tmp; |
tmp = RREG32(RLC_LB_CNTL); |
if (enable) |
tmp |= LOAD_BALANCE_ENABLE; |
else |
tmp &= ~LOAD_BALANCE_ENABLE; |
WREG32(RLC_LB_CNTL, tmp); |
if (!enable) { |
si_select_se_sh(rdev, 0xffffffff, 0xffffffff); |
WREG32(SPI_LB_CU_MASK, 0x00ff); |
} |
} |
static int si_rlc_resume(struct radeon_device *rdev) |
{ |
u32 i; |
const __be32 *fw_data; |
if (!rdev->rlc_fw) |
return -EINVAL; |
4390,25 → 5806,47 |
si_rlc_stop(rdev); |
si_rlc_reset(rdev); |
si_init_pg(rdev); |
si_init_cg(rdev); |
WREG32(RLC_RL_BASE, 0); |
WREG32(RLC_RL_SIZE, 0); |
WREG32(RLC_LB_CNTL, 0); |
WREG32(RLC_LB_CNTR_MAX, 0xffffffff); |
WREG32(RLC_LB_CNTR_INIT, 0); |
WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff); |
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); |
WREG32(RLC_MC_CNTL, 0); |
WREG32(RLC_UCODE_CNTL, 0); |
fw_data = (const __be32 *)rdev->rlc_fw->data; |
if (rdev->new_fw) { |
const struct rlc_firmware_header_v1_0 *hdr = |
(const struct rlc_firmware_header_v1_0 *)rdev->rlc_fw->data; |
u32 fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; |
const __le32 *fw_data = (const __le32 *) |
(rdev->rlc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
radeon_ucode_print_rlc_hdr(&hdr->header); |
for (i = 0; i < fw_size; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, le32_to_cpup(fw_data++)); |
} |
} else { |
const __be32 *fw_data = |
(const __be32 *)rdev->rlc_fw->data; |
for (i = 0; i < SI_RLC_UCODE_SIZE; i++) { |
WREG32(RLC_UCODE_ADDR, i); |
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); |
} |
} |
WREG32(RLC_UCODE_ADDR, 0); |
si_enable_lbpw(rdev, si_lbpw_supported(rdev)); |
si_rlc_start(rdev); |
return 0; |
4446,7 → 5884,9 |
{ |
u32 tmp; |
WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
tmp = RREG32(CP_INT_CNTL_RING0) & |
(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
WREG32(CP_INT_CNTL_RING0, tmp); |
WREG32(CP_INT_CNTL_RING1, 0); |
WREG32(CP_INT_CNTL_RING2, 0); |
tmp = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE; |
4481,7 → 5921,7 |
} |
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); |
4532,7 → 5972,7 |
WREG32(INTERRUPT_CNTL, interrupt_cntl); |
WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8); |
rb_bufsz = drm_order(rdev->ih.ring_size / 4); |
rb_bufsz = order_base_2(rdev->ih.ring_size / 4); |
ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE | |
IH_WPTR_OVERFLOW_CLEAR | |
4571,13 → 6011,13 |
int si_irq_set(struct radeon_device *rdev) |
{ |
u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; |
u32 cp_int_cntl; |
u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0; |
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; |
if (!rdev->irq.installed) { |
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
4591,6 → 6031,9 |
return 0; |
} |
cp_int_cntl = RREG32(CP_INT_CNTL_RING0) & |
(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); |
if (!ASIC_IS_NODCE(rdev)) { |
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; |
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; |
4603,6 → 6046,9 |
dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE; |
dma_cntl1 = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE; |
thermal_int = RREG32(CG_THERMAL_INT) & |
~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); |
/* enable CP interrupts on all rings */ |
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { |
DRM_DEBUG("si_irq_set: sw int gfx\n"); |
4689,6 → 6135,11 |
WREG32(GRBM_INT_CNTL, grbm_int_cntl); |
if (rdev->irq.dpm_thermal) { |
DRM_DEBUG("dpm thermal\n"); |
thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; |
} |
if (rdev->num_crtc >= 2) { |
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); |
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); |
4703,16 → 6154,22 |
} |
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)) { |
4724,6 → 6181,8 |
WREG32(DC_HPD6_INT_CONTROL, hpd6); |
} |
WREG32(CG_THERMAL_INT, thermal_int); |
return 0; |
} |
4867,6 → 6326,7 |
tmp = RREG32(IH_RB_CNTL); |
tmp |= IH_WPTR_OVERFLOW_CLEAR; |
WREG32(IH_RB_CNTL, tmp); |
wptr &= ~RB_OVERFLOW; |
} |
return (wptr & rdev->ih.ptr_mask); |
} |
4888,6 → 6348,8 |
u32 src_id, src_data, ring_id; |
u32 ring_index; |
bool queue_hotplug = false; |
bool queue_thermal = false; |
u32 status, addr; |
if (!rdev->ih.enabled || rdev->shutdown) |
return IRQ_NONE; |
5072,6 → 6534,14 |
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); |
break; |
case 42: /* HPD hotplug */ |
switch (src_data) { |
case 0: |
5121,15 → 6591,24 |
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", |
RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); |
addr); |
dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", |
RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); |
/* reset addr and status */ |
WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); |
status); |
si_vm_decode_fault(rdev, status, addr); |
break; |
case 176: /* RINGID0 CP_INT */ |
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); |
5158,6 → 6637,16 |
DRM_DEBUG("IH: DMA trap\n"); |
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX); |
break; |
case 230: /* thermal low to high */ |
DRM_DEBUG("IH: thermal low to high\n"); |
rdev->pm.dpm.thermal.high_to_low = false; |
queue_thermal = true; |
break; |
case 231: /* thermal high to low */ |
DRM_DEBUG("IH: thermal high to low\n"); |
rdev->pm.dpm.thermal.high_to_low = true; |
queue_thermal = true; |
break; |
case 233: /* GUI IDLE */ |
DRM_DEBUG("IH: GUI idle\n"); |
break; |
5188,80 → 6677,6 |
return IRQ_HANDLED; |
} |
/** |
* si_copy_dma - copy pages using the 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 DMA engine (SI). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int si_copy_dma(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.dma_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_bytes, cur_size_in_bytes; |
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, 0xfffff); |
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11); |
if (r) { |
DRM_ERROR("radeon: moving bo (%d).\n", r); |
radeon_semaphore_free(rdev, &sem, NULL); |
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); |
} |
for (i = 0; i < num_loops; i++) { |
cur_size_in_bytes = size_in_bytes; |
if (cur_size_in_bytes > 0xFFFFF) |
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, upper_32_bits(dst_offset) & 0xff); |
radeon_ring_write(ring, upper_32_bits(src_offset) & 0xff); |
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); |
return r; |
} |
radeon_ring_unlock_commit(rdev, ring); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
/* |
* startup/shutdown callbacks |
*/ |
5270,26 → 6685,26 |
struct radeon_ring *ring; |
int 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"); |
/* enable pcie gen2/3 link */ |
si_pcie_gen3_enable(rdev); |
/* enable aspm */ |
si_program_aspm(rdev); |
/* scratch needs to be initialized before MC */ |
r = r600_vram_scratch_init(rdev); |
if (r) |
return r; |
} |
} |
si_mc_program(rdev); |
if (!rdev->pm.dpm_enabled) { |
r = si_mc_load_microcode(rdev); |
if (r) { |
DRM_ERROR("Failed to load MC firmware!\n"); |
return r; |
} |
} |
r = r600_vram_scratch_init(rdev); |
if (r) |
return r; |
si_mc_program(rdev); |
r = si_pcie_gart_enable(rdev); |
if (r) |
return r; |
5296,7 → 6711,13 |
si_gpu_init(rdev); |
/* allocate rlc buffers */ |
r = si_rlc_init(rdev); |
if (rdev->family == CHIP_VERDE) { |
rdev->rlc.reg_list = verde_rlc_save_restore_register_list; |
rdev->rlc.reg_list_size = |
(u32)ARRAY_SIZE(verde_rlc_save_restore_register_list); |
} |
rdev->rlc.cs_data = si_cs_data; |
r = sumo_rlc_init(rdev); |
if (r) { |
DRM_ERROR("Failed to init rlc BOs!\n"); |
return r; |
5337,6 → 6758,17 |
return r; |
} |
if (rdev->has_uvd) { |
r = uvd_v2_2_resume(rdev); |
if (!r) { |
r = radeon_fence_driver_start_ring(rdev, |
R600_RING_TYPE_UVD_INDEX); |
if (r) |
dev_err(rdev->dev, "UVD fences init error (%d).\n", r); |
} |
if (r) |
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; |
} |
/* Enable IRQ */ |
if (!rdev->irq.installed) { |
5355,38 → 6787,31 |
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, |
0, 0xfffff, RADEON_CP_PACKET2); |
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, |
0, 0xfffff, RADEON_CP_PACKET2); |
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, |
0, 0xfffff, RADEON_CP_PACKET2); |
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, |
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0)); |
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, |
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0)); |
DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0)); |
if (r) |
return r; |
5401,6 → 6826,17 |
if (r) |
return r; |
if (rdev->has_uvd) { |
ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
if (ring->ring_size) { |
r = radeon_ring_init(rdev, ring, ring->ring_size, 0, |
RADEON_CP_PACKET2); |
if (!r) |
r = uvd_v1_0_init(rdev); |
if (r) |
DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); |
} |
} |
r = radeon_ib_pool_init(rdev); |
if (r) { |
5414,6 → 6850,10 |
return r; |
} |
r = dce6_audio_init(rdev); |
if (r) |
return r; |
return 0; |
} |
5431,8 → 6871,6 |
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; |
int r; |
ENTER(); |
/* Read BIOS */ |
if (!radeon_get_bios(rdev)) { |
if (ASIC_IS_AVIVO(rdev)) |
5479,6 → 6917,18 |
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); |
5499,6 → 6949,15 |
ring->ring_obj = NULL; |
r600_ring_init(rdev, ring, 64 * 1024); |
if (rdev->has_uvd) { |
r = radeon_uvd_init(rdev); |
if (!r) { |
ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
ring->ring_obj = NULL; |
r600_ring_init(rdev, ring, 4096); |
} |
} |
rdev->ih.ring_obj = NULL; |
r600_ih_ring_init(rdev, 64 * 1024); |
5510,7 → 6969,7 |
r = si_startup(rdev); |
if (r) { |
dev_err(rdev->dev, "disabling GPU acceleration\n"); |
// si_cp_fini(rdev); |
si_cp_fini(rdev); |
// si_irq_fini(rdev); |
// si_rlc_fini(rdev); |
// radeon_wb_fini(rdev); |
5529,7 → 6988,6 |
DRM_ERROR("radeon: MC ucode required for NI+.\n"); |
return -EINVAL; |
} |
LEAVE(); |
return 0; |
} |
5554,7 → 7012,6 |
return clock; |
} |
#if 0 |
int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) |
{ |
unsigned fb_div = 0, vclk_div = 0, dclk_div = 0; |
5645,4 → 7102,364 |
return 0; |
} |
#endif |
static void si_pcie_gen3_enable(struct radeon_device *rdev) |
{ |
struct pci_dev *root = rdev->pdev->bus->self; |
int bridge_pos, gpu_pos; |
u32 speed_cntl, mask, current_data_rate; |
int ret, i; |
u16 tmp16; |
if (radeon_pcie_gen2 == 0) |
return; |
if (rdev->flags & RADEON_IS_IGP) |
return; |
if (!(rdev->flags & RADEON_IS_PCIE)) |
return; |
ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); |
if (ret != 0) |
return; |
if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) |
return; |
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> |
LC_CURRENT_DATA_RATE_SHIFT; |
if (mask & DRM_PCIE_SPEED_80) { |
if (current_data_rate == 2) { |
DRM_INFO("PCIE gen 3 link speeds already enabled\n"); |
return; |
} |
DRM_INFO("enabling PCIE gen 3 link speeds, disable with radeon.pcie_gen2=0\n"); |
} else if (mask & DRM_PCIE_SPEED_50) { |
if (current_data_rate == 1) { |
DRM_INFO("PCIE gen 2 link speeds already enabled\n"); |
return; |
} |
DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n"); |
} |
bridge_pos = pci_pcie_cap(root); |
if (!bridge_pos) |
return; |
gpu_pos = pci_pcie_cap(rdev->pdev); |
if (!gpu_pos) |
return; |
if (mask & DRM_PCIE_SPEED_80) { |
/* re-try equalization if gen3 is not already enabled */ |
if (current_data_rate != 2) { |
u16 bridge_cfg, gpu_cfg; |
u16 bridge_cfg2, gpu_cfg2; |
u32 max_lw, current_lw, tmp; |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg); |
tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD; |
pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16); |
tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD; |
pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16); |
tmp = RREG32_PCIE(PCIE_LC_STATUS1); |
max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT; |
current_lw = (tmp & LC_OPERATING_LINK_WIDTH_MASK) >> LC_OPERATING_LINK_WIDTH_SHIFT; |
if (current_lw < max_lw) { |
tmp = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL); |
if (tmp & LC_RENEGOTIATION_SUPPORT) { |
tmp &= ~(LC_LINK_WIDTH_MASK | LC_UPCONFIGURE_DIS); |
tmp |= (max_lw << LC_LINK_WIDTH_SHIFT); |
tmp |= LC_UPCONFIGURE_SUPPORT | LC_RENEGOTIATE_EN | LC_RECONFIG_NOW; |
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, tmp); |
} |
} |
for (i = 0; i < 10; i++) { |
/* check status */ |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16); |
if (tmp16 & PCI_EXP_DEVSTA_TRPND) |
break; |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg); |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2); |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4); |
tmp |= LC_SET_QUIESCE; |
WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp); |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4); |
tmp |= LC_REDO_EQ; |
WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp); |
mdelay(100); |
/* linkctl */ |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16); |
tmp16 &= ~PCI_EXP_LNKCTL_HAWD; |
tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD); |
pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16); |
tmp16 &= ~PCI_EXP_LNKCTL_HAWD; |
tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD); |
pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16); |
/* linkctl2 */ |
pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16); |
tmp16 &= ~((1 << 4) | (7 << 9)); |
tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9))); |
pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); |
tmp16 &= ~((1 << 4) | (7 << 9)); |
tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9))); |
pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16); |
tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4); |
tmp &= ~LC_SET_QUIESCE; |
WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp); |
} |
} |
} |
/* set the link speed */ |
speed_cntl |= LC_FORCE_EN_SW_SPEED_CHANGE | LC_FORCE_DIS_HW_SPEED_CHANGE; |
speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl); |
pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); |
tmp16 &= ~0xf; |
if (mask & DRM_PCIE_SPEED_80) |
tmp16 |= 3; /* gen3 */ |
else if (mask & DRM_PCIE_SPEED_50) |
tmp16 |= 2; /* gen2 */ |
else |
tmp16 |= 1; /* gen1 */ |
pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16); |
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE; |
WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl); |
for (i = 0; i < rdev->usec_timeout; i++) { |
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); |
if ((speed_cntl & LC_INITIATE_LINK_SPEED_CHANGE) == 0) |
break; |
udelay(1); |
} |
} |
static void si_program_aspm(struct radeon_device *rdev) |
{ |
u32 data, orig; |
bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false; |
bool disable_clkreq = false; |
if (radeon_aspm == 0) |
return; |
if (!(rdev->flags & RADEON_IS_PCIE)) |
return; |
orig = data = RREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL); |
data &= ~LC_XMIT_N_FTS_MASK; |
data |= LC_XMIT_N_FTS(0x24) | LC_XMIT_N_FTS_OVERRIDE_EN; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL, data); |
orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL3); |
data |= LC_GO_TO_RECOVERY; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL3, data); |
orig = data = RREG32_PCIE(PCIE_P_CNTL); |
data |= P_IGNORE_EDB_ERR; |
if (orig != data) |
WREG32_PCIE(PCIE_P_CNTL, data); |
orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL); |
data &= ~(LC_L0S_INACTIVITY_MASK | LC_L1_INACTIVITY_MASK); |
data |= LC_PMI_TO_L1_DIS; |
if (!disable_l0s) |
data |= LC_L0S_INACTIVITY(7); |
if (!disable_l1) { |
data |= LC_L1_INACTIVITY(7); |
data &= ~LC_PMI_TO_L1_DIS; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL, data); |
if (!disable_plloff_in_l1) { |
bool clk_req_support; |
orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0); |
data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK); |
data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7); |
if (orig != data) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data); |
orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1); |
data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK); |
data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7); |
if (orig != data) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data); |
orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0); |
data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK); |
data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7); |
if (orig != data) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data); |
orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1); |
data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK); |
data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7); |
if (orig != data) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data); |
if ((rdev->family != CHIP_OLAND) && (rdev->family != CHIP_HAINAN)) { |
orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0); |
data &= ~PLL_RAMP_UP_TIME_0_MASK; |
if (orig != data) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data); |
orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1); |
data &= ~PLL_RAMP_UP_TIME_1_MASK; |
if (orig != data) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data); |
orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_2); |
data &= ~PLL_RAMP_UP_TIME_2_MASK; |
if (orig != data) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_2, data); |
orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_3); |
data &= ~PLL_RAMP_UP_TIME_3_MASK; |
if (orig != data) |
WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_3, data); |
orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0); |
data &= ~PLL_RAMP_UP_TIME_0_MASK; |
if (orig != data) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data); |
orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1); |
data &= ~PLL_RAMP_UP_TIME_1_MASK; |
if (orig != data) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data); |
orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_2); |
data &= ~PLL_RAMP_UP_TIME_2_MASK; |
if (orig != data) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_2, data); |
orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_3); |
data &= ~PLL_RAMP_UP_TIME_3_MASK; |
if (orig != data) |
WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_3, data); |
} |
orig = data = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL); |
data &= ~LC_DYN_LANES_PWR_STATE_MASK; |
data |= LC_DYN_LANES_PWR_STATE(3); |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data); |
orig = data = RREG32_PIF_PHY0(PB0_PIF_CNTL); |
data &= ~LS2_EXIT_TIME_MASK; |
if ((rdev->family == CHIP_OLAND) || (rdev->family == CHIP_HAINAN)) |
data |= LS2_EXIT_TIME(5); |
if (orig != data) |
WREG32_PIF_PHY0(PB0_PIF_CNTL, data); |
orig = data = RREG32_PIF_PHY1(PB1_PIF_CNTL); |
data &= ~LS2_EXIT_TIME_MASK; |
if ((rdev->family == CHIP_OLAND) || (rdev->family == CHIP_HAINAN)) |
data |= LS2_EXIT_TIME(5); |
if (orig != data) |
WREG32_PIF_PHY1(PB1_PIF_CNTL, data); |
if (!disable_clkreq) { |
struct pci_dev *root = rdev->pdev->bus->self; |
u32 lnkcap; |
clk_req_support = false; |
pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap); |
if (lnkcap & PCI_EXP_LNKCAP_CLKPM) |
clk_req_support = true; |
} else { |
clk_req_support = false; |
} |
if (clk_req_support) { |
orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL2); |
data |= LC_ALLOW_PDWN_IN_L1 | LC_ALLOW_PDWN_IN_L23; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL2, data); |
orig = data = RREG32(THM_CLK_CNTL); |
data &= ~(CMON_CLK_SEL_MASK | TMON_CLK_SEL_MASK); |
data |= CMON_CLK_SEL(1) | TMON_CLK_SEL(1); |
if (orig != data) |
WREG32(THM_CLK_CNTL, data); |
orig = data = RREG32(MISC_CLK_CNTL); |
data &= ~(DEEP_SLEEP_CLK_SEL_MASK | ZCLK_SEL_MASK); |
data |= DEEP_SLEEP_CLK_SEL(1) | ZCLK_SEL(1); |
if (orig != data) |
WREG32(MISC_CLK_CNTL, data); |
orig = data = RREG32(CG_CLKPIN_CNTL); |
data &= ~BCLK_AS_XCLK; |
if (orig != data) |
WREG32(CG_CLKPIN_CNTL, data); |
orig = data = RREG32(CG_CLKPIN_CNTL_2); |
data &= ~FORCE_BIF_REFCLK_EN; |
if (orig != data) |
WREG32(CG_CLKPIN_CNTL_2, data); |
orig = data = RREG32(MPLL_BYPASSCLK_SEL); |
data &= ~MPLL_CLKOUT_SEL_MASK; |
data |= MPLL_CLKOUT_SEL(4); |
if (orig != data) |
WREG32(MPLL_BYPASSCLK_SEL, data); |
orig = data = RREG32(SPLL_CNTL_MODE); |
data &= ~SPLL_REFCLK_SEL_MASK; |
if (orig != data) |
WREG32(SPLL_CNTL_MODE, data); |
} |
} |
} else { |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL, data); |
} |
orig = data = RREG32_PCIE(PCIE_CNTL2); |
data |= SLV_MEM_LS_EN | MST_MEM_LS_EN | REPLAY_MEM_LS_EN; |
if (orig != data) |
WREG32_PCIE(PCIE_CNTL2, data); |
if (!disable_l0s) { |
data = RREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL); |
if((data & LC_N_FTS_MASK) == LC_N_FTS_MASK) { |
data = RREG32_PCIE(PCIE_LC_STATUS1); |
if ((data & LC_REVERSE_XMIT) && (data & LC_REVERSE_RCVR)) { |
orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL); |
data &= ~LC_L0S_INACTIVITY_MASK; |
if (orig != data) |
WREG32_PCIE_PORT(PCIE_LC_CNTL, data); |
} |
} |
} |
} |
/drivers/video/drm/radeon/si_dma.c |
---|
0,0 → 1,283 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#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); |
/** |
* si_dma_is_lockup - Check if the DMA engine is locked up |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring structure holding ring information |
* |
* Check if the async DMA engine is locked up. |
* Returns true if the engine appears to be locked up, false if not. |
*/ |
bool si_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
u32 reset_mask = si_gpu_check_soft_reset(rdev); |
u32 mask; |
if (ring->idx == R600_RING_TYPE_DMA_INDEX) |
mask = RADEON_RESET_DMA; |
else |
mask = RADEON_RESET_DMA1; |
if (!(reset_mask & mask)) { |
radeon_ring_lockup_update(rdev, ring); |
return false; |
} |
return radeon_ring_test_lockup(rdev, ring); |
} |
/** |
* si_dma_vm_copy_pages - update PTEs by copying them from the GART |
* |
* @rdev: radeon_device pointer |
* @ib: indirect buffer to fill with commands |
* @pe: addr of the page entry |
* @src: src addr where to copy from |
* @count: number of page entries to update |
* |
* Update PTEs by copying them from the GART using the DMA (SI). |
*/ |
void si_dma_vm_copy_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, uint64_t src, |
unsigned count) |
{ |
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; |
} |
} |
/** |
* si_dma_vm_write_pages - update PTEs by writing them manually |
* |
* @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 PTEs by writing them manually using the DMA (SI). |
*/ |
void si_dma_vm_write_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags) |
{ |
uint64_t value; |
unsigned ndw; |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
/* for non-physically contiguous pages (system) */ |
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, ndw); |
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 & R600_PTE_SYSTEM) { |
value = radeon_vm_map_gart(rdev, addr); |
value &= 0xFFFFFFFFFFFFF000ULL; |
} else if (flags & R600_PTE_VALID) { |
value = addr; |
} else { |
value = 0; |
} |
addr += incr; |
value |= flags; |
ib->ptr[ib->length_dw++] = value; |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
} |
} |
} |
/** |
* si_dma_vm_set_pages - update the page tables using the DMA |
* |
* @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 DMA (SI). |
*/ |
void si_dma_vm_set_pages(struct radeon_device *rdev, |
struct radeon_ib *ib, |
uint64_t pe, |
uint64_t addr, unsigned count, |
uint32_t incr, uint32_t flags) |
{ |
uint64_t value; |
unsigned ndw; |
while (count) { |
ndw = count * 2; |
if (ndw > 0xFFFFE) |
ndw = 0xFFFFE; |
if (flags & R600_PTE_VALID) |
value = addr; |
else |
value = 0; |
/* for physically contiguous pages (vram) */ |
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++] = flags; /* mask */ |
ib->ptr[ib->length_dw++] = 0; |
ib->ptr[ib->length_dw++] = value; /* value */ |
ib->ptr[ib->length_dw++] = upper_32_bits(value); |
ib->ptr[ib->length_dw++] = incr; /* increment size */ |
ib->ptr[ib->length_dw++] = 0; |
pe += ndw * 4; |
addr += (ndw / 2) * incr; |
count -= ndw / 2; |
} |
} |
void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) |
{ |
struct radeon_ring *ring = &rdev->ring[ridx]; |
if (vm == NULL) |
return; |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); |
if (vm->id < 8) { |
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2)); |
} else { |
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2)); |
} |
radeon_ring_write(ring, vm->pd_gpu_addr >> 12); |
/* flush hdp cache */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2)); |
radeon_ring_write(ring, 1); |
/* bits 0-7 are the VM contexts0-7 */ |
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); |
radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); |
radeon_ring_write(ring, 1 << vm->id); |
} |
/** |
* si_copy_dma - copy pages using the 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 DMA engine (SI). |
* Used by the radeon ttm implementation to move pages if |
* registered as the asic copy callback. |
*/ |
int si_copy_dma(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.dma_ring_index; |
struct radeon_ring *ring = &rdev->ring[ring_index]; |
u32 size_in_bytes, cur_size_in_bytes; |
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, 0xfffff); |
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11); |
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 > 0xFFFFF) |
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, 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; |
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, false); |
radeon_semaphore_free(rdev, &sem, *fence); |
return r; |
} |
/drivers/video/drm/radeon/si_dpm.c |
---|
0,0 → 1,6563 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "sid.h" |
#include "r600_dpm.h" |
#include "si_dpm.h" |
#include "atom.h" |
#include <linux/math64.h> |
#include <linux/seq_file.h> |
#define MC_CG_ARB_FREQ_F0 0x0a |
#define MC_CG_ARB_FREQ_F1 0x0b |
#define MC_CG_ARB_FREQ_F2 0x0c |
#define MC_CG_ARB_FREQ_F3 0x0d |
#define SMC_RAM_END 0x20000 |
#define SCLK_MIN_DEEPSLEEP_FREQ 1350 |
static const struct si_cac_config_reg cac_weights_tahiti[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0xc, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x101, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0xc, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x8fc, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x95, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x34e, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x1a1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0xda, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x46, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x208, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0xe7, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x948, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x167, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x31, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x18e, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg lcac_tahiti[] = |
{ |
{ 0x143, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x146, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x149, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x149, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14c, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x101, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x101, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8f, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x92, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x92, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x95, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x95, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x152, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x155, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x155, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x158, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x158, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x113, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x116, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x116, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x119, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND }, |
{ 0x119, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x122, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x122, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x125, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x125, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x128, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x128, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_override_tahiti[] = |
{ |
{ 0xFFFFFFFF } |
}; |
static const struct si_powertune_data powertune_data_tahiti = |
{ |
((1 << 16) | 27027), |
6, |
0, |
4, |
95, |
{ |
0UL, |
0UL, |
4521550UL, |
309631529UL, |
-1270850L, |
4513710L, |
40 |
}, |
595000000UL, |
12, |
{ |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0 |
}, |
true |
}; |
static const struct si_dte_data dte_data_tahiti = |
{ |
{ 1159409, 0, 0, 0, 0 }, |
{ 777, 0, 0, 0, 0 }, |
2, |
54000, |
127000, |
25, |
2, |
10, |
13, |
{ 27, 31, 35, 39, 43, 47, 54, 61, 67, 74, 81, 88, 95, 0, 0, 0 }, |
{ 240888759, 221057860, 235370597, 162287531, 158510299, 131423027, 116673180, 103067515, 87941937, 76209048, 68209175, 64090048, 58301890, 0, 0, 0 }, |
{ 12024, 11189, 11451, 8411, 7939, 6666, 5681, 4905, 4241, 3720, 3354, 3122, 2890, 0, 0, 0 }, |
85, |
false |
}; |
static const struct si_dte_data dte_data_tahiti_le = |
{ |
{ 0x1E8480, 0x7A1200, 0x2160EC0, 0x3938700, 0 }, |
{ 0x7D, 0x7D, 0x4E4, 0xB00, 0 }, |
0x5, |
0xAFC8, |
0x64, |
0x32, |
1, |
0, |
0x10, |
{ 0x78, 0x7C, 0x82, 0x88, 0x8E, 0x94, 0x9A, 0xA0, 0xA6, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, 0xC0, 0xC4 }, |
{ 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700 }, |
{ 0x2AF8, 0x2AF8, 0x29BB, 0x27F9, 0x2637, 0x2475, 0x22B3, 0x20F1, 0x1F2F, 0x1D6D, 0x1734, 0x1414, 0x10F4, 0xDD4, 0xAB4, 0x794 }, |
85, |
true |
}; |
static const struct si_dte_data dte_data_tahiti_pro = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0 }, |
5, |
45000, |
100, |
0xA, |
1, |
0, |
0x10, |
{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0x7D0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_dte_data dte_data_new_zealand = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0 }, |
{ 0x29B, 0x3E9, 0x537, 0x7D2, 0 }, |
0x5, |
0xAFC8, |
0x69, |
0x32, |
1, |
0, |
0x10, |
{ 0x82, 0xA0, 0xB4, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0xDAC, 0x1388, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685 }, |
85, |
true |
}; |
static const struct si_dte_data dte_data_aruba_pro = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0 }, |
5, |
45000, |
100, |
0xA, |
1, |
0, |
0x10, |
{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_dte_data dte_data_malta = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0 }, |
5, |
45000, |
100, |
0xA, |
1, |
0, |
0x10, |
{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
struct si_cac_config_reg cac_weights_pitcairn[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x8a, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x24d, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x19, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0xc11, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0x7f3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x403, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x367, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x4c9, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x45d, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0x36d, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x534, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x5da, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x880, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0x201, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x9f, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x1f, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x5de, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x7b, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x13, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0xf9, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x66, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x13, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x186, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg lcac_pitcairn[] = |
{ |
{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x113, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x152, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x146, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x116, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x116, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x155, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x155, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x92, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x92, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x149, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x149, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x101, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x101, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x119, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x119, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x158, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x158, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x95, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x95, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x122, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x122, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x125, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x125, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x128, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x128, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_override_pitcairn[] = |
{ |
{ 0xFFFFFFFF } |
}; |
static const struct si_powertune_data powertune_data_pitcairn = |
{ |
((1 << 16) | 27027), |
5, |
0, |
6, |
100, |
{ |
51600000UL, |
1800000UL, |
7194395UL, |
309631529UL, |
-1270850L, |
4513710L, |
100 |
}, |
117830498UL, |
12, |
{ |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0 |
}, |
true |
}; |
static const struct si_dte_data dte_data_pitcairn = |
{ |
{ 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0 }, |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
0, |
false |
}; |
static const struct si_dte_data dte_data_curacao_xt = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0 }, |
5, |
45000, |
100, |
0xA, |
1, |
0, |
0x10, |
{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0x1D17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_dte_data dte_data_curacao_pro = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0 }, |
5, |
45000, |
100, |
0xA, |
1, |
0, |
0x10, |
{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0x1D17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_dte_data dte_data_neptune_xt = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0 }, |
5, |
45000, |
100, |
0xA, |
1, |
0, |
0x10, |
{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0x3A2F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_cac_config_reg cac_weights_chelsea_pro[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x2BD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_weights_chelsea_xt[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x30A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_weights_heathrow[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x362, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_weights_cape_verde_pro[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x315, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_weights_cape_verde[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x3BA, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg lcac_cape_verde[] = |
{ |
{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x113, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x152, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x146, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_override_cape_verde[] = |
{ |
{ 0xFFFFFFFF } |
}; |
static const struct si_powertune_data powertune_data_cape_verde = |
{ |
((1 << 16) | 0x6993), |
5, |
0, |
7, |
105, |
{ |
0UL, |
0UL, |
7194395UL, |
309631529UL, |
-1270850L, |
4513710L, |
100 |
}, |
117830498UL, |
12, |
{ |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0 |
}, |
true |
}; |
static const struct si_dte_data dte_data_cape_verde = |
{ |
{ 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0 }, |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
0, |
false |
}; |
static const struct si_dte_data dte_data_venus_xtx = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x71C, 0xAAB, 0xE39, 0x11C7, 0x0 }, |
5, |
55000, |
0x69, |
0xA, |
1, |
0, |
0x3, |
{ 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
{ 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
{ 0xD6D8, 0x88B8, 0x1555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_dte_data dte_data_venus_xt = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0xBDA, 0x11C7, 0x17B4, 0x1DA1, 0x0 }, |
5, |
55000, |
0x69, |
0xA, |
1, |
0, |
0x3, |
{ 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
{ 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
{ 0xAFC8, 0x88B8, 0x238E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_dte_data dte_data_venus_pro = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x11C7, 0x1AAB, 0x238E, 0x2C72, 0x0 }, |
5, |
55000, |
0x69, |
0xA, |
1, |
0, |
0x3, |
{ 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
{ 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
{ 0x88B8, 0x88B8, 0x3555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
struct si_cac_config_reg cac_weights_oland[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x3BA, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_weights_mars_pro[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_weights_mars_xt[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x60, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_weights_oland_pro[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x90, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_weights_oland_xt[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x120, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg lcac_oland[] = |
{ |
{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg lcac_mars_pro[] = |
{ |
{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_cac_config_reg cac_override_oland[] = |
{ |
{ 0xFFFFFFFF } |
}; |
static const struct si_powertune_data powertune_data_oland = |
{ |
((1 << 16) | 0x6993), |
5, |
0, |
7, |
105, |
{ |
0UL, |
0UL, |
7194395UL, |
309631529UL, |
-1270850L, |
4513710L, |
100 |
}, |
117830498UL, |
12, |
{ |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0 |
}, |
true |
}; |
static const struct si_powertune_data powertune_data_mars_pro = |
{ |
((1 << 16) | 0x6993), |
5, |
0, |
7, |
105, |
{ |
0UL, |
0UL, |
7194395UL, |
309631529UL, |
-1270850L, |
4513710L, |
100 |
}, |
117830498UL, |
12, |
{ |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0 |
}, |
true |
}; |
static const struct si_dte_data dte_data_oland = |
{ |
{ 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0 }, |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
0, |
false |
}; |
static const struct si_dte_data dte_data_mars_pro = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0 }, |
5, |
55000, |
105, |
0xA, |
1, |
0, |
0x10, |
{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0xF627, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_dte_data dte_data_sun_xt = |
{ |
{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 }, |
{ 0x0, 0x0, 0x0, 0x0, 0x0 }, |
5, |
55000, |
105, |
0xA, |
1, |
0, |
0x10, |
{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, |
{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 }, |
{ 0xD555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, |
90, |
true |
}; |
static const struct si_cac_config_reg cac_weights_hainan[] = |
{ |
{ 0x0, 0x0000ffff, 0, 0x2d9, SISLANDS_CACCONFIG_CGIND }, |
{ 0x0, 0xffff0000, 16, 0x22b, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0x0000ffff, 0, 0x21c, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1, 0xffff0000, 16, 0x1dc, SISLANDS_CACCONFIG_CGIND }, |
{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0x0000ffff, 0, 0x24e, SISLANDS_CACCONFIG_CGIND }, |
{ 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0x0000ffff, 0, 0x35e, SISLANDS_CACCONFIG_CGIND }, |
{ 0x5, 0xffff0000, 16, 0x1143, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0x0000ffff, 0, 0xe17, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6, 0xffff0000, 16, 0x441, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0x0000ffff, 0, 0x28b, SISLANDS_CACCONFIG_CGIND }, |
{ 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x8, 0xffff0000, 16, 0xabe, SISLANDS_CACCONFIG_CGIND }, |
{ 0x9, 0x0000ffff, 0, 0xf11, SISLANDS_CACCONFIG_CGIND }, |
{ 0xa, 0x0000ffff, 0, 0x907, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0x0000ffff, 0, 0xb45, SISLANDS_CACCONFIG_CGIND }, |
{ 0xb, 0xffff0000, 16, 0xd1e, SISLANDS_CACCONFIG_CGIND }, |
{ 0xc, 0x0000ffff, 0, 0xa2c, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0x0000ffff, 0, 0x62, SISLANDS_CACCONFIG_CGIND }, |
{ 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0xe, 0x0000ffff, 0, 0x1f3, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0x0000ffff, 0, 0x42, SISLANDS_CACCONFIG_CGIND }, |
{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0x0000ffff, 0, 0x709, SISLANDS_CACCONFIG_CGIND }, |
{ 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x12, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x13, 0xffff0000, 16, 0x3a, SISLANDS_CACCONFIG_CGIND }, |
{ 0x14, 0x0000ffff, 0, 0x357, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0x0000ffff, 0, 0x9f, SISLANDS_CACCONFIG_CGIND }, |
{ 0x15, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0x0000ffff, 0, 0x314, SISLANDS_CACCONFIG_CGIND }, |
{ 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x17, 0x0000ffff, 0, 0x6d, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND }, |
{ 0x6d, 0x0000ffff, 0, 0x1b9, SISLANDS_CACCONFIG_CGIND }, |
{ 0xFFFFFFFF } |
}; |
static const struct si_powertune_data powertune_data_hainan = |
{ |
((1 << 16) | 0x6993), |
5, |
0, |
9, |
105, |
{ |
0UL, |
0UL, |
7194395UL, |
309631529UL, |
-1270850L, |
4513710L, |
100 |
}, |
117830498UL, |
12, |
{ |
0, |
0, |
0, |
0, |
0, |
0, |
0, |
0 |
}, |
true |
}; |
struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev); |
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); |
static int si_get_std_voltage_value(struct radeon_device *rdev, |
SISLANDS_SMC_VOLTAGE_VALUE *voltage, |
u16 *std_voltage); |
static int si_write_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 value); |
static int si_convert_power_level_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
SISLANDS_SMC_HW_PERFORMANCE_LEVEL *level); |
static int si_calculate_sclk_params(struct radeon_device *rdev, |
u32 engine_clock, |
SISLANDS_SMC_SCLK_VALUE *sclk); |
static struct si_power_info *si_get_pi(struct radeon_device *rdev) |
{ |
struct si_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coeffients *coeff, |
u16 v, s32 t, u32 ileakage, u32 *leakage) |
{ |
s64 kt, kv, leakage_w, i_leakage, vddc; |
s64 temperature, t_slope, t_intercept, av, bv, t_ref; |
s64 tmp; |
i_leakage = div64_s64(drm_int2fixp(ileakage), 100); |
vddc = div64_s64(drm_int2fixp(v), 1000); |
temperature = div64_s64(drm_int2fixp(t), 1000); |
t_slope = div64_s64(drm_int2fixp(coeff->t_slope), 100000000); |
t_intercept = div64_s64(drm_int2fixp(coeff->t_intercept), 100000000); |
av = div64_s64(drm_int2fixp(coeff->av), 100000000); |
bv = div64_s64(drm_int2fixp(coeff->bv), 100000000); |
t_ref = drm_int2fixp(coeff->t_ref); |
tmp = drm_fixp_mul(t_slope, vddc) + t_intercept; |
kt = drm_fixp_exp(drm_fixp_mul(tmp, temperature)); |
kt = drm_fixp_div(kt, drm_fixp_exp(drm_fixp_mul(tmp, t_ref))); |
kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc))); |
leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc); |
*leakage = drm_fixp2int(leakage_w * 1000); |
} |
static void si_calculate_leakage_for_v_and_t(struct radeon_device *rdev, |
const struct ni_leakage_coeffients *coeff, |
u16 v, |
s32 t, |
u32 i_leakage, |
u32 *leakage) |
{ |
si_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage); |
} |
static void si_calculate_leakage_for_v_formula(const struct ni_leakage_coeffients *coeff, |
const u32 fixed_kt, u16 v, |
u32 ileakage, u32 *leakage) |
{ |
s64 kt, kv, leakage_w, i_leakage, vddc; |
i_leakage = div64_s64(drm_int2fixp(ileakage), 100); |
vddc = div64_s64(drm_int2fixp(v), 1000); |
kt = div64_s64(drm_int2fixp(fixed_kt), 100000000); |
kv = drm_fixp_mul(div64_s64(drm_int2fixp(coeff->av), 100000000), |
drm_fixp_exp(drm_fixp_mul(div64_s64(drm_int2fixp(coeff->bv), 100000000), vddc))); |
leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc); |
*leakage = drm_fixp2int(leakage_w * 1000); |
} |
static void si_calculate_leakage_for_v(struct radeon_device *rdev, |
const struct ni_leakage_coeffients *coeff, |
const u32 fixed_kt, |
u16 v, |
u32 i_leakage, |
u32 *leakage) |
{ |
si_calculate_leakage_for_v_formula(coeff, fixed_kt, v, i_leakage, leakage); |
} |
static void si_update_dte_from_pl2(struct radeon_device *rdev, |
struct si_dte_data *dte_data) |
{ |
u32 p_limit1 = rdev->pm.dpm.tdp_limit; |
u32 p_limit2 = rdev->pm.dpm.near_tdp_limit; |
u32 k = dte_data->k; |
u32 t_max = dte_data->max_t; |
u32 t_split[5] = { 10, 15, 20, 25, 30 }; |
u32 t_0 = dte_data->t0; |
u32 i; |
if (p_limit2 != 0 && p_limit2 <= p_limit1) { |
dte_data->tdep_count = 3; |
for (i = 0; i < k; i++) { |
dte_data->r[i] = |
(t_split[i] * (t_max - t_0/(u32)1000) * (1 << 14)) / |
(p_limit2 * (u32)100); |
} |
dte_data->tdep_r[1] = dte_data->r[4] * 2; |
for (i = 2; i < SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE; i++) { |
dte_data->tdep_r[i] = dte_data->r[4]; |
} |
} else { |
DRM_ERROR("Invalid PL2! DTE will not be updated.\n"); |
} |
} |
static void si_initialize_powertune_defaults(struct radeon_device *rdev) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
bool update_dte_from_pl2 = false; |
if (rdev->family == CHIP_TAHITI) { |
si_pi->cac_weights = cac_weights_tahiti; |
si_pi->lcac_config = lcac_tahiti; |
si_pi->cac_override = cac_override_tahiti; |
si_pi->powertune_data = &powertune_data_tahiti; |
si_pi->dte_data = dte_data_tahiti; |
switch (rdev->pdev->device) { |
case 0x6798: |
si_pi->dte_data.enable_dte_by_default = true; |
break; |
case 0x6799: |
si_pi->dte_data = dte_data_new_zealand; |
break; |
case 0x6790: |
case 0x6791: |
case 0x6792: |
case 0x679E: |
si_pi->dte_data = dte_data_aruba_pro; |
update_dte_from_pl2 = true; |
break; |
case 0x679B: |
si_pi->dte_data = dte_data_malta; |
update_dte_from_pl2 = true; |
break; |
case 0x679A: |
si_pi->dte_data = dte_data_tahiti_pro; |
update_dte_from_pl2 = true; |
break; |
default: |
if (si_pi->dte_data.enable_dte_by_default == true) |
DRM_ERROR("DTE is not enabled!\n"); |
break; |
} |
} else if (rdev->family == CHIP_PITCAIRN) { |
switch (rdev->pdev->device) { |
case 0x6810: |
case 0x6818: |
si_pi->cac_weights = cac_weights_pitcairn; |
si_pi->lcac_config = lcac_pitcairn; |
si_pi->cac_override = cac_override_pitcairn; |
si_pi->powertune_data = &powertune_data_pitcairn; |
si_pi->dte_data = dte_data_curacao_xt; |
update_dte_from_pl2 = true; |
break; |
case 0x6819: |
case 0x6811: |
si_pi->cac_weights = cac_weights_pitcairn; |
si_pi->lcac_config = lcac_pitcairn; |
si_pi->cac_override = cac_override_pitcairn; |
si_pi->powertune_data = &powertune_data_pitcairn; |
si_pi->dte_data = dte_data_curacao_pro; |
update_dte_from_pl2 = true; |
break; |
case 0x6800: |
case 0x6806: |
si_pi->cac_weights = cac_weights_pitcairn; |
si_pi->lcac_config = lcac_pitcairn; |
si_pi->cac_override = cac_override_pitcairn; |
si_pi->powertune_data = &powertune_data_pitcairn; |
si_pi->dte_data = dte_data_neptune_xt; |
update_dte_from_pl2 = true; |
break; |
default: |
si_pi->cac_weights = cac_weights_pitcairn; |
si_pi->lcac_config = lcac_pitcairn; |
si_pi->cac_override = cac_override_pitcairn; |
si_pi->powertune_data = &powertune_data_pitcairn; |
si_pi->dte_data = dte_data_pitcairn; |
break; |
} |
} else if (rdev->family == CHIP_VERDE) { |
si_pi->lcac_config = lcac_cape_verde; |
si_pi->cac_override = cac_override_cape_verde; |
si_pi->powertune_data = &powertune_data_cape_verde; |
switch (rdev->pdev->device) { |
case 0x683B: |
case 0x683F: |
case 0x6829: |
case 0x6835: |
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; |
si_pi->dte_data = dte_data_cape_verde; |
break; |
case 0x6824: |
case 0x682D: |
si_pi->cac_weights = cac_weights_chelsea_xt; |
si_pi->dte_data = dte_data_cape_verde; |
break; |
case 0x682F: |
si_pi->cac_weights = cac_weights_chelsea_pro; |
si_pi->dte_data = dte_data_cape_verde; |
break; |
case 0x6820: |
si_pi->cac_weights = cac_weights_heathrow; |
si_pi->dte_data = dte_data_venus_xtx; |
break; |
case 0x6821: |
si_pi->cac_weights = cac_weights_heathrow; |
si_pi->dte_data = dte_data_venus_xt; |
break; |
case 0x6823: |
case 0x682B: |
case 0x6822: |
case 0x682A: |
si_pi->cac_weights = cac_weights_chelsea_pro; |
si_pi->dte_data = dte_data_venus_pro; |
break; |
default: |
si_pi->cac_weights = cac_weights_cape_verde; |
si_pi->dte_data = dte_data_cape_verde; |
break; |
} |
} else if (rdev->family == CHIP_OLAND) { |
switch (rdev->pdev->device) { |
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; |
si_pi->powertune_data = &powertune_data_mars_pro; |
si_pi->dte_data = dte_data_mars_pro; |
update_dte_from_pl2 = true; |
break; |
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; |
si_pi->powertune_data = &powertune_data_mars_pro; |
si_pi->dte_data = dte_data_mars_pro; |
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; |
si_pi->powertune_data = &powertune_data_mars_pro; |
si_pi->dte_data = dte_data_mars_pro; |
update_dte_from_pl2 = true; |
break; |
case 0x6610: |
si_pi->cac_weights = cac_weights_oland_xt; |
si_pi->lcac_config = lcac_mars_pro; |
si_pi->cac_override = cac_override_oland; |
si_pi->powertune_data = &powertune_data_mars_pro; |
si_pi->dte_data = dte_data_mars_pro; |
update_dte_from_pl2 = true; |
break; |
default: |
si_pi->cac_weights = cac_weights_oland; |
si_pi->lcac_config = lcac_oland; |
si_pi->cac_override = cac_override_oland; |
si_pi->powertune_data = &powertune_data_oland; |
si_pi->dte_data = dte_data_oland; |
break; |
} |
} else if (rdev->family == CHIP_HAINAN) { |
si_pi->cac_weights = cac_weights_hainan; |
si_pi->lcac_config = lcac_oland; |
si_pi->cac_override = cac_override_oland; |
si_pi->powertune_data = &powertune_data_hainan; |
si_pi->dte_data = dte_data_sun_xt; |
update_dte_from_pl2 = true; |
} else { |
DRM_ERROR("Unknown SI asic revision, failed to initialize PowerTune!\n"); |
return; |
} |
ni_pi->enable_power_containment = false; |
ni_pi->enable_cac = false; |
ni_pi->enable_sq_ramping = false; |
si_pi->enable_dte = false; |
if (si_pi->powertune_data->enable_powertune_by_default) { |
ni_pi->enable_power_containment= true; |
ni_pi->enable_cac = true; |
if (si_pi->dte_data.enable_dte_by_default) { |
si_pi->enable_dte = true; |
if (update_dte_from_pl2) |
si_update_dte_from_pl2(rdev, &si_pi->dte_data); |
} |
ni_pi->enable_sq_ramping = true; |
} |
ni_pi->driver_calculate_cac_leakage = true; |
ni_pi->cac_configuration_required = true; |
if (ni_pi->cac_configuration_required) { |
ni_pi->support_cac_long_term_average = true; |
si_pi->dyn_powertune_data.l2_lta_window_size = |
si_pi->powertune_data->l2_lta_window_size_default; |
si_pi->dyn_powertune_data.lts_truncate = |
si_pi->powertune_data->lts_truncate_default; |
} else { |
ni_pi->support_cac_long_term_average = false; |
si_pi->dyn_powertune_data.l2_lta_window_size = 0; |
si_pi->dyn_powertune_data.lts_truncate = 0; |
} |
si_pi->dyn_powertune_data.disable_uvd_powertune = false; |
} |
static u32 si_get_smc_power_scaling_factor(struct radeon_device *rdev) |
{ |
return 1; |
} |
static u32 si_calculate_cac_wintime(struct radeon_device *rdev) |
{ |
u32 xclk; |
u32 wintime; |
u32 cac_window; |
u32 cac_window_size; |
xclk = radeon_get_xclk(rdev); |
if (xclk == 0) |
return 0; |
cac_window = RREG32(CG_CAC_CTRL) & CAC_WINDOW_MASK; |
cac_window_size = ((cac_window & 0xFFFF0000) >> 16) * (cac_window & 0x0000FFFF); |
wintime = (cac_window_size * 100) / xclk; |
return wintime; |
} |
static u32 si_scale_power_for_smc(u32 power_in_watts, u32 scaling_factor) |
{ |
return power_in_watts; |
} |
static int si_calculate_adjusted_tdp_limits(struct radeon_device *rdev, |
bool adjust_polarity, |
u32 tdp_adjustment, |
u32 *tdp_limit, |
u32 *near_tdp_limit) |
{ |
u32 adjustment_delta, max_tdp_limit; |
if (tdp_adjustment > (u32)rdev->pm.dpm.tdp_od_limit) |
return -EINVAL; |
max_tdp_limit = ((100 + 100) * rdev->pm.dpm.tdp_limit) / 100; |
if (adjust_polarity) { |
*tdp_limit = ((100 + tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100; |
*near_tdp_limit = rdev->pm.dpm.near_tdp_limit_adjusted + (*tdp_limit - rdev->pm.dpm.tdp_limit); |
} else { |
*tdp_limit = ((100 - tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100; |
adjustment_delta = rdev->pm.dpm.tdp_limit - *tdp_limit; |
if (adjustment_delta < rdev->pm.dpm.near_tdp_limit_adjusted) |
*near_tdp_limit = rdev->pm.dpm.near_tdp_limit_adjusted - adjustment_delta; |
else |
*near_tdp_limit = 0; |
} |
if ((*tdp_limit <= 0) || (*tdp_limit > max_tdp_limit)) |
return -EINVAL; |
if ((*near_tdp_limit <= 0) || (*near_tdp_limit > *tdp_limit)) |
return -EINVAL; |
return 0; |
} |
static int si_populate_smc_tdp_limits(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
if (ni_pi->enable_power_containment) { |
SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable; |
PP_SIslands_PAPMParameters *papm_parm; |
struct radeon_ppm_table *ppm = rdev->pm.dpm.dyn_state.ppm_table; |
u32 scaling_factor = si_get_smc_power_scaling_factor(rdev); |
u32 tdp_limit; |
u32 near_tdp_limit; |
int ret; |
if (scaling_factor == 0) |
return -EINVAL; |
memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE)); |
ret = si_calculate_adjusted_tdp_limits(rdev, |
false, /* ??? */ |
rdev->pm.dpm.tdp_adjustment, |
&tdp_limit, |
&near_tdp_limit); |
if (ret) |
return ret; |
smc_table->dpm2Params.TDPLimit = |
cpu_to_be32(si_scale_power_for_smc(tdp_limit, scaling_factor) * 1000); |
smc_table->dpm2Params.NearTDPLimit = |
cpu_to_be32(si_scale_power_for_smc(near_tdp_limit, scaling_factor) * 1000); |
smc_table->dpm2Params.SafePowerLimit = |
cpu_to_be32(si_scale_power_for_smc((near_tdp_limit * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000); |
ret = si_copy_bytes_to_smc(rdev, |
(si_pi->state_table_start + offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) + |
offsetof(PP_SIslands_DPM2Parameters, TDPLimit)), |
(u8 *)(&(smc_table->dpm2Params.TDPLimit)), |
sizeof(u32) * 3, |
si_pi->sram_end); |
if (ret) |
return ret; |
if (si_pi->enable_ppm) { |
papm_parm = &si_pi->papm_parm; |
memset(papm_parm, 0, sizeof(PP_SIslands_PAPMParameters)); |
papm_parm->NearTDPLimitTherm = cpu_to_be32(ppm->dgpu_tdp); |
papm_parm->dGPU_T_Limit = cpu_to_be32(ppm->tj_max); |
papm_parm->dGPU_T_Warning = cpu_to_be32(95); |
papm_parm->dGPU_T_Hysteresis = cpu_to_be32(5); |
papm_parm->PlatformPowerLimit = 0xffffffff; |
papm_parm->NearTDPLimitPAPM = 0xffffffff; |
ret = si_copy_bytes_to_smc(rdev, si_pi->papm_cfg_table_start, |
(u8 *)papm_parm, |
sizeof(PP_SIslands_PAPMParameters), |
si_pi->sram_end); |
if (ret) |
return ret; |
} |
} |
return 0; |
} |
static int si_populate_smc_tdp_limits_2(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
if (ni_pi->enable_power_containment) { |
SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable; |
u32 scaling_factor = si_get_smc_power_scaling_factor(rdev); |
int ret; |
memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE)); |
smc_table->dpm2Params.NearTDPLimit = |
cpu_to_be32(si_scale_power_for_smc(rdev->pm.dpm.near_tdp_limit_adjusted, scaling_factor) * 1000); |
smc_table->dpm2Params.SafePowerLimit = |
cpu_to_be32(si_scale_power_for_smc((rdev->pm.dpm.near_tdp_limit_adjusted * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000); |
ret = si_copy_bytes_to_smc(rdev, |
(si_pi->state_table_start + |
offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) + |
offsetof(PP_SIslands_DPM2Parameters, NearTDPLimit)), |
(u8 *)(&(smc_table->dpm2Params.NearTDPLimit)), |
sizeof(u32) * 2, |
si_pi->sram_end); |
if (ret) |
return ret; |
} |
return 0; |
} |
static u16 si_calculate_power_efficiency_ratio(struct radeon_device *rdev, |
const u16 prev_std_vddc, |
const u16 curr_std_vddc) |
{ |
u64 margin = (u64)SISLANDS_DPM2_PWREFFICIENCYRATIO_MARGIN; |
u64 prev_vddc = (u64)prev_std_vddc; |
u64 curr_vddc = (u64)curr_std_vddc; |
u64 pwr_efficiency_ratio, n, d; |
if ((prev_vddc == 0) || (curr_vddc == 0)) |
return 0; |
n = div64_u64((u64)1024 * curr_vddc * curr_vddc * ((u64)1000 + margin), (u64)1000); |
d = prev_vddc * prev_vddc; |
pwr_efficiency_ratio = div64_u64(n, d); |
if (pwr_efficiency_ratio > (u64)0xFFFF) |
return 0; |
return (u16)pwr_efficiency_ratio; |
} |
static bool si_should_disable_uvd_powertune(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
if (si_pi->dyn_powertune_data.disable_uvd_powertune && |
radeon_state->vclk && radeon_state->dclk) |
return true; |
return false; |
} |
static int si_populate_power_containment_values(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
SISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
SISLANDS_SMC_VOLTAGE_VALUE vddc; |
u32 prev_sclk; |
u32 max_sclk; |
u32 min_sclk; |
u16 prev_std_vddc; |
u16 curr_std_vddc; |
int i; |
u16 pwr_efficiency_ratio; |
u8 max_ps_percent; |
bool disable_uvd_power_tune; |
int ret; |
if (ni_pi->enable_power_containment == false) |
return 0; |
if (state->performance_level_count == 0) |
return -EINVAL; |
if (smc_state->levelCount != state->performance_level_count) |
return -EINVAL; |
disable_uvd_power_tune = si_should_disable_uvd_powertune(rdev, radeon_state); |
smc_state->levels[0].dpm2.MaxPS = 0; |
smc_state->levels[0].dpm2.NearTDPDec = 0; |
smc_state->levels[0].dpm2.AboveSafeInc = 0; |
smc_state->levels[0].dpm2.BelowSafeInc = 0; |
smc_state->levels[0].dpm2.PwrEfficiencyRatio = 0; |
for (i = 1; i < state->performance_level_count; i++) { |
prev_sclk = state->performance_levels[i-1].sclk; |
max_sclk = state->performance_levels[i].sclk; |
if (i == 1) |
max_ps_percent = SISLANDS_DPM2_MAXPS_PERCENT_M; |
else |
max_ps_percent = SISLANDS_DPM2_MAXPS_PERCENT_H; |
if (prev_sclk > max_sclk) |
return -EINVAL; |
if ((max_ps_percent == 0) || |
(prev_sclk == max_sclk) || |
disable_uvd_power_tune) { |
min_sclk = max_sclk; |
} else if (i == 1) { |
min_sclk = prev_sclk; |
} else { |
min_sclk = (prev_sclk * (u32)max_ps_percent) / 100; |
} |
if (min_sclk < state->performance_levels[0].sclk) |
min_sclk = state->performance_levels[0].sclk; |
if (min_sclk == 0) |
return -EINVAL; |
ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
state->performance_levels[i-1].vddc, &vddc); |
if (ret) |
return ret; |
ret = si_get_std_voltage_value(rdev, &vddc, &prev_std_vddc); |
if (ret) |
return ret; |
ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
state->performance_levels[i].vddc, &vddc); |
if (ret) |
return ret; |
ret = si_get_std_voltage_value(rdev, &vddc, &curr_std_vddc); |
if (ret) |
return ret; |
pwr_efficiency_ratio = si_calculate_power_efficiency_ratio(rdev, |
prev_std_vddc, curr_std_vddc); |
smc_state->levels[i].dpm2.MaxPS = (u8)((SISLANDS_DPM2_MAX_PULSE_SKIP * (max_sclk - min_sclk)) / max_sclk); |
smc_state->levels[i].dpm2.NearTDPDec = SISLANDS_DPM2_NEAR_TDP_DEC; |
smc_state->levels[i].dpm2.AboveSafeInc = SISLANDS_DPM2_ABOVE_SAFE_INC; |
smc_state->levels[i].dpm2.BelowSafeInc = SISLANDS_DPM2_BELOW_SAFE_INC; |
smc_state->levels[i].dpm2.PwrEfficiencyRatio = cpu_to_be16(pwr_efficiency_ratio); |
} |
return 0; |
} |
static int si_populate_sq_ramping_values(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
SISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
u32 sq_power_throttle, sq_power_throttle2; |
bool enable_sq_ramping = ni_pi->enable_sq_ramping; |
int i; |
if (state->performance_level_count == 0) |
return -EINVAL; |
if (smc_state->levelCount != state->performance_level_count) |
return -EINVAL; |
if (rdev->pm.dpm.sq_ramping_threshold == 0) |
return -EINVAL; |
if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT)) |
enable_sq_ramping = false; |
if (SISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT)) |
enable_sq_ramping = false; |
if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT)) |
enable_sq_ramping = false; |
if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT)) |
enable_sq_ramping = false; |
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++) { |
sq_power_throttle = 0; |
sq_power_throttle2 = 0; |
if ((state->performance_levels[i].sclk >= rdev->pm.dpm.sq_ramping_threshold) && |
enable_sq_ramping) { |
sq_power_throttle |= MAX_POWER(SISLANDS_DPM2_SQ_RAMP_MAX_POWER); |
sq_power_throttle |= MIN_POWER(SISLANDS_DPM2_SQ_RAMP_MIN_POWER); |
sq_power_throttle2 |= MAX_POWER_DELTA(SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA); |
sq_power_throttle2 |= STI_SIZE(SISLANDS_DPM2_SQ_RAMP_STI_SIZE); |
sq_power_throttle2 |= LTI_RATIO(SISLANDS_DPM2_SQ_RAMP_LTI_RATIO); |
} else { |
sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK; |
sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; |
} |
smc_state->levels[i].SQPowerThrottle = cpu_to_be32(sq_power_throttle); |
smc_state->levels[i].SQPowerThrottle_2 = cpu_to_be32(sq_power_throttle2); |
} |
return 0; |
} |
static int si_enable_power_containment(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
bool enable) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
PPSMC_Result smc_result; |
int ret = 0; |
if (ni_pi->enable_power_containment) { |
if (enable) { |
if (!si_should_disable_uvd_powertune(rdev, radeon_new_state)) { |
smc_result = si_send_msg_to_smc(rdev, PPSMC_TDPClampingActive); |
if (smc_result != PPSMC_Result_OK) { |
ret = -EINVAL; |
ni_pi->pc_enabled = false; |
} else { |
ni_pi->pc_enabled = true; |
} |
} |
} else { |
smc_result = si_send_msg_to_smc(rdev, PPSMC_TDPClampingInactive); |
if (smc_result != PPSMC_Result_OK) |
ret = -EINVAL; |
ni_pi->pc_enabled = false; |
} |
} |
return ret; |
} |
static int si_initialize_smc_dte_tables(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
int ret = 0; |
struct si_dte_data *dte_data = &si_pi->dte_data; |
Smc_SIslands_DTE_Configuration *dte_tables = NULL; |
u32 table_size; |
u8 tdep_count; |
u32 i; |
if (dte_data == NULL) |
si_pi->enable_dte = false; |
if (si_pi->enable_dte == false) |
return 0; |
if (dte_data->k <= 0) |
return -EINVAL; |
dte_tables = kzalloc(sizeof(Smc_SIslands_DTE_Configuration), GFP_KERNEL); |
if (dte_tables == NULL) { |
si_pi->enable_dte = false; |
return -ENOMEM; |
} |
table_size = dte_data->k; |
if (table_size > SMC_SISLANDS_DTE_MAX_FILTER_STAGES) |
table_size = SMC_SISLANDS_DTE_MAX_FILTER_STAGES; |
tdep_count = dte_data->tdep_count; |
if (tdep_count > SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE) |
tdep_count = SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE; |
dte_tables->K = cpu_to_be32(table_size); |
dte_tables->T0 = cpu_to_be32(dte_data->t0); |
dte_tables->MaxT = cpu_to_be32(dte_data->max_t); |
dte_tables->WindowSize = dte_data->window_size; |
dte_tables->temp_select = dte_data->temp_select; |
dte_tables->DTE_mode = dte_data->dte_mode; |
dte_tables->Tthreshold = cpu_to_be32(dte_data->t_threshold); |
if (tdep_count > 0) |
table_size--; |
for (i = 0; i < table_size; i++) { |
dte_tables->tau[i] = cpu_to_be32(dte_data->tau[i]); |
dte_tables->R[i] = cpu_to_be32(dte_data->r[i]); |
} |
dte_tables->Tdep_count = tdep_count; |
for (i = 0; i < (u32)tdep_count; i++) { |
dte_tables->T_limits[i] = dte_data->t_limits[i]; |
dte_tables->Tdep_tau[i] = cpu_to_be32(dte_data->tdep_tau[i]); |
dte_tables->Tdep_R[i] = cpu_to_be32(dte_data->tdep_r[i]); |
} |
ret = si_copy_bytes_to_smc(rdev, si_pi->dte_table_start, (u8 *)dte_tables, |
sizeof(Smc_SIslands_DTE_Configuration), si_pi->sram_end); |
kfree(dte_tables); |
return ret; |
} |
static int si_get_cac_std_voltage_max_min(struct radeon_device *rdev, |
u16 *max, u16 *min) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct radeon_cac_leakage_table *table = |
&rdev->pm.dpm.dyn_state.cac_leakage_table; |
u32 i; |
u32 v0_loadline; |
if (table == NULL) |
return -EINVAL; |
*max = 0; |
*min = 0xFFFF; |
for (i = 0; i < table->count; i++) { |
if (table->entries[i].vddc > *max) |
*max = table->entries[i].vddc; |
if (table->entries[i].vddc < *min) |
*min = table->entries[i].vddc; |
} |
if (si_pi->powertune_data->lkge_lut_v0_percent > 100) |
return -EINVAL; |
v0_loadline = (*min) * (100 - si_pi->powertune_data->lkge_lut_v0_percent) / 100; |
if (v0_loadline > 0xFFFFUL) |
return -EINVAL; |
*min = (u16)v0_loadline; |
if ((*min > *max) || (*max == 0) || (*min == 0)) |
return -EINVAL; |
return 0; |
} |
static u16 si_get_cac_std_voltage_step(u16 max, u16 min) |
{ |
return ((max - min) + (SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES - 1)) / |
SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; |
} |
static int si_init_dte_leakage_table(struct radeon_device *rdev, |
PP_SIslands_CacConfig *cac_tables, |
u16 vddc_max, u16 vddc_min, u16 vddc_step, |
u16 t0, u16 t_step) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 leakage; |
unsigned int i, j; |
s32 t; |
u32 smc_leakage; |
u32 scaling_factor; |
u16 voltage; |
scaling_factor = si_get_smc_power_scaling_factor(rdev); |
for (i = 0; i < SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES ; i++) { |
t = (1000 * (i * t_step + t0)); |
for (j = 0; j < SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) { |
voltage = vddc_max - (vddc_step * j); |
si_calculate_leakage_for_v_and_t(rdev, |
&si_pi->powertune_data->leakage_coefficients, |
voltage, |
t, |
si_pi->dyn_powertune_data.cac_leakage, |
&leakage); |
smc_leakage = si_scale_power_for_smc(leakage, scaling_factor) / 4; |
if (smc_leakage > 0xFFFF) |
smc_leakage = 0xFFFF; |
cac_tables->cac_lkge_lut[i][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES-1-j] = |
cpu_to_be16((u16)smc_leakage); |
} |
} |
return 0; |
} |
static int si_init_simplified_leakage_table(struct radeon_device *rdev, |
PP_SIslands_CacConfig *cac_tables, |
u16 vddc_max, u16 vddc_min, u16 vddc_step) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 leakage; |
unsigned int i, j; |
u32 smc_leakage; |
u32 scaling_factor; |
u16 voltage; |
scaling_factor = si_get_smc_power_scaling_factor(rdev); |
for (j = 0; j < SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) { |
voltage = vddc_max - (vddc_step * j); |
si_calculate_leakage_for_v(rdev, |
&si_pi->powertune_data->leakage_coefficients, |
si_pi->powertune_data->fixed_kt, |
voltage, |
si_pi->dyn_powertune_data.cac_leakage, |
&leakage); |
smc_leakage = si_scale_power_for_smc(leakage, scaling_factor) / 4; |
if (smc_leakage > 0xFFFF) |
smc_leakage = 0xFFFF; |
for (i = 0; i < SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES ; i++) |
cac_tables->cac_lkge_lut[i][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES-1-j] = |
cpu_to_be16((u16)smc_leakage); |
} |
return 0; |
} |
static int si_initialize_smc_cac_tables(struct radeon_device *rdev) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
PP_SIslands_CacConfig *cac_tables = NULL; |
u16 vddc_max, vddc_min, vddc_step; |
u16 t0, t_step; |
u32 load_line_slope, reg; |
int ret = 0; |
u32 ticks_per_us = radeon_get_xclk(rdev) / 100; |
if (ni_pi->enable_cac == false) |
return 0; |
cac_tables = kzalloc(sizeof(PP_SIslands_CacConfig), GFP_KERNEL); |
if (!cac_tables) |
return -ENOMEM; |
reg = RREG32(CG_CAC_CTRL) & ~CAC_WINDOW_MASK; |
reg |= CAC_WINDOW(si_pi->powertune_data->cac_window); |
WREG32(CG_CAC_CTRL, reg); |
si_pi->dyn_powertune_data.cac_leakage = rdev->pm.dpm.cac_leakage; |
si_pi->dyn_powertune_data.dc_pwr_value = |
si_pi->powertune_data->dc_cac[NISLANDS_DCCAC_LEVEL_0]; |
si_pi->dyn_powertune_data.wintime = si_calculate_cac_wintime(rdev); |
si_pi->dyn_powertune_data.shift_n = si_pi->powertune_data->shift_n_default; |
si_pi->dyn_powertune_data.leakage_minimum_temperature = 80 * 1000; |
ret = si_get_cac_std_voltage_max_min(rdev, &vddc_max, &vddc_min); |
if (ret) |
goto done_free; |
vddc_step = si_get_cac_std_voltage_step(vddc_max, vddc_min); |
vddc_min = vddc_max - (vddc_step * (SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES - 1)); |
t_step = 4; |
t0 = 60; |
if (si_pi->enable_dte || ni_pi->driver_calculate_cac_leakage) |
ret = si_init_dte_leakage_table(rdev, cac_tables, |
vddc_max, vddc_min, vddc_step, |
t0, t_step); |
else |
ret = si_init_simplified_leakage_table(rdev, cac_tables, |
vddc_max, vddc_min, vddc_step); |
if (ret) |
goto done_free; |
load_line_slope = ((u32)rdev->pm.dpm.load_line_slope << SMC_SISLANDS_SCALE_R) / 100; |
cac_tables->l2numWin_TDP = cpu_to_be32(si_pi->dyn_powertune_data.l2_lta_window_size); |
cac_tables->lts_truncate_n = si_pi->dyn_powertune_data.lts_truncate; |
cac_tables->SHIFT_N = si_pi->dyn_powertune_data.shift_n; |
cac_tables->lkge_lut_V0 = cpu_to_be32((u32)vddc_min); |
cac_tables->lkge_lut_Vstep = cpu_to_be32((u32)vddc_step); |
cac_tables->R_LL = cpu_to_be32(load_line_slope); |
cac_tables->WinTime = cpu_to_be32(si_pi->dyn_powertune_data.wintime); |
cac_tables->calculation_repeats = cpu_to_be32(2); |
cac_tables->dc_cac = cpu_to_be32(0); |
cac_tables->log2_PG_LKG_SCALE = 12; |
cac_tables->cac_temp = si_pi->powertune_data->operating_temp; |
cac_tables->lkge_lut_T0 = cpu_to_be32((u32)t0); |
cac_tables->lkge_lut_Tstep = cpu_to_be32((u32)t_step); |
ret = si_copy_bytes_to_smc(rdev, si_pi->cac_table_start, (u8 *)cac_tables, |
sizeof(PP_SIslands_CacConfig), si_pi->sram_end); |
if (ret) |
goto done_free; |
ret = si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_ticks_per_us, ticks_per_us); |
done_free: |
if (ret) { |
ni_pi->enable_cac = false; |
ni_pi->enable_power_containment = false; |
} |
kfree(cac_tables); |
return 0; |
} |
static int si_program_cac_config_registers(struct radeon_device *rdev, |
const struct si_cac_config_reg *cac_config_regs) |
{ |
const struct si_cac_config_reg *config_regs = cac_config_regs; |
u32 data = 0, offset; |
if (!config_regs) |
return -EINVAL; |
while (config_regs->offset != 0xFFFFFFFF) { |
switch (config_regs->type) { |
case SISLANDS_CACCONFIG_CGIND: |
offset = SMC_CG_IND_START + config_regs->offset; |
if (offset < SMC_CG_IND_END) |
data = RREG32_SMC(offset); |
break; |
default: |
data = RREG32(config_regs->offset << 2); |
break; |
} |
data &= ~config_regs->mask; |
data |= ((config_regs->value << config_regs->shift) & config_regs->mask); |
switch (config_regs->type) { |
case SISLANDS_CACCONFIG_CGIND: |
offset = SMC_CG_IND_START + config_regs->offset; |
if (offset < SMC_CG_IND_END) |
WREG32_SMC(offset, data); |
break; |
default: |
WREG32(config_regs->offset << 2, data); |
break; |
} |
config_regs++; |
} |
return 0; |
} |
static int si_initialize_hardware_cac_manager(struct radeon_device *rdev) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
int ret; |
if ((ni_pi->enable_cac == false) || |
(ni_pi->cac_configuration_required == false)) |
return 0; |
ret = si_program_cac_config_registers(rdev, si_pi->lcac_config); |
if (ret) |
return ret; |
ret = si_program_cac_config_registers(rdev, si_pi->cac_override); |
if (ret) |
return ret; |
ret = si_program_cac_config_registers(rdev, si_pi->cac_weights); |
if (ret) |
return ret; |
return 0; |
} |
static int si_enable_smc_cac(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
bool enable) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
PPSMC_Result smc_result; |
int ret = 0; |
if (ni_pi->enable_cac) { |
if (enable) { |
if (!si_should_disable_uvd_powertune(rdev, radeon_new_state)) { |
if (ni_pi->support_cac_long_term_average) { |
smc_result = si_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgEnable); |
if (smc_result != PPSMC_Result_OK) |
ni_pi->support_cac_long_term_average = false; |
} |
smc_result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac); |
if (smc_result != PPSMC_Result_OK) { |
ret = -EINVAL; |
ni_pi->cac_enabled = false; |
} else { |
ni_pi->cac_enabled = true; |
} |
if (si_pi->enable_dte) { |
smc_result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableDTE); |
if (smc_result != PPSMC_Result_OK) |
ret = -EINVAL; |
} |
} |
} else if (ni_pi->cac_enabled) { |
if (si_pi->enable_dte) |
smc_result = si_send_msg_to_smc(rdev, PPSMC_MSG_DisableDTE); |
smc_result = si_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac); |
ni_pi->cac_enabled = false; |
if (ni_pi->support_cac_long_term_average) |
smc_result = si_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgDisable); |
} |
} |
return ret; |
} |
static int si_init_smc_spll_table(struct radeon_device *rdev) |
{ |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
SMC_SISLANDS_SPLL_DIV_TABLE *spll_table; |
SISLANDS_SMC_SCLK_VALUE sclk_params; |
u32 fb_div, p_div; |
u32 clk_s, clk_v; |
u32 sclk = 0; |
int ret = 0; |
u32 tmp; |
int i; |
if (si_pi->spll_table_start == 0) |
return -EINVAL; |
spll_table = kzalloc(sizeof(SMC_SISLANDS_SPLL_DIV_TABLE), GFP_KERNEL); |
if (spll_table == NULL) |
return -ENOMEM; |
for (i = 0; i < 256; i++) { |
ret = si_calculate_sclk_params(rdev, sclk, &sclk_params); |
if (ret) |
break; |
p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT; |
fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT; |
clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT; |
clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT; |
fb_div &= ~0x00001FFF; |
fb_div >>= 1; |
clk_v >>= 6; |
if (p_div & ~(SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT)) |
ret = -EINVAL; |
if (fb_div & ~(SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT)) |
ret = -EINVAL; |
if (clk_s & ~(SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT)) |
ret = -EINVAL; |
if (clk_v & ~(SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT)) |
ret = -EINVAL; |
if (ret) |
break; |
tmp = ((fb_div << SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK) | |
((p_div << SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK); |
spll_table->freq[i] = cpu_to_be32(tmp); |
tmp = ((clk_v << SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK) | |
((clk_s << SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK); |
spll_table->ss[i] = cpu_to_be32(tmp); |
sclk += 512; |
} |
if (!ret) |
ret = si_copy_bytes_to_smc(rdev, si_pi->spll_table_start, |
(u8 *)spll_table, sizeof(SMC_SISLANDS_SPLL_DIV_TABLE), |
si_pi->sram_end); |
if (ret) |
ni_pi->enable_power_containment = false; |
kfree(spll_table); |
return ret; |
} |
static void si_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct ni_ps *ps = ni_get_ps(rps); |
struct radeon_clock_and_voltage_limits *max_limits; |
bool disable_mclk_switching = false; |
bool disable_sclk_switching = false; |
u32 mclk, sclk; |
u16 vddc, vddci; |
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; |
int i; |
if ((rdev->pm.dpm.new_active_crtc_count > 1) || |
ni_dpm_vblank_too_short(rdev)) |
disable_mclk_switching = true; |
if (rps->vclk || rps->dclk) { |
disable_mclk_switching = true; |
disable_sclk_switching = true; |
} |
if (rdev->pm.dpm.ac_power) |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
else |
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc; |
for (i = ps->performance_level_count - 2; i >= 0; i--) { |
if (ps->performance_levels[i].vddc > ps->performance_levels[i+1].vddc) |
ps->performance_levels[i].vddc = ps->performance_levels[i+1].vddc; |
} |
if (rdev->pm.dpm.ac_power == false) { |
for (i = 0; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].mclk > max_limits->mclk) |
ps->performance_levels[i].mclk = max_limits->mclk; |
if (ps->performance_levels[i].sclk > max_limits->sclk) |
ps->performance_levels[i].sclk = max_limits->sclk; |
if (ps->performance_levels[i].vddc > max_limits->vddc) |
ps->performance_levels[i].vddc = max_limits->vddc; |
if (ps->performance_levels[i].vddci > max_limits->vddci) |
ps->performance_levels[i].vddci = max_limits->vddci; |
} |
} |
/* limit clocks to max supported clocks based on voltage dependency tables */ |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
&max_sclk_vddc); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
&max_mclk_vddci); |
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
&max_mclk_vddc); |
for (i = 0; i < ps->performance_level_count; i++) { |
if (max_sclk_vddc) { |
if (ps->performance_levels[i].sclk > max_sclk_vddc) |
ps->performance_levels[i].sclk = max_sclk_vddc; |
} |
if (max_mclk_vddci) { |
if (ps->performance_levels[i].mclk > max_mclk_vddci) |
ps->performance_levels[i].mclk = max_mclk_vddci; |
} |
if (max_mclk_vddc) { |
if (ps->performance_levels[i].mclk > max_mclk_vddc) |
ps->performance_levels[i].mclk = max_mclk_vddc; |
} |
} |
/* XXX validate the min clocks required for display */ |
if (disable_mclk_switching) { |
mclk = ps->performance_levels[ps->performance_level_count - 1].mclk; |
vddci = ps->performance_levels[ps->performance_level_count - 1].vddci; |
} else { |
mclk = ps->performance_levels[0].mclk; |
vddci = ps->performance_levels[0].vddci; |
} |
if (disable_sclk_switching) { |
sclk = ps->performance_levels[ps->performance_level_count - 1].sclk; |
vddc = ps->performance_levels[ps->performance_level_count - 1].vddc; |
} else { |
sclk = ps->performance_levels[0].sclk; |
vddc = ps->performance_levels[0].vddc; |
} |
/* 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; |
if (disable_sclk_switching) { |
sclk = ps->performance_levels[0].sclk; |
for (i = 1; i < ps->performance_level_count; i++) { |
if (sclk < ps->performance_levels[i].sclk) |
sclk = ps->performance_levels[i].sclk; |
} |
for (i = 0; i < ps->performance_level_count; i++) { |
ps->performance_levels[i].sclk = sclk; |
ps->performance_levels[i].vddc = vddc; |
} |
} else { |
for (i = 1; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk) |
ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk; |
if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc) |
ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc; |
} |
} |
if (disable_mclk_switching) { |
mclk = ps->performance_levels[0].mclk; |
for (i = 1; i < ps->performance_level_count; i++) { |
if (mclk < ps->performance_levels[i].mclk) |
mclk = ps->performance_levels[i].mclk; |
} |
for (i = 0; i < ps->performance_level_count; i++) { |
ps->performance_levels[i].mclk = mclk; |
ps->performance_levels[i].vddci = vddci; |
} |
} else { |
for (i = 1; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].mclk < ps->performance_levels[i - 1].mclk) |
ps->performance_levels[i].mclk = ps->performance_levels[i - 1].mclk; |
if (ps->performance_levels[i].vddci < ps->performance_levels[i - 1].vddci) |
ps->performance_levels[i].vddci = ps->performance_levels[i - 1].vddci; |
} |
} |
for (i = 0; i < ps->performance_level_count; i++) |
btc_adjust_clock_combinations(rdev, max_limits, |
&ps->performance_levels[i]); |
for (i = 0; i < ps->performance_level_count; i++) { |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, |
ps->performance_levels[i].sclk, |
max_limits->vddc, &ps->performance_levels[i].vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
ps->performance_levels[i].mclk, |
max_limits->vddci, &ps->performance_levels[i].vddci); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
ps->performance_levels[i].mclk, |
max_limits->vddc, &ps->performance_levels[i].vddc); |
btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk, |
rdev->clock.current_dispclk, |
max_limits->vddc, &ps->performance_levels[i].vddc); |
} |
for (i = 0; i < ps->performance_level_count; i++) { |
btc_apply_voltage_delta_rules(rdev, |
max_limits->vddc, max_limits->vddci, |
&ps->performance_levels[i].vddc, |
&ps->performance_levels[i].vddci); |
} |
ps->dc_compatible = true; |
for (i = 0; i < ps->performance_level_count; i++) { |
if (ps->performance_levels[i].vddc > rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) |
ps->dc_compatible = false; |
} |
} |
#if 0 |
static int si_read_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 *value) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
return si_read_smc_sram_dword(rdev, |
si_pi->soft_regs_start + reg_offset, value, |
si_pi->sram_end); |
} |
#endif |
static int si_write_smc_soft_register(struct radeon_device *rdev, |
u16 reg_offset, u32 value) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
return si_write_smc_sram_dword(rdev, |
si_pi->soft_regs_start + reg_offset, |
value, si_pi->sram_end); |
} |
static bool si_is_special_1gb_platform(struct radeon_device *rdev) |
{ |
bool ret = false; |
u32 tmp, width, row, column, bank, density; |
bool is_memory_gddr5, is_special; |
tmp = RREG32(MC_SEQ_MISC0); |
is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE == ((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT)); |
is_special = (MC_SEQ_MISC0_REV_ID_VALUE == ((tmp & MC_SEQ_MISC0_REV_ID_MASK) >> MC_SEQ_MISC0_REV_ID_SHIFT)) |
& (MC_SEQ_MISC0_VEN_ID_VALUE == ((tmp & MC_SEQ_MISC0_VEN_ID_MASK) >> MC_SEQ_MISC0_VEN_ID_SHIFT)); |
WREG32(MC_SEQ_IO_DEBUG_INDEX, 0xb); |
width = ((RREG32(MC_SEQ_IO_DEBUG_DATA) >> 1) & 1) ? 16 : 32; |
tmp = RREG32(MC_ARB_RAMCFG); |
row = ((tmp & NOOFROWS_MASK) >> NOOFROWS_SHIFT) + 10; |
column = ((tmp & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) + 8; |
bank = ((tmp & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + 2; |
density = (1 << (row + column - 20 + bank)) * width; |
if ((rdev->pdev->device == 0x6819) && |
is_memory_gddr5 && is_special && (density == 0x400)) |
ret = true; |
return ret; |
} |
static void si_get_leakage_vddc(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
u16 vddc, count = 0; |
int i, ret; |
for (i = 0; i < SISLANDS_MAX_LEAKAGE_COUNT; i++) { |
ret = radeon_atom_get_leakage_vddc_based_on_leakage_idx(rdev, &vddc, SISLANDS_LEAKAGE_INDEX0 + i); |
if (!ret && (vddc > 0) && (vddc != (SISLANDS_LEAKAGE_INDEX0 + i))) { |
si_pi->leakage_voltage.entries[count].voltage = vddc; |
si_pi->leakage_voltage.entries[count].leakage_index = |
SISLANDS_LEAKAGE_INDEX0 + i; |
count++; |
} |
} |
si_pi->leakage_voltage.count = count; |
} |
static int si_get_leakage_voltage_from_leakage_index(struct radeon_device *rdev, |
u32 index, u16 *leakage_voltage) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
int i; |
if (leakage_voltage == NULL) |
return -EINVAL; |
if ((index & 0xff00) != 0xff00) |
return -EINVAL; |
if ((index & 0xff) > SISLANDS_MAX_LEAKAGE_COUNT + 1) |
return -EINVAL; |
if (index < SISLANDS_LEAKAGE_INDEX0) |
return -EINVAL; |
for (i = 0; i < si_pi->leakage_voltage.count; i++) { |
if (si_pi->leakage_voltage.entries[i].leakage_index == index) { |
*leakage_voltage = si_pi->leakage_voltage.entries[i].voltage; |
return 0; |
} |
} |
return -EAGAIN; |
} |
static void si_set_dpm_event_sources(struct radeon_device *rdev, u32 sources) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
bool want_thermal_protection; |
enum radeon_dpm_event_src dpm_event_src; |
switch (sources) { |
case 0: |
default: |
want_thermal_protection = false; |
break; |
case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL; |
break; |
case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL; |
break; |
case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) | |
(1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)): |
want_thermal_protection = true; |
dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL; |
break; |
} |
if (want_thermal_protection) { |
WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK); |
if (pi->thermal_protection) |
WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); |
} else { |
WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); |
} |
} |
static void si_enable_auto_throttle_source(struct radeon_device *rdev, |
enum radeon_dpm_auto_throttle_src source, |
bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (enable) { |
if (!(pi->active_auto_throttle_sources & (1 << source))) { |
pi->active_auto_throttle_sources |= 1 << source; |
si_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); |
} |
} else { |
if (pi->active_auto_throttle_sources & (1 << source)) { |
pi->active_auto_throttle_sources &= ~(1 << source); |
si_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); |
} |
} |
} |
static void si_start_dpm(struct radeon_device *rdev) |
{ |
WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN); |
} |
static void si_stop_dpm(struct radeon_device *rdev) |
{ |
WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); |
} |
static void si_enable_sclk_control(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF); |
else |
WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF); |
} |
#if 0 |
static int si_notify_hardware_of_thermal_state(struct radeon_device *rdev, |
u32 thermal_level) |
{ |
PPSMC_Result ret; |
if (thermal_level == 0) { |
ret = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); |
if (ret == PPSMC_Result_OK) |
return 0; |
else |
return -EINVAL; |
} |
return 0; |
} |
static void si_notify_hardware_vpu_recovery_event(struct radeon_device *rdev) |
{ |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen, true); |
} |
#endif |
#if 0 |
static int si_notify_hw_of_powersource(struct radeon_device *rdev, bool ac_power) |
{ |
if (ac_power) |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
return 0; |
} |
#endif |
static PPSMC_Result si_send_msg_to_smc_with_parameter(struct radeon_device *rdev, |
PPSMC_Msg msg, u32 parameter) |
{ |
WREG32(SMC_SCRATCH0, parameter); |
return si_send_msg_to_smc(rdev, msg); |
} |
static int si_restrict_performance_levels_before_switch(struct radeon_device *rdev) |
{ |
if (si_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK) |
return -EINVAL; |
return (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
int si_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
struct radeon_ps *rps = rdev->pm.dpm.current_ps; |
struct ni_ps *ps = ni_get_ps(rps); |
u32 levels = ps->performance_level_count; |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK) |
return -EINVAL; |
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK) |
return -EINVAL; |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) |
return -EINVAL; |
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK) |
return -EINVAL; |
} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { |
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) |
return -EINVAL; |
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK) |
return -EINVAL; |
} |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
static int si_set_boot_state(struct radeon_device *rdev) |
{ |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static int si_set_sw_state(struct radeon_device *rdev) |
{ |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static int si_halt_smc(struct radeon_device *rdev) |
{ |
if (si_send_msg_to_smc(rdev, PPSMC_MSG_Halt) != PPSMC_Result_OK) |
return -EINVAL; |
return (si_wait_for_smc_inactive(rdev) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static int si_resume_smc(struct radeon_device *rdev) |
{ |
if (si_send_msg_to_smc(rdev, PPSMC_FlushDataCache) != PPSMC_Result_OK) |
return -EINVAL; |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_Resume) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static void si_dpm_start_smc(struct radeon_device *rdev) |
{ |
si_program_jump_on_start(rdev); |
si_start_smc(rdev); |
si_start_smc_clock(rdev); |
} |
static void si_dpm_stop_smc(struct radeon_device *rdev) |
{ |
si_reset_smc(rdev); |
si_stop_smc_clock(rdev); |
} |
static int si_process_firmware_header(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = si_read_smc_sram_dword(rdev, |
SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
SISLANDS_SMC_FIRMWARE_HEADER_stateTable, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
si_pi->state_table_start = tmp; |
ret = si_read_smc_sram_dword(rdev, |
SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
SISLANDS_SMC_FIRMWARE_HEADER_softRegisters, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
si_pi->soft_regs_start = tmp; |
ret = si_read_smc_sram_dword(rdev, |
SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
SISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
si_pi->mc_reg_table_start = tmp; |
ret = si_read_smc_sram_dword(rdev, |
SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
si_pi->arb_table_start = tmp; |
ret = si_read_smc_sram_dword(rdev, |
SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
SISLANDS_SMC_FIRMWARE_HEADER_CacConfigTable, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
si_pi->cac_table_start = tmp; |
ret = si_read_smc_sram_dword(rdev, |
SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
SISLANDS_SMC_FIRMWARE_HEADER_DteConfiguration, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
si_pi->dte_table_start = tmp; |
ret = si_read_smc_sram_dword(rdev, |
SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
SISLANDS_SMC_FIRMWARE_HEADER_spllTable, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
si_pi->spll_table_start = tmp; |
ret = si_read_smc_sram_dword(rdev, |
SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + |
SISLANDS_SMC_FIRMWARE_HEADER_PAPMParameters, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
si_pi->papm_cfg_table_start = tmp; |
return ret; |
} |
static void si_read_clock_registers(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
si_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL); |
si_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2); |
si_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3); |
si_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4); |
si_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM); |
si_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2); |
si_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL); |
si_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL); |
si_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL); |
si_pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL); |
si_pi->clock_registers.mpll_func_cntl = RREG32(MPLL_FUNC_CNTL); |
si_pi->clock_registers.mpll_func_cntl_1 = RREG32(MPLL_FUNC_CNTL_1); |
si_pi->clock_registers.mpll_func_cntl_2 = RREG32(MPLL_FUNC_CNTL_2); |
si_pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1); |
si_pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2); |
} |
static void si_enable_thermal_protection(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); |
else |
WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); |
} |
static void si_enable_acpi_power_management(struct radeon_device *rdev) |
{ |
WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN); |
} |
#if 0 |
static int si_enter_ulp_state(struct radeon_device *rdev) |
{ |
WREG32(SMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower); |
udelay(25000); |
return 0; |
} |
static int si_exit_ulp_state(struct radeon_device *rdev) |
{ |
int i; |
WREG32(SMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower); |
udelay(7000); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(SMC_RESP_0) == 1) |
break; |
udelay(1000); |
} |
return 0; |
} |
#endif |
static int si_notify_smc_display_change(struct radeon_device *rdev, |
bool has_display) |
{ |
PPSMC_Msg msg = has_display ? |
PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay; |
return (si_send_msg_to_smc(rdev, msg) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static void si_program_response_times(struct radeon_device *rdev) |
{ |
u32 voltage_response_time, backbias_response_time, acpi_delay_time, vbi_time_out; |
u32 vddc_dly, acpi_dly, vbi_dly; |
u32 reference_clock; |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_mvdd_chg_time, 1); |
voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time; |
backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time; |
if (voltage_response_time == 0) |
voltage_response_time = 1000; |
acpi_delay_time = 15000; |
vbi_time_out = 100000; |
reference_clock = radeon_get_xclk(rdev); |
vddc_dly = (voltage_response_time * reference_clock) / 100; |
acpi_dly = (acpi_delay_time * reference_clock) / 100; |
vbi_dly = (vbi_time_out * reference_clock) / 100; |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_delay_vreg, vddc_dly); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_delay_acpi, acpi_dly); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_mc_block_delay, 0xAA); |
} |
static void si_program_ds_registers(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
u32 tmp = 1; /* XXX: 0x10 on tahiti A0 */ |
if (eg_pi->sclk_deep_sleep) { |
WREG32_P(MISC_CLK_CNTL, DEEP_SLEEP_CLK_SEL(tmp), ~DEEP_SLEEP_CLK_SEL_MASK); |
WREG32_P(CG_SPLL_AUTOSCALE_CNTL, AUTOSCALE_ON_SS_CLEAR, |
~AUTOSCALE_ON_SS_CLEAR); |
} |
} |
static void si_program_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp, pipe; |
int i; |
tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK); |
if (rdev->pm.dpm.new_active_crtc_count > 0) |
tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); |
else |
tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE); |
if (rdev->pm.dpm.new_active_crtc_count > 1) |
tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); |
else |
tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE); |
WREG32(CG_DISPLAY_GAP_CNTL, tmp); |
tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG); |
pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT; |
if ((rdev->pm.dpm.new_active_crtc_count > 0) && |
(!(rdev->pm.dpm.new_active_crtcs & (1 << pipe)))) { |
/* find the first active crtc */ |
for (i = 0; i < rdev->num_crtc; i++) { |
if (rdev->pm.dpm.new_active_crtcs & (1 << i)) |
break; |
} |
if (i == rdev->num_crtc) |
pipe = 0; |
else |
pipe = i; |
tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK; |
tmp |= DCCG_DISP1_SLOW_SELECT(pipe); |
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); |
} |
static void si_enable_spread_spectrum(struct radeon_device *rdev, bool enable) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
if (enable) { |
if (pi->sclk_ss) |
WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); |
} else { |
WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN); |
WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); |
} |
} |
static void si_setup_bsp(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u32 xclk = radeon_get_xclk(rdev); |
r600_calculate_u_and_p(pi->asi, |
xclk, |
16, |
&pi->bsp, |
&pi->bsu); |
r600_calculate_u_and_p(pi->pasi, |
xclk, |
16, |
&pi->pbsp, |
&pi->pbsu); |
pi->dsp = BSP(pi->bsp) | BSU(pi->bsu); |
pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu); |
WREG32(CG_BSP, pi->dsp); |
} |
static void si_program_git(struct radeon_device *rdev) |
{ |
WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK); |
} |
static void si_program_tp(struct radeon_device *rdev) |
{ |
int i; |
enum r600_td td = R600_TD_DFLT; |
for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) |
WREG32(CG_FFCT_0 + (i * 4), (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i]))); |
if (td == R600_TD_AUTO) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL); |
else |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL); |
if (td == R600_TD_UP) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE); |
if (td == R600_TD_DOWN) |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE); |
} |
static void si_program_tpp(struct radeon_device *rdev) |
{ |
WREG32(CG_TPC, R600_TPC_DFLT); |
} |
static void si_program_sstp(struct radeon_device *rdev) |
{ |
WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT))); |
} |
static void si_enable_display_gap(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); |
tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK); |
tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) | |
DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE)); |
tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); |
tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) | |
DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE)); |
WREG32(CG_DISPLAY_GAP_CNTL, tmp); |
} |
static void si_program_vc(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
WREG32(CG_FTV, pi->vrc); |
} |
static void si_clear_vc(struct radeon_device *rdev) |
{ |
WREG32(CG_FTV, 0); |
} |
u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock) |
{ |
u8 mc_para_index; |
if (memory_clock < 10000) |
mc_para_index = 0; |
else if (memory_clock >= 80000) |
mc_para_index = 0x0f; |
else |
mc_para_index = (u8)((memory_clock - 10000) / 5000 + 1); |
return mc_para_index; |
} |
u8 si_get_mclk_frequency_ratio(u32 memory_clock, bool strobe_mode) |
{ |
u8 mc_para_index; |
if (strobe_mode) { |
if (memory_clock < 12500) |
mc_para_index = 0x00; |
else if (memory_clock > 47500) |
mc_para_index = 0x0f; |
else |
mc_para_index = (u8)((memory_clock - 10000) / 2500); |
} else { |
if (memory_clock < 65000) |
mc_para_index = 0x00; |
else if (memory_clock > 135000) |
mc_para_index = 0x0f; |
else |
mc_para_index = (u8)((memory_clock - 60000) / 5000); |
} |
return mc_para_index; |
} |
static u8 si_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
bool strobe_mode = false; |
u8 result = 0; |
if (mclk <= pi->mclk_strobe_mode_threshold) |
strobe_mode = true; |
if (pi->mem_gddr5) |
result = si_get_mclk_frequency_ratio(mclk, strobe_mode); |
else |
result = si_get_ddr3_mclk_frequency_ratio(mclk); |
if (strobe_mode) |
result |= SISLANDS_SMC_STROBE_ENABLE; |
return result; |
} |
static int si_upload_firmware(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
int ret; |
si_reset_smc(rdev); |
si_stop_smc_clock(rdev); |
ret = si_load_smc_ucode(rdev, si_pi->sram_end); |
return ret; |
} |
static bool si_validate_phase_shedding_tables(struct radeon_device *rdev, |
const struct atom_voltage_table *table, |
const struct radeon_phase_shedding_limits_table *limits) |
{ |
u32 data, num_bits, num_levels; |
if ((table == NULL) || (limits == NULL)) |
return false; |
data = table->mask_low; |
num_bits = hweight32(data); |
if (num_bits == 0) |
return false; |
num_levels = (1 << num_bits); |
if (table->count != num_levels) |
return false; |
if (limits->count != (num_levels - 1)) |
return false; |
return true; |
} |
void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev, |
u32 max_voltage_steps, |
struct atom_voltage_table *voltage_table) |
{ |
unsigned int i, diff; |
if (voltage_table->count <= max_voltage_steps) |
return; |
diff = voltage_table->count - max_voltage_steps; |
for (i= 0; i < max_voltage_steps; i++) |
voltage_table->entries[i] = voltage_table->entries[i + diff]; |
voltage_table->count = max_voltage_steps; |
} |
static int si_get_svi2_voltage_table(struct radeon_device *rdev, |
struct radeon_clock_voltage_dependency_table *voltage_dependency_table, |
struct atom_voltage_table *voltage_table) |
{ |
u32 i; |
if (voltage_dependency_table == NULL) |
return -EINVAL; |
voltage_table->mask_low = 0; |
voltage_table->phase_delay = 0; |
voltage_table->count = voltage_dependency_table->count; |
for (i = 0; i < voltage_table->count; i++) { |
voltage_table->entries[i].value = voltage_dependency_table->entries[i].v; |
voltage_table->entries[i].smio_low = 0; |
} |
return 0; |
} |
static int si_construct_voltage_tables(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
int ret; |
if (pi->voltage_control) { |
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC, |
VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table); |
if (ret) |
return ret; |
if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS) |
si_trim_voltage_table_to_fit_state_table(rdev, |
SISLANDS_MAX_NO_VREG_STEPS, |
&eg_pi->vddc_voltage_table); |
} else if (si_pi->voltage_control_svi2) { |
ret = si_get_svi2_voltage_table(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, |
&eg_pi->vddc_voltage_table); |
if (ret) |
return ret; |
} else { |
return -EINVAL; |
} |
if (eg_pi->vddci_control) { |
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDCI, |
VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddci_voltage_table); |
if (ret) |
return ret; |
if (eg_pi->vddci_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS) |
si_trim_voltage_table_to_fit_state_table(rdev, |
SISLANDS_MAX_NO_VREG_STEPS, |
&eg_pi->vddci_voltage_table); |
} |
if (si_pi->vddci_control_svi2) { |
ret = si_get_svi2_voltage_table(rdev, |
&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, |
&eg_pi->vddci_voltage_table); |
if (ret) |
return ret; |
} |
if (pi->mvdd_control) { |
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_MVDDC, |
VOLTAGE_OBJ_GPIO_LUT, &si_pi->mvdd_voltage_table); |
if (ret) { |
pi->mvdd_control = false; |
return ret; |
} |
if (si_pi->mvdd_voltage_table.count == 0) { |
pi->mvdd_control = false; |
return -EINVAL; |
} |
if (si_pi->mvdd_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS) |
si_trim_voltage_table_to_fit_state_table(rdev, |
SISLANDS_MAX_NO_VREG_STEPS, |
&si_pi->mvdd_voltage_table); |
} |
if (si_pi->vddc_phase_shed_control) { |
ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC, |
VOLTAGE_OBJ_PHASE_LUT, &si_pi->vddc_phase_shed_table); |
if (ret) |
si_pi->vddc_phase_shed_control = false; |
if ((si_pi->vddc_phase_shed_table.count == 0) || |
(si_pi->vddc_phase_shed_table.count > SISLANDS_MAX_NO_VREG_STEPS)) |
si_pi->vddc_phase_shed_control = false; |
} |
return 0; |
} |
static void si_populate_smc_voltage_table(struct radeon_device *rdev, |
const struct atom_voltage_table *voltage_table, |
SISLANDS_SMC_STATETABLE *table) |
{ |
unsigned int i; |
for (i = 0; i < voltage_table->count; i++) |
table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low); |
} |
static int si_populate_smc_voltage_tables(struct radeon_device *rdev, |
SISLANDS_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
u8 i; |
if (si_pi->voltage_control_svi2) { |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc, |
si_pi->svc_gpio_id); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd, |
si_pi->svd_gpio_id); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_plat_type, |
2); |
} else { |
if (eg_pi->vddc_voltage_table.count) { |
si_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table); |
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] = |
cpu_to_be32(eg_pi->vddc_voltage_table.mask_low); |
for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) { |
if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) { |
table->maxVDDCIndexInPPTable = i; |
break; |
} |
} |
} |
if (eg_pi->vddci_voltage_table.count) { |
si_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table); |
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] = |
cpu_to_be32(eg_pi->vddci_voltage_table.mask_low); |
} |
if (si_pi->mvdd_voltage_table.count) { |
si_populate_smc_voltage_table(rdev, &si_pi->mvdd_voltage_table, table); |
table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] = |
cpu_to_be32(si_pi->mvdd_voltage_table.mask_low); |
} |
if (si_pi->vddc_phase_shed_control) { |
if (si_validate_phase_shedding_tables(rdev, &si_pi->vddc_phase_shed_table, |
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) { |
si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table); |
table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] = |
cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay, |
(u32)si_pi->vddc_phase_shed_table.phase_delay); |
} else { |
si_pi->vddc_phase_shed_control = false; |
} |
} |
} |
return 0; |
} |
static int si_populate_voltage_value(struct radeon_device *rdev, |
const struct atom_voltage_table *table, |
u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage) |
{ |
unsigned int i; |
for (i = 0; i < table->count; i++) { |
if (value <= table->entries[i].value) { |
voltage->index = (u8)i; |
voltage->value = cpu_to_be16(table->entries[i].value); |
break; |
} |
} |
if (i >= table->count) |
return -EINVAL; |
return 0; |
} |
static int si_populate_mvdd_value(struct radeon_device *rdev, u32 mclk, |
SISLANDS_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
if (pi->mvdd_control) { |
if (mclk <= pi->mvdd_split_frequency) |
voltage->index = 0; |
else |
voltage->index = (u8)(si_pi->mvdd_voltage_table.count) - 1; |
voltage->value = cpu_to_be16(si_pi->mvdd_voltage_table.entries[voltage->index].value); |
} |
return 0; |
} |
static int si_get_std_voltage_value(struct radeon_device *rdev, |
SISLANDS_SMC_VOLTAGE_VALUE *voltage, |
u16 *std_voltage) |
{ |
u16 v_index; |
bool voltage_found = false; |
*std_voltage = be16_to_cpu(voltage->value); |
if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries) { |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE) { |
if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL) |
return -EINVAL; |
for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) { |
if (be16_to_cpu(voltage->value) == |
(u16)rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) { |
voltage_found = true; |
if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count) |
*std_voltage = |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[v_index].vddc; |
else |
*std_voltage = |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[rdev->pm.dpm.dyn_state.cac_leakage_table.count-1].vddc; |
break; |
} |
} |
if (!voltage_found) { |
for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) { |
if (be16_to_cpu(voltage->value) <= |
(u16)rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) { |
voltage_found = true; |
if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count) |
*std_voltage = |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[v_index].vddc; |
else |
*std_voltage = |
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[rdev->pm.dpm.dyn_state.cac_leakage_table.count-1].vddc; |
break; |
} |
} |
} |
} else { |
if ((u32)voltage->index < rdev->pm.dpm.dyn_state.cac_leakage_table.count) |
*std_voltage = rdev->pm.dpm.dyn_state.cac_leakage_table.entries[voltage->index].vddc; |
} |
} |
return 0; |
} |
static int si_populate_std_voltage_value(struct radeon_device *rdev, |
u16 value, u8 index, |
SISLANDS_SMC_VOLTAGE_VALUE *voltage) |
{ |
voltage->index = index; |
voltage->value = cpu_to_be16(value); |
return 0; |
} |
static int si_populate_phase_shedding_value(struct radeon_device *rdev, |
const struct radeon_phase_shedding_limits_table *limits, |
u16 voltage, u32 sclk, u32 mclk, |
SISLANDS_SMC_VOLTAGE_VALUE *smc_voltage) |
{ |
unsigned int i; |
for (i = 0; i < limits->count; i++) { |
if ((voltage <= limits->entries[i].voltage) && |
(sclk <= limits->entries[i].sclk) && |
(mclk <= limits->entries[i].mclk)) |
break; |
} |
smc_voltage->phase_settings = (u8)i; |
return 0; |
} |
static int si_init_arb_table_index(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = si_read_smc_sram_dword(rdev, si_pi->arb_table_start, &tmp, si_pi->sram_end); |
if (ret) |
return ret; |
tmp &= 0x00FFFFFF; |
tmp |= MC_CG_ARB_FREQ_F1 << 24; |
return si_write_smc_sram_dword(rdev, si_pi->arb_table_start, tmp, si_pi->sram_end); |
} |
static int si_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev) |
{ |
return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1); |
} |
static int si_reset_to_default(struct radeon_device *rdev) |
{ |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
static int si_force_switch_to_arb_f0(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 tmp; |
int ret; |
ret = si_read_smc_sram_dword(rdev, si_pi->arb_table_start, |
&tmp, si_pi->sram_end); |
if (ret) |
return ret; |
tmp = (tmp >> 24) & 0xff; |
if (tmp == MC_CG_ARB_FREQ_F0) |
return 0; |
return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0); |
} |
static u32 si_calculate_memory_refresh_rate(struct radeon_device *rdev, |
u32 engine_clock) |
{ |
u32 dram_rows; |
u32 dram_refresh_rate; |
u32 mc_arb_rfsh_rate; |
u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; |
if (tmp >= 4) |
dram_rows = 16384; |
else |
dram_rows = 1 << (tmp + 10); |
dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3); |
mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64; |
return mc_arb_rfsh_rate; |
} |
static int si_populate_memory_timing_parameters(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
SMC_SIslands_MCArbDramTimingRegisterSet *arb_regs) |
{ |
u32 dram_timing; |
u32 dram_timing2; |
u32 burst_time; |
arb_regs->mc_arb_rfsh_rate = |
(u8)si_calculate_memory_refresh_rate(rdev, pl->sclk); |
radeon_atom_set_engine_dram_timings(rdev, |
pl->sclk, |
pl->mclk); |
dram_timing = RREG32(MC_ARB_DRAM_TIMING); |
dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); |
burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK; |
arb_regs->mc_arb_dram_timing = cpu_to_be32(dram_timing); |
arb_regs->mc_arb_dram_timing2 = cpu_to_be32(dram_timing2); |
arb_regs->mc_arb_burst_time = (u8)burst_time; |
return 0; |
} |
static int si_do_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
unsigned int first_arb_set) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
SMC_SIslands_MCArbDramTimingRegisterSet arb_regs = { 0 }; |
int i, ret = 0; |
for (i = 0; i < state->performance_level_count; i++) { |
ret = si_populate_memory_timing_parameters(rdev, &state->performance_levels[i], &arb_regs); |
if (ret) |
break; |
ret = si_copy_bytes_to_smc(rdev, |
si_pi->arb_table_start + |
offsetof(SMC_SIslands_MCArbDramTimingRegisters, data) + |
sizeof(SMC_SIslands_MCArbDramTimingRegisterSet) * (first_arb_set + i), |
(u8 *)&arb_regs, |
sizeof(SMC_SIslands_MCArbDramTimingRegisterSet), |
si_pi->sram_end); |
if (ret) |
break; |
} |
return ret; |
} |
static int si_program_memory_timing_parameters(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
return si_do_program_memory_timing_parameters(rdev, radeon_new_state, |
SISLANDS_DRIVER_STATE_ARB_INDEX); |
} |
static int si_populate_initial_mvdd_value(struct radeon_device *rdev, |
struct SISLANDS_SMC_VOLTAGE_VALUE *voltage) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
if (pi->mvdd_control) |
return si_populate_voltage_value(rdev, &si_pi->mvdd_voltage_table, |
si_pi->mvdd_bootup_value, voltage); |
return 0; |
} |
static int si_populate_smc_initial_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_initial_state, |
SISLANDS_SMC_STATETABLE *table) |
{ |
struct ni_ps *initial_state = ni_get_ps(radeon_initial_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 reg; |
int ret; |
table->initialState.levels[0].mclk.vDLL_CNTL = |
cpu_to_be32(si_pi->clock_registers.dll_cntl); |
table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL = |
cpu_to_be32(si_pi->clock_registers.mclk_pwrmgt_cntl); |
table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL = |
cpu_to_be32(si_pi->clock_registers.mpll_ad_func_cntl); |
table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL = |
cpu_to_be32(si_pi->clock_registers.mpll_dq_func_cntl); |
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL = |
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl); |
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_1 = |
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_1); |
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_2 = |
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_2); |
table->initialState.levels[0].mclk.vMPLL_SS = |
cpu_to_be32(si_pi->clock_registers.mpll_ss1); |
table->initialState.levels[0].mclk.vMPLL_SS2 = |
cpu_to_be32(si_pi->clock_registers.mpll_ss2); |
table->initialState.levels[0].mclk.mclk_value = |
cpu_to_be32(initial_state->performance_levels[0].mclk); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = |
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = |
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_2); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = |
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_3); |
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 = |
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_4); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM = |
cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum); |
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 = |
cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum_2); |
table->initialState.levels[0].sclk.sclk_value = |
cpu_to_be32(initial_state->performance_levels[0].sclk); |
table->initialState.levels[0].arbRefreshState = |
SISLANDS_INITIAL_STATE_ARB_INDEX; |
table->initialState.levels[0].ACIndex = 0; |
ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
initial_state->performance_levels[0].vddc, |
&table->initialState.levels[0].vddc); |
if (!ret) { |
u16 std_vddc; |
ret = si_get_std_voltage_value(rdev, |
&table->initialState.levels[0].vddc, |
&std_vddc); |
if (!ret) |
si_populate_std_voltage_value(rdev, std_vddc, |
table->initialState.levels[0].vddc.index, |
&table->initialState.levels[0].std_vddc); |
} |
if (eg_pi->vddci_control) |
si_populate_voltage_value(rdev, |
&eg_pi->vddci_voltage_table, |
initial_state->performance_levels[0].vddci, |
&table->initialState.levels[0].vddci); |
if (si_pi->vddc_phase_shed_control) |
si_populate_phase_shedding_value(rdev, |
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table, |
initial_state->performance_levels[0].vddc, |
initial_state->performance_levels[0].sclk, |
initial_state->performance_levels[0].mclk, |
&table->initialState.levels[0].vddc); |
si_populate_initial_mvdd_value(rdev, &table->initialState.levels[0].mvdd); |
reg = CG_R(0xffff) | CG_L(0); |
table->initialState.levels[0].aT = cpu_to_be32(reg); |
table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp); |
table->initialState.levels[0].gen2PCIE = (u8)si_pi->boot_pcie_gen; |
if (pi->mem_gddr5) { |
table->initialState.levels[0].strobeMode = |
si_get_strobe_mode_settings(rdev, |
initial_state->performance_levels[0].mclk); |
if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold) |
table->initialState.levels[0].mcFlags = SISLANDS_SMC_MC_EDC_RD_FLAG | SISLANDS_SMC_MC_EDC_WR_FLAG; |
else |
table->initialState.levels[0].mcFlags = 0; |
} |
table->initialState.levelCount = 1; |
table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC; |
table->initialState.levels[0].dpm2.MaxPS = 0; |
table->initialState.levels[0].dpm2.NearTDPDec = 0; |
table->initialState.levels[0].dpm2.AboveSafeInc = 0; |
table->initialState.levels[0].dpm2.BelowSafeInc = 0; |
table->initialState.levels[0].dpm2.PwrEfficiencyRatio = 0; |
reg = MIN_POWER_MASK | MAX_POWER_MASK; |
table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg); |
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; |
table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg); |
return 0; |
} |
static int si_populate_smc_acpi_state(struct radeon_device *rdev, |
SISLANDS_SMC_STATETABLE *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 spll_func_cntl = si_pi->clock_registers.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = si_pi->clock_registers.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = si_pi->clock_registers.cg_spll_func_cntl_3; |
u32 spll_func_cntl_4 = si_pi->clock_registers.cg_spll_func_cntl_4; |
u32 dll_cntl = si_pi->clock_registers.dll_cntl; |
u32 mclk_pwrmgt_cntl = si_pi->clock_registers.mclk_pwrmgt_cntl; |
u32 mpll_ad_func_cntl = si_pi->clock_registers.mpll_ad_func_cntl; |
u32 mpll_dq_func_cntl = si_pi->clock_registers.mpll_dq_func_cntl; |
u32 mpll_func_cntl = si_pi->clock_registers.mpll_func_cntl; |
u32 mpll_func_cntl_1 = si_pi->clock_registers.mpll_func_cntl_1; |
u32 mpll_func_cntl_2 = si_pi->clock_registers.mpll_func_cntl_2; |
u32 reg; |
int ret; |
table->ACPIState = table->initialState; |
table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC; |
if (pi->acpi_vddc) { |
ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
pi->acpi_vddc, &table->ACPIState.levels[0].vddc); |
if (!ret) { |
u16 std_vddc; |
ret = si_get_std_voltage_value(rdev, |
&table->ACPIState.levels[0].vddc, &std_vddc); |
if (!ret) |
si_populate_std_voltage_value(rdev, std_vddc, |
table->ACPIState.levels[0].vddc.index, |
&table->ACPIState.levels[0].std_vddc); |
} |
table->ACPIState.levels[0].gen2PCIE = si_pi->acpi_pcie_gen; |
if (si_pi->vddc_phase_shed_control) { |
si_populate_phase_shedding_value(rdev, |
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table, |
pi->acpi_vddc, |
0, |
0, |
&table->ACPIState.levels[0].vddc); |
} |
} else { |
ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table, |
pi->min_vddc_in_table, &table->ACPIState.levels[0].vddc); |
if (!ret) { |
u16 std_vddc; |
ret = si_get_std_voltage_value(rdev, |
&table->ACPIState.levels[0].vddc, &std_vddc); |
if (!ret) |
si_populate_std_voltage_value(rdev, std_vddc, |
table->ACPIState.levels[0].vddc.index, |
&table->ACPIState.levels[0].std_vddc); |
} |
table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(rdev, |
si_pi->sys_pcie_mask, |
si_pi->boot_pcie_gen, |
RADEON_PCIE_GEN1); |
if (si_pi->vddc_phase_shed_control) |
si_populate_phase_shedding_value(rdev, |
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table, |
pi->min_vddc_in_table, |
0, |
0, |
&table->ACPIState.levels[0].vddc); |
} |
if (pi->acpi_vddc) { |
if (eg_pi->acpi_vddci) |
si_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table, |
eg_pi->acpi_vddci, |
&table->ACPIState.levels[0].vddci); |
} |
mclk_pwrmgt_cntl |= MRDCK0_RESET | MRDCK1_RESET; |
mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB); |
dll_cntl &= ~(MRDCK0_BYPASS | MRDCK1_BYPASS); |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(4); |
table->ACPIState.levels[0].mclk.vDLL_CNTL = |
cpu_to_be32(dll_cntl); |
table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL = |
cpu_to_be32(mclk_pwrmgt_cntl); |
table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL = |
cpu_to_be32(mpll_ad_func_cntl); |
table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL = |
cpu_to_be32(mpll_dq_func_cntl); |
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL = |
cpu_to_be32(mpll_func_cntl); |
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_1 = |
cpu_to_be32(mpll_func_cntl_1); |
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_2 = |
cpu_to_be32(mpll_func_cntl_2); |
table->ACPIState.levels[0].mclk.vMPLL_SS = |
cpu_to_be32(si_pi->clock_registers.mpll_ss1); |
table->ACPIState.levels[0].mclk.vMPLL_SS2 = |
cpu_to_be32(si_pi->clock_registers.mpll_ss2); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = |
cpu_to_be32(spll_func_cntl); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = |
cpu_to_be32(spll_func_cntl_2); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = |
cpu_to_be32(spll_func_cntl_3); |
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 = |
cpu_to_be32(spll_func_cntl_4); |
table->ACPIState.levels[0].mclk.mclk_value = 0; |
table->ACPIState.levels[0].sclk.sclk_value = 0; |
si_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd); |
if (eg_pi->dynamic_ac_timing) |
table->ACPIState.levels[0].ACIndex = 0; |
table->ACPIState.levels[0].dpm2.MaxPS = 0; |
table->ACPIState.levels[0].dpm2.NearTDPDec = 0; |
table->ACPIState.levels[0].dpm2.AboveSafeInc = 0; |
table->ACPIState.levels[0].dpm2.BelowSafeInc = 0; |
table->ACPIState.levels[0].dpm2.PwrEfficiencyRatio = 0; |
reg = MIN_POWER_MASK | MAX_POWER_MASK; |
table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg); |
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; |
table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg); |
return 0; |
} |
static int si_populate_ulv_state(struct radeon_device *rdev, |
SISLANDS_SMC_SWSTATE *state) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct si_ulv_param *ulv = &si_pi->ulv; |
u32 sclk_in_sr = 1350; /* ??? */ |
int ret; |
ret = si_convert_power_level_to_smc(rdev, &ulv->pl, |
&state->levels[0]); |
if (!ret) { |
if (eg_pi->sclk_deep_sleep) { |
if (sclk_in_sr <= SCLK_MIN_DEEPSLEEP_FREQ) |
state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS; |
else |
state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE; |
} |
if (ulv->one_pcie_lane_in_ulv) |
state->flags |= PPSMC_SWSTATE_FLAG_PCIE_X1; |
state->levels[0].arbRefreshState = (u8)(SISLANDS_ULV_STATE_ARB_INDEX); |
state->levels[0].ACIndex = 1; |
state->levels[0].std_vddc = state->levels[0].vddc; |
state->levelCount = 1; |
state->flags |= PPSMC_SWSTATE_FLAG_DC; |
} |
return ret; |
} |
static int si_program_ulv_memory_timing_parameters(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct si_ulv_param *ulv = &si_pi->ulv; |
SMC_SIslands_MCArbDramTimingRegisterSet arb_regs = { 0 }; |
int ret; |
ret = si_populate_memory_timing_parameters(rdev, &ulv->pl, |
&arb_regs); |
if (ret) |
return ret; |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_ulv_volt_change_delay, |
ulv->volt_change_delay); |
ret = si_copy_bytes_to_smc(rdev, |
si_pi->arb_table_start + |
offsetof(SMC_SIslands_MCArbDramTimingRegisters, data) + |
sizeof(SMC_SIslands_MCArbDramTimingRegisterSet) * SISLANDS_ULV_STATE_ARB_INDEX, |
(u8 *)&arb_regs, |
sizeof(SMC_SIslands_MCArbDramTimingRegisterSet), |
si_pi->sram_end); |
return ret; |
} |
static void si_get_mvdd_configuration(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
pi->mvdd_split_frequency = 30000; |
} |
static int si_init_smc_table(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps; |
const struct si_ulv_param *ulv = &si_pi->ulv; |
SISLANDS_SMC_STATETABLE *table = &si_pi->smc_statetable; |
int ret; |
u32 lane_width; |
u32 vr_hot_gpio; |
si_populate_smc_voltage_tables(rdev, table); |
switch (rdev->pm.int_thermal_type) { |
case THERMAL_TYPE_SI: |
case THERMAL_TYPE_EMC2103_WITH_INTERNAL: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL; |
break; |
case THERMAL_TYPE_NONE: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE; |
break; |
default: |
table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL; |
break; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT) { |
if ((rdev->pdev->device != 0x6818) && (rdev->pdev->device != 0x6819)) |
table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT; |
} |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) |
table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; |
if (pi->mem_gddr5) |
table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5; |
if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY) |
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; |
vr_hot_gpio = rdev->pm.dpm.backbias_response_time; |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_vr_hot_gpio, |
vr_hot_gpio); |
} |
ret = si_populate_smc_initial_state(rdev, radeon_boot_state, table); |
if (ret) |
return ret; |
ret = si_populate_smc_acpi_state(rdev, table); |
if (ret) |
return ret; |
table->driverState = table->initialState; |
ret = si_do_program_memory_timing_parameters(rdev, radeon_boot_state, |
SISLANDS_INITIAL_STATE_ARB_INDEX); |
if (ret) |
return ret; |
if (ulv->supported && ulv->pl.vddc) { |
ret = si_populate_ulv_state(rdev, &table->ULVState); |
if (ret) |
return ret; |
ret = si_program_ulv_memory_timing_parameters(rdev); |
if (ret) |
return ret; |
WREG32(CG_ULV_CONTROL, ulv->cg_ulv_control); |
WREG32(CG_ULV_PARAMETER, ulv->cg_ulv_parameter); |
lane_width = radeon_get_pcie_lanes(rdev); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width, lane_width); |
} else { |
table->ULVState = table->initialState; |
} |
return si_copy_bytes_to_smc(rdev, si_pi->state_table_start, |
(u8 *)table, sizeof(SISLANDS_SMC_STATETABLE), |
si_pi->sram_end); |
} |
static int si_calculate_sclk_params(struct radeon_device *rdev, |
u32 engine_clock, |
SISLANDS_SMC_SCLK_VALUE *sclk) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct atom_clock_dividers dividers; |
u32 spll_func_cntl = si_pi->clock_registers.cg_spll_func_cntl; |
u32 spll_func_cntl_2 = si_pi->clock_registers.cg_spll_func_cntl_2; |
u32 spll_func_cntl_3 = si_pi->clock_registers.cg_spll_func_cntl_3; |
u32 spll_func_cntl_4 = si_pi->clock_registers.cg_spll_func_cntl_4; |
u32 cg_spll_spread_spectrum = si_pi->clock_registers.cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2 = si_pi->clock_registers.cg_spll_spread_spectrum_2; |
u64 tmp; |
u32 reference_clock = rdev->clock.spll.reference_freq; |
u32 reference_divider; |
u32 fbdiv; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
engine_clock, false, ÷rs); |
if (ret) |
return ret; |
reference_divider = 1 + dividers.ref_div; |
tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16384; |
do_div(tmp, reference_clock); |
fbdiv = (u32) tmp; |
spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK); |
spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div); |
spll_func_cntl |= SPLL_PDIV_A(dividers.post_div); |
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; |
spll_func_cntl_2 |= SCLK_MUX_SEL(2); |
spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK; |
spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv); |
spll_func_cntl_3 |= SPLL_DITHEN; |
if (pi->sclk_ss) { |
struct radeon_atom_ss ss; |
u32 vco_freq = engine_clock * dividers.post_div; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_ENGINE_SS, vco_freq)) { |
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); |
u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000); |
cg_spll_spread_spectrum &= ~CLK_S_MASK; |
cg_spll_spread_spectrum |= CLK_S(clk_s); |
cg_spll_spread_spectrum |= SSEN; |
cg_spll_spread_spectrum_2 &= ~CLK_V_MASK; |
cg_spll_spread_spectrum_2 |= CLK_V(clk_v); |
} |
} |
sclk->sclk_value = engine_clock; |
sclk->vCG_SPLL_FUNC_CNTL = spll_func_cntl; |
sclk->vCG_SPLL_FUNC_CNTL_2 = spll_func_cntl_2; |
sclk->vCG_SPLL_FUNC_CNTL_3 = spll_func_cntl_3; |
sclk->vCG_SPLL_FUNC_CNTL_4 = spll_func_cntl_4; |
sclk->vCG_SPLL_SPREAD_SPECTRUM = cg_spll_spread_spectrum; |
sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cg_spll_spread_spectrum_2; |
return 0; |
} |
static int si_populate_sclk_value(struct radeon_device *rdev, |
u32 engine_clock, |
SISLANDS_SMC_SCLK_VALUE *sclk) |
{ |
SISLANDS_SMC_SCLK_VALUE sclk_tmp; |
int ret; |
ret = si_calculate_sclk_params(rdev, engine_clock, &sclk_tmp); |
if (!ret) { |
sclk->sclk_value = cpu_to_be32(sclk_tmp.sclk_value); |
sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL); |
sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_2); |
sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_3); |
sclk->vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_4); |
sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM); |
sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM_2); |
} |
return ret; |
} |
static int si_populate_mclk_value(struct radeon_device *rdev, |
u32 engine_clock, |
u32 memory_clock, |
SISLANDS_SMC_MCLK_VALUE *mclk, |
bool strobe_mode, |
bool dll_state_on) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 dll_cntl = si_pi->clock_registers.dll_cntl; |
u32 mclk_pwrmgt_cntl = si_pi->clock_registers.mclk_pwrmgt_cntl; |
u32 mpll_ad_func_cntl = si_pi->clock_registers.mpll_ad_func_cntl; |
u32 mpll_dq_func_cntl = si_pi->clock_registers.mpll_dq_func_cntl; |
u32 mpll_func_cntl = si_pi->clock_registers.mpll_func_cntl; |
u32 mpll_func_cntl_1 = si_pi->clock_registers.mpll_func_cntl_1; |
u32 mpll_func_cntl_2 = si_pi->clock_registers.mpll_func_cntl_2; |
u32 mpll_ss1 = si_pi->clock_registers.mpll_ss1; |
u32 mpll_ss2 = si_pi->clock_registers.mpll_ss2; |
struct atom_mpll_param mpll_param; |
int ret; |
ret = radeon_atom_get_memory_pll_dividers(rdev, memory_clock, strobe_mode, &mpll_param); |
if (ret) |
return ret; |
mpll_func_cntl &= ~BWCTRL_MASK; |
mpll_func_cntl |= BWCTRL(mpll_param.bwcntl); |
mpll_func_cntl_1 &= ~(CLKF_MASK | CLKFRAC_MASK | VCO_MODE_MASK); |
mpll_func_cntl_1 |= CLKF(mpll_param.clkf) | |
CLKFRAC(mpll_param.clkfrac) | VCO_MODE(mpll_param.vco_mode); |
mpll_ad_func_cntl &= ~YCLK_POST_DIV_MASK; |
mpll_ad_func_cntl |= YCLK_POST_DIV(mpll_param.post_div); |
if (pi->mem_gddr5) { |
mpll_dq_func_cntl &= ~(YCLK_SEL_MASK | YCLK_POST_DIV_MASK); |
mpll_dq_func_cntl |= YCLK_SEL(mpll_param.yclk_sel) | |
YCLK_POST_DIV(mpll_param.post_div); |
} |
if (pi->mclk_ss) { |
struct radeon_atom_ss ss; |
u32 freq_nom; |
u32 tmp; |
u32 reference_clock = rdev->clock.mpll.reference_freq; |
if (pi->mem_gddr5) |
freq_nom = memory_clock * 4; |
else |
freq_nom = memory_clock * 2; |
tmp = freq_nom / reference_clock; |
tmp = tmp * tmp; |
if (radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_MEMORY_SS, freq_nom)) { |
u32 clks = reference_clock * 5 / ss.rate; |
u32 clkv = (u32)((((131 * ss.percentage * ss.rate) / 100) * tmp) / freq_nom); |
mpll_ss1 &= ~CLKV_MASK; |
mpll_ss1 |= CLKV(clkv); |
mpll_ss2 &= ~CLKS_MASK; |
mpll_ss2 |= CLKS(clks); |
} |
} |
mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK; |
mclk_pwrmgt_cntl |= DLL_SPEED(mpll_param.dll_speed); |
if (dll_state_on) |
mclk_pwrmgt_cntl |= MRDCK0_PDNB | MRDCK1_PDNB; |
else |
mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB); |
mclk->mclk_value = cpu_to_be32(memory_clock); |
mclk->vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl); |
mclk->vMPLL_FUNC_CNTL_1 = cpu_to_be32(mpll_func_cntl_1); |
mclk->vMPLL_FUNC_CNTL_2 = cpu_to_be32(mpll_func_cntl_2); |
mclk->vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); |
mclk->vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); |
mclk->vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); |
mclk->vDLL_CNTL = cpu_to_be32(dll_cntl); |
mclk->vMPLL_SS = cpu_to_be32(mpll_ss1); |
mclk->vMPLL_SS2 = cpu_to_be32(mpll_ss2); |
return 0; |
} |
static void si_populate_smc_sp(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
SISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct ni_ps *ps = ni_get_ps(radeon_state); |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
int i; |
for (i = 0; i < ps->performance_level_count - 1; i++) |
smc_state->levels[i].bSP = cpu_to_be32(pi->dsp); |
smc_state->levels[ps->performance_level_count - 1].bSP = |
cpu_to_be32(pi->psp); |
} |
static int si_convert_power_level_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
SISLANDS_SMC_HW_PERFORMANCE_LEVEL *level) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
int ret; |
bool dll_state_on; |
u16 std_vddc; |
bool gmc_pg = false; |
if (eg_pi->pcie_performance_request && |
(si_pi->force_pcie_gen != RADEON_PCIE_GEN_INVALID)) |
level->gen2PCIE = (u8)si_pi->force_pcie_gen; |
else |
level->gen2PCIE = (u8)pl->pcie_gen; |
ret = si_populate_sclk_value(rdev, pl->sclk, &level->sclk); |
if (ret) |
return ret; |
level->mcFlags = 0; |
if (pi->mclk_stutter_mode_threshold && |
(pl->mclk <= pi->mclk_stutter_mode_threshold) && |
!eg_pi->uvd_enabled && |
(RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) && |
(rdev->pm.dpm.new_active_crtc_count <= 2)) { |
level->mcFlags |= SISLANDS_SMC_MC_STUTTER_EN; |
if (gmc_pg) |
level->mcFlags |= SISLANDS_SMC_MC_PG_EN; |
} |
if (pi->mem_gddr5) { |
if (pl->mclk > pi->mclk_edc_enable_threshold) |
level->mcFlags |= SISLANDS_SMC_MC_EDC_RD_FLAG; |
if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold) |
level->mcFlags |= SISLANDS_SMC_MC_EDC_WR_FLAG; |
level->strobeMode = si_get_strobe_mode_settings(rdev, pl->mclk); |
if (level->strobeMode & SISLANDS_SMC_STROBE_ENABLE) { |
if (si_get_mclk_frequency_ratio(pl->mclk, true) >= |
((RREG32(MC_SEQ_MISC7) >> 16) & 0xf)) |
dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false; |
else |
dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false; |
} else { |
dll_state_on = false; |
} |
} else { |
level->strobeMode = si_get_strobe_mode_settings(rdev, |
pl->mclk); |
dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false; |
} |
ret = si_populate_mclk_value(rdev, |
pl->sclk, |
pl->mclk, |
&level->mclk, |
(level->strobeMode & SISLANDS_SMC_STROBE_ENABLE) != 0, dll_state_on); |
if (ret) |
return ret; |
ret = si_populate_voltage_value(rdev, |
&eg_pi->vddc_voltage_table, |
pl->vddc, &level->vddc); |
if (ret) |
return ret; |
ret = si_get_std_voltage_value(rdev, &level->vddc, &std_vddc); |
if (ret) |
return ret; |
ret = si_populate_std_voltage_value(rdev, std_vddc, |
level->vddc.index, &level->std_vddc); |
if (ret) |
return ret; |
if (eg_pi->vddci_control) { |
ret = si_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table, |
pl->vddci, &level->vddci); |
if (ret) |
return ret; |
} |
if (si_pi->vddc_phase_shed_control) { |
ret = si_populate_phase_shedding_value(rdev, |
&rdev->pm.dpm.dyn_state.phase_shedding_limits_table, |
pl->vddc, |
pl->sclk, |
pl->mclk, |
&level->vddc); |
if (ret) |
return ret; |
} |
level->MaxPoweredUpCU = si_pi->max_cu; |
ret = si_populate_mvdd_value(rdev, pl->mclk, &level->mvdd); |
return ret; |
} |
static int si_populate_smc_t(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
SISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
u32 a_t; |
u32 t_l, t_h; |
u32 high_bsp; |
int i, ret; |
if (state->performance_level_count >= 9) |
return -EINVAL; |
if (state->performance_level_count < 2) { |
a_t = CG_R(0xffff) | CG_L(0); |
smc_state->levels[0].aT = cpu_to_be32(a_t); |
return 0; |
} |
smc_state->levels[0].aT = cpu_to_be32(0); |
for (i = 0; i <= state->performance_level_count - 2; i++) { |
ret = r600_calculate_at( |
(50 / SISLANDS_MAX_HARDWARE_POWERLEVELS) * 100 * (i + 1), |
100 * R600_AH_DFLT, |
state->performance_levels[i + 1].sclk, |
state->performance_levels[i].sclk, |
&t_l, |
&t_h); |
if (ret) { |
t_h = (i + 1) * 1000 - 50 * R600_AH_DFLT; |
t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT; |
} |
a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK; |
a_t |= CG_R(t_l * pi->bsp / 20000); |
smc_state->levels[i].aT = cpu_to_be32(a_t); |
high_bsp = (i == state->performance_level_count - 2) ? |
pi->pbsp : pi->bsp; |
a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000); |
smc_state->levels[i + 1].aT = cpu_to_be32(a_t); |
} |
return 0; |
} |
static int si_disable_ulv(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct si_ulv_param *ulv = &si_pi->ulv; |
if (ulv->supported) |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
return 0; |
} |
static bool si_is_state_ulv_compatible(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
const struct si_power_info *si_pi = si_get_pi(rdev); |
const struct si_ulv_param *ulv = &si_pi->ulv; |
const struct ni_ps *state = ni_get_ps(radeon_state); |
int i; |
if (state->performance_levels[0].mclk != ulv->pl.mclk) |
return false; |
/* XXX validate against display requirements! */ |
for (i = 0; i < rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count; i++) { |
if (rdev->clock.current_dispclk <= |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].clk) { |
if (ulv->pl.vddc < |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].v) |
return false; |
} |
} |
if ((radeon_state->vclk != 0) || (radeon_state->dclk != 0)) |
return false; |
return true; |
} |
static int si_set_power_state_conditionally_enable_ulv(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
const struct si_power_info *si_pi = si_get_pi(rdev); |
const struct si_ulv_param *ulv = &si_pi->ulv; |
if (ulv->supported) { |
if (si_is_state_ulv_compatible(rdev, radeon_new_state)) |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_EnableULV) == PPSMC_Result_OK) ? |
0 : -EINVAL; |
} |
return 0; |
} |
static int si_convert_power_state_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
SISLANDS_SMC_SWSTATE *smc_state) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct ni_power_info *ni_pi = ni_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct ni_ps *state = ni_get_ps(radeon_state); |
int i, ret; |
u32 threshold; |
u32 sclk_in_sr = 1350; /* ??? */ |
if (state->performance_level_count > SISLANDS_MAX_HARDWARE_POWERLEVELS) |
return -EINVAL; |
threshold = state->performance_levels[state->performance_level_count-1].sclk * 100 / 100; |
if (radeon_state->vclk && radeon_state->dclk) { |
eg_pi->uvd_enabled = true; |
if (eg_pi->smu_uvd_hs) |
smc_state->flags |= PPSMC_SWSTATE_FLAG_UVD; |
} else { |
eg_pi->uvd_enabled = false; |
} |
if (state->dc_compatible) |
smc_state->flags |= PPSMC_SWSTATE_FLAG_DC; |
smc_state->levelCount = 0; |
for (i = 0; i < state->performance_level_count; i++) { |
if (eg_pi->sclk_deep_sleep) { |
if ((i == 0) || si_pi->sclk_deep_sleep_above_low) { |
if (sclk_in_sr <= SCLK_MIN_DEEPSLEEP_FREQ) |
smc_state->levels[i].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS; |
else |
smc_state->levels[i].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE; |
} |
} |
ret = si_convert_power_level_to_smc(rdev, &state->performance_levels[i], |
&smc_state->levels[i]); |
smc_state->levels[i].arbRefreshState = |
(u8)(SISLANDS_DRIVER_STATE_ARB_INDEX + i); |
if (ret) |
return ret; |
if (ni_pi->enable_power_containment) |
smc_state->levels[i].displayWatermark = |
(state->performance_levels[i].sclk < threshold) ? |
PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH; |
else |
smc_state->levels[i].displayWatermark = (i < 2) ? |
PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH; |
if (eg_pi->dynamic_ac_timing) |
smc_state->levels[i].ACIndex = SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i; |
else |
smc_state->levels[i].ACIndex = 0; |
smc_state->levelCount++; |
} |
si_write_smc_soft_register(rdev, |
SI_SMC_SOFT_REGISTER_watermark_threshold, |
threshold / 512); |
si_populate_smc_sp(rdev, radeon_state, smc_state); |
ret = si_populate_power_containment_values(rdev, radeon_state, smc_state); |
if (ret) |
ni_pi->enable_power_containment = false; |
ret = si_populate_sq_ramping_values(rdev, radeon_state, smc_state); |
if (ret) |
ni_pi->enable_sq_ramping = false; |
return si_populate_smc_t(rdev, radeon_state, smc_state); |
} |
static int si_upload_sw_state(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct ni_ps *new_state = ni_get_ps(radeon_new_state); |
int ret; |
u32 address = si_pi->state_table_start + |
offsetof(SISLANDS_SMC_STATETABLE, driverState); |
u32 state_size = sizeof(SISLANDS_SMC_SWSTATE) + |
((new_state->performance_level_count - 1) * |
sizeof(SISLANDS_SMC_HW_PERFORMANCE_LEVEL)); |
SISLANDS_SMC_SWSTATE *smc_state = &si_pi->smc_statetable.driverState; |
memset(smc_state, 0, state_size); |
ret = si_convert_power_state_to_smc(rdev, radeon_new_state, smc_state); |
if (ret) |
return ret; |
ret = si_copy_bytes_to_smc(rdev, address, (u8 *)smc_state, |
state_size, si_pi->sram_end); |
return ret; |
} |
static int si_upload_ulv_state(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct si_ulv_param *ulv = &si_pi->ulv; |
int ret = 0; |
if (ulv->supported && ulv->pl.vddc) { |
u32 address = si_pi->state_table_start + |
offsetof(SISLANDS_SMC_STATETABLE, ULVState); |
SISLANDS_SMC_SWSTATE *smc_state = &si_pi->smc_statetable.ULVState; |
u32 state_size = sizeof(SISLANDS_SMC_SWSTATE); |
memset(smc_state, 0, state_size); |
ret = si_populate_ulv_state(rdev, smc_state); |
if (!ret) |
ret = si_copy_bytes_to_smc(rdev, address, (u8 *)smc_state, |
state_size, si_pi->sram_end); |
} |
return ret; |
} |
static int si_upload_smc_data(struct radeon_device *rdev) |
{ |
struct radeon_crtc *radeon_crtc = NULL; |
int i; |
if (rdev->pm.dpm.new_active_crtc_count == 0) |
return 0; |
for (i = 0; i < rdev->num_crtc; i++) { |
if (rdev->pm.dpm.new_active_crtcs & (1 << i)) { |
radeon_crtc = rdev->mode_info.crtcs[i]; |
break; |
} |
} |
if (radeon_crtc == NULL) |
return 0; |
if (radeon_crtc->line_time <= 0) |
return 0; |
if (si_write_smc_soft_register(rdev, |
SI_SMC_SOFT_REGISTER_crtc_index, |
radeon_crtc->crtc_id) != PPSMC_Result_OK) |
return 0; |
if (si_write_smc_soft_register(rdev, |
SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min, |
radeon_crtc->wm_high / radeon_crtc->line_time) != PPSMC_Result_OK) |
return 0; |
if (si_write_smc_soft_register(rdev, |
SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max, |
radeon_crtc->wm_low / radeon_crtc->line_time) != PPSMC_Result_OK) |
return 0; |
return 0; |
} |
static int si_set_mc_special_registers(struct radeon_device *rdev, |
struct si_mc_reg_table *table) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
u8 i, j, k; |
u32 temp_reg; |
for (i = 0, j = table->last; i < table->last; i++) { |
if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
switch (table->mc_reg_address[i].s1 << 2) { |
case MC_SEQ_MISC1: |
temp_reg = RREG32(MC_PMG_CMD_EMRS); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
for (k = 0; k < table->num_entries; k++) |
table->mc_reg_table_entry[k].mc_data[j] = |
((temp_reg & 0xffff0000)) | |
((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16); |
j++; |
if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
temp_reg = RREG32(MC_PMG_CMD_MRS); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
for (k = 0; k < table->num_entries; k++) { |
table->mc_reg_table_entry[k].mc_data[j] = |
(temp_reg & 0xffff0000) | |
(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); |
if (!pi->mem_gddr5) |
table->mc_reg_table_entry[k].mc_data[j] |= 0x100; |
} |
j++; |
if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
if (!pi->mem_gddr5) { |
table->mc_reg_address[j].s1 = MC_PMG_AUTO_CMD >> 2; |
table->mc_reg_address[j].s0 = MC_PMG_AUTO_CMD >> 2; |
for (k = 0; k < table->num_entries; k++) |
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) |
return -EINVAL; |
} |
break; |
case MC_SEQ_RESERVE_M: |
temp_reg = RREG32(MC_PMG_CMD_MRS1); |
table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2; |
table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
for(k = 0; k < table->num_entries; k++) |
table->mc_reg_table_entry[k].mc_data[j] = |
(temp_reg & 0xffff0000) | |
(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); |
j++; |
if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
break; |
default: |
break; |
} |
} |
table->last = j; |
return 0; |
} |
static bool si_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg) |
{ |
bool result = true; |
switch (in_reg) { |
case MC_SEQ_RAS_TIMING >> 2: |
*out_reg = MC_SEQ_RAS_TIMING_LP >> 2; |
break; |
case MC_SEQ_CAS_TIMING >> 2: |
*out_reg = MC_SEQ_CAS_TIMING_LP >> 2; |
break; |
case MC_SEQ_MISC_TIMING >> 2: |
*out_reg = MC_SEQ_MISC_TIMING_LP >> 2; |
break; |
case MC_SEQ_MISC_TIMING2 >> 2: |
*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2; |
break; |
case MC_SEQ_RD_CTL_D0 >> 2: |
*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2; |
break; |
case MC_SEQ_RD_CTL_D1 >> 2: |
*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_D0 >> 2: |
*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_D1 >> 2: |
*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2; |
break; |
case MC_PMG_CMD_EMRS >> 2: |
*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2; |
break; |
case MC_PMG_CMD_MRS >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2; |
break; |
case MC_PMG_CMD_MRS1 >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2; |
break; |
case MC_SEQ_PMG_TIMING >> 2: |
*out_reg = MC_SEQ_PMG_TIMING_LP >> 2; |
break; |
case MC_PMG_CMD_MRS2 >> 2: |
*out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2; |
break; |
case MC_SEQ_WR_CTL_2 >> 2: |
*out_reg = MC_SEQ_WR_CTL_2_LP >> 2; |
break; |
default: |
result = false; |
break; |
} |
return result; |
} |
static void si_set_valid_flag(struct si_mc_reg_table *table) |
{ |
u8 i, j; |
for (i = 0; i < table->last; i++) { |
for (j = 1; j < table->num_entries; j++) { |
if (table->mc_reg_table_entry[j-1].mc_data[i] != table->mc_reg_table_entry[j].mc_data[i]) { |
table->valid_flag |= 1 << i; |
break; |
} |
} |
} |
} |
static void si_set_s0_mc_reg_index(struct si_mc_reg_table *table) |
{ |
u32 i; |
u16 address; |
for (i = 0; i < table->last; i++) |
table->mc_reg_address[i].s0 = si_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ? |
address : table->mc_reg_address[i].s1; |
} |
static int si_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table, |
struct si_mc_reg_table *si_table) |
{ |
u8 i, j; |
if (table->last > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) |
return -EINVAL; |
if (table->num_entries > MAX_AC_TIMING_ENTRIES) |
return -EINVAL; |
for (i = 0; i < table->last; i++) |
si_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1; |
si_table->last = table->last; |
for (i = 0; i < table->num_entries; i++) { |
si_table->mc_reg_table_entry[i].mclk_max = |
table->mc_reg_table_entry[i].mclk_max; |
for (j = 0; j < table->last; j++) { |
si_table->mc_reg_table_entry[i].mc_data[j] = |
table->mc_reg_table_entry[i].mc_data[j]; |
} |
} |
si_table->num_entries = table->num_entries; |
return 0; |
} |
static int si_initialize_mc_reg_table(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct atom_mc_reg_table *table; |
struct si_mc_reg_table *si_table = &si_pi->mc_reg_table; |
u8 module_index = rv770_get_memory_module_index(rdev); |
int ret; |
table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL); |
if (!table) |
return -ENOMEM; |
WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING)); |
WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING)); |
WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING)); |
WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2)); |
WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS)); |
WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS)); |
WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1)); |
WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0)); |
WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1)); |
WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0)); |
WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1)); |
WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING)); |
WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2)); |
WREG32(MC_SEQ_WR_CTL_2_LP, RREG32(MC_SEQ_WR_CTL_2)); |
ret = radeon_atom_init_mc_reg_table(rdev, module_index, table); |
if (ret) |
goto init_mc_done; |
ret = si_copy_vbios_mc_reg_table(table, si_table); |
if (ret) |
goto init_mc_done; |
si_set_s0_mc_reg_index(si_table); |
ret = si_set_mc_special_registers(rdev, si_table); |
if (ret) |
goto init_mc_done; |
si_set_valid_flag(si_table); |
init_mc_done: |
kfree(table); |
return ret; |
} |
static void si_populate_mc_reg_addresses(struct radeon_device *rdev, |
SMC_SIslands_MCRegisters *mc_reg_table) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 i, j; |
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_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); |
mc_reg_table->address[i].s1 = |
cpu_to_be16(si_pi->mc_reg_table.mc_reg_address[j].s1); |
i++; |
} |
} |
mc_reg_table->last = (u8)i; |
} |
static void si_convert_mc_registers(const struct si_mc_reg_entry *entry, |
SMC_SIslands_MCRegisterSet *data, |
u32 num_entries, u32 valid_flag) |
{ |
u32 i, j; |
for(i = 0, j = 0; j < num_entries; j++) { |
if (valid_flag & (1 << j)) { |
data->value[i] = cpu_to_be32(entry->mc_data[j]); |
i++; |
} |
} |
} |
static void si_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev, |
struct rv7xx_pl *pl, |
SMC_SIslands_MCRegisterSet *mc_reg_table_data) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 i = 0; |
for (i = 0; i < si_pi->mc_reg_table.num_entries; i++) { |
if (pl->mclk <= si_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max) |
break; |
} |
if ((i == si_pi->mc_reg_table.num_entries) && (i > 0)) |
--i; |
si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[i], |
mc_reg_table_data, si_pi->mc_reg_table.last, |
si_pi->mc_reg_table.valid_flag); |
} |
static void si_convert_mc_reg_table_to_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_state, |
SMC_SIslands_MCRegisters *mc_reg_table) |
{ |
struct ni_ps *state = ni_get_ps(radeon_state); |
int i; |
for (i = 0; i < state->performance_level_count; i++) { |
si_convert_mc_reg_table_entry_to_smc(rdev, |
&state->performance_levels[i], |
&mc_reg_table->data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i]); |
} |
} |
static int si_populate_mc_reg_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_boot_state) |
{ |
struct ni_ps *boot_state = ni_get_ps(radeon_boot_state); |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct si_ulv_param *ulv = &si_pi->ulv; |
SMC_SIslands_MCRegisters *smc_mc_reg_table = &si_pi->smc_mc_reg_table; |
memset(smc_mc_reg_table, 0, sizeof(SMC_SIslands_MCRegisters)); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_seq_index, 1); |
si_populate_mc_reg_addresses(rdev, smc_mc_reg_table); |
si_convert_mc_reg_table_entry_to_smc(rdev, &boot_state->performance_levels[0], |
&smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_INITIAL_SLOT]); |
si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[0], |
&smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ACPI_SLOT], |
si_pi->mc_reg_table.last, |
si_pi->mc_reg_table.valid_flag); |
if (ulv->supported && ulv->pl.vddc != 0) |
si_convert_mc_reg_table_entry_to_smc(rdev, &ulv->pl, |
&smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ULV_SLOT]); |
else |
si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[0], |
&smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ULV_SLOT], |
si_pi->mc_reg_table.last, |
si_pi->mc_reg_table.valid_flag); |
si_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, smc_mc_reg_table); |
return si_copy_bytes_to_smc(rdev, si_pi->mc_reg_table_start, |
(u8 *)smc_mc_reg_table, |
sizeof(SMC_SIslands_MCRegisters), si_pi->sram_end); |
} |
static int si_upload_mc_reg_table(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state) |
{ |
struct ni_ps *new_state = ni_get_ps(radeon_new_state); |
struct si_power_info *si_pi = si_get_pi(rdev); |
u32 address = si_pi->mc_reg_table_start + |
offsetof(SMC_SIslands_MCRegisters, |
data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT]); |
SMC_SIslands_MCRegisters *smc_mc_reg_table = &si_pi->smc_mc_reg_table; |
memset(smc_mc_reg_table, 0, sizeof(SMC_SIslands_MCRegisters)); |
si_convert_mc_reg_table_to_smc(rdev, radeon_new_state, smc_mc_reg_table); |
return si_copy_bytes_to_smc(rdev, address, |
(u8 *)&smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT], |
sizeof(SMC_SIslands_MCRegisterSet) * new_state->performance_level_count, |
si_pi->sram_end); |
} |
static void si_enable_voltage_control(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN); |
else |
WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN); |
} |
static enum radeon_pcie_gen si_get_maximum_link_speed(struct radeon_device *rdev, |
struct radeon_ps *radeon_state) |
{ |
struct ni_ps *state = ni_get_ps(radeon_state); |
int i; |
u16 pcie_speed, max_speed = 0; |
for (i = 0; i < state->performance_level_count; i++) { |
pcie_speed = state->performance_levels[i].pcie_gen; |
if (max_speed < pcie_speed) |
max_speed = pcie_speed; |
} |
return max_speed; |
} |
static u16 si_get_current_pcie_speed(struct radeon_device *rdev) |
{ |
u32 speed_cntl; |
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE_MASK; |
speed_cntl >>= LC_CURRENT_DATA_RATE_SHIFT; |
return (u16)speed_cntl; |
} |
static void si_request_link_speed_change_before_state_change(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
enum radeon_pcie_gen target_link_speed = si_get_maximum_link_speed(rdev, radeon_new_state); |
enum radeon_pcie_gen current_link_speed; |
if (si_pi->force_pcie_gen == RADEON_PCIE_GEN_INVALID) |
current_link_speed = si_get_maximum_link_speed(rdev, radeon_current_state); |
else |
current_link_speed = si_pi->force_pcie_gen; |
si_pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID; |
si_pi->pspp_notify_required = false; |
if (target_link_speed > current_link_speed) { |
switch (target_link_speed) { |
#if defined(CONFIG_ACPI) |
case RADEON_PCIE_GEN3: |
if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN3, false) == 0) |
break; |
si_pi->force_pcie_gen = RADEON_PCIE_GEN2; |
if (current_link_speed == RADEON_PCIE_GEN2) |
break; |
case RADEON_PCIE_GEN2: |
if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, false) == 0) |
break; |
#endif |
default: |
si_pi->force_pcie_gen = si_get_current_pcie_speed(rdev); |
break; |
} |
} else { |
if (target_link_speed < current_link_speed) |
si_pi->pspp_notify_required = true; |
} |
} |
static void si_notify_link_speed_change_after_state_change(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
enum radeon_pcie_gen target_link_speed = si_get_maximum_link_speed(rdev, radeon_new_state); |
u8 request; |
if (si_pi->pspp_notify_required) { |
if (target_link_speed == RADEON_PCIE_GEN3) |
request = PCIE_PERF_REQ_PECI_GEN3; |
else if (target_link_speed == RADEON_PCIE_GEN2) |
request = PCIE_PERF_REQ_PECI_GEN2; |
else |
request = PCIE_PERF_REQ_PECI_GEN1; |
if ((request == PCIE_PERF_REQ_PECI_GEN1) && |
(si_get_current_pcie_speed(rdev) > 0)) |
return; |
#if defined(CONFIG_ACPI) |
radeon_acpi_pcie_performance_request(rdev, request, false); |
#endif |
} |
} |
#if 0 |
static int si_ds_request(struct radeon_device *rdev, |
bool ds_status_on, u32 count_write) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
if (eg_pi->sclk_deep_sleep) { |
if (ds_status_on) |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_CancelThrottleOVRDSCLKDS) == |
PPSMC_Result_OK) ? |
0 : -EINVAL; |
else |
return (si_send_msg_to_smc(rdev, PPSMC_MSG_ThrottleOVRDSCLKDS) == |
PPSMC_Result_OK) ? 0 : -EINVAL; |
} |
return 0; |
} |
#endif |
static void si_set_max_cu_value(struct radeon_device *rdev) |
{ |
struct si_power_info *si_pi = si_get_pi(rdev); |
if (rdev->family == CHIP_VERDE) { |
switch (rdev->pdev->device) { |
case 0x6820: |
case 0x6825: |
case 0x6821: |
case 0x6823: |
case 0x6827: |
si_pi->max_cu = 10; |
break; |
case 0x682D: |
case 0x6824: |
case 0x682F: |
case 0x6826: |
si_pi->max_cu = 8; |
break; |
case 0x6828: |
case 0x6830: |
case 0x6831: |
case 0x6838: |
case 0x6839: |
case 0x683D: |
si_pi->max_cu = 10; |
break; |
case 0x683B: |
case 0x683F: |
case 0x6829: |
si_pi->max_cu = 8; |
break; |
default: |
si_pi->max_cu = 0; |
break; |
} |
} else { |
si_pi->max_cu = 0; |
} |
} |
static int si_patch_single_dependency_table_based_on_leakage(struct radeon_device *rdev, |
struct radeon_clock_voltage_dependency_table *table) |
{ |
u32 i; |
int j; |
u16 leakage_voltage; |
if (table) { |
for (i = 0; i < table->count; i++) { |
switch (si_get_leakage_voltage_from_leakage_index(rdev, |
table->entries[i].v, |
&leakage_voltage)) { |
case 0: |
table->entries[i].v = leakage_voltage; |
break; |
case -EAGAIN: |
return -EINVAL; |
case -EINVAL: |
default: |
break; |
} |
} |
for (j = (table->count - 2); j >= 0; j--) { |
table->entries[j].v = (table->entries[j].v <= table->entries[j + 1].v) ? |
table->entries[j].v : table->entries[j + 1].v; |
} |
} |
return 0; |
} |
static int si_patch_dependency_tables_based_on_leakage(struct radeon_device *rdev) |
{ |
int ret = 0; |
ret = si_patch_single_dependency_table_based_on_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk); |
ret = si_patch_single_dependency_table_based_on_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk); |
ret = si_patch_single_dependency_table_based_on_leakage(rdev, |
&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk); |
return ret; |
} |
static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev, |
struct radeon_ps *radeon_new_state, |
struct radeon_ps *radeon_current_state) |
{ |
u32 lane_width; |
u32 new_lane_width = |
(radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; |
u32 current_lane_width = |
(radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; |
if (new_lane_width != current_lane_width) { |
radeon_set_pcie_lanes(rdev, new_lane_width); |
lane_width = radeon_get_pcie_lanes(rdev); |
si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width, lane_width); |
} |
} |
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); |
} |
static int si_set_thermal_temperature_range(struct radeon_device *rdev, |
int min_temp, int max_temp) |
{ |
int low_temp = 0 * 1000; |
int high_temp = 255 * 1000; |
if (low_temp < min_temp) |
low_temp = min_temp; |
if (high_temp > max_temp) |
high_temp = max_temp; |
if (high_temp < low_temp) { |
DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); |
return -EINVAL; |
} |
WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK); |
WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK); |
WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK); |
rdev->pm.dpm.thermal.min_temp = low_temp; |
rdev->pm.dpm.thermal.max_temp = high_temp; |
return 0; |
} |
int si_dpm_enable(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; |
int ret; |
if (si_is_smc_running(rdev)) |
return -EINVAL; |
if (pi->voltage_control || si_pi->voltage_control_svi2) |
si_enable_voltage_control(rdev, true); |
if (pi->mvdd_control) |
si_get_mvdd_configuration(rdev); |
if (pi->voltage_control || si_pi->voltage_control_svi2) { |
ret = si_construct_voltage_tables(rdev); |
if (ret) { |
DRM_ERROR("si_construct_voltage_tables failed\n"); |
return ret; |
} |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = si_initialize_mc_reg_table(rdev); |
if (ret) |
eg_pi->dynamic_ac_timing = false; |
} |
if (pi->dynamic_ss) |
si_enable_spread_spectrum(rdev, true); |
if (pi->thermal_protection) |
si_enable_thermal_protection(rdev, true); |
si_setup_bsp(rdev); |
si_program_git(rdev); |
si_program_tp(rdev); |
si_program_tpp(rdev); |
si_program_sstp(rdev); |
si_enable_display_gap(rdev); |
si_program_vc(rdev); |
ret = si_upload_firmware(rdev); |
if (ret) { |
DRM_ERROR("si_upload_firmware failed\n"); |
return ret; |
} |
ret = si_process_firmware_header(rdev); |
if (ret) { |
DRM_ERROR("si_process_firmware_header failed\n"); |
return ret; |
} |
ret = si_initial_switch_from_arb_f0_to_f1(rdev); |
if (ret) { |
DRM_ERROR("si_initial_switch_from_arb_f0_to_f1 failed\n"); |
return ret; |
} |
ret = si_init_smc_table(rdev); |
if (ret) { |
DRM_ERROR("si_init_smc_table failed\n"); |
return ret; |
} |
ret = si_init_smc_spll_table(rdev); |
if (ret) { |
DRM_ERROR("si_init_smc_spll_table failed\n"); |
return ret; |
} |
ret = si_init_arb_table_index(rdev); |
if (ret) { |
DRM_ERROR("si_init_arb_table_index failed\n"); |
return ret; |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = si_populate_mc_reg_table(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("si_populate_mc_reg_table failed\n"); |
return ret; |
} |
} |
ret = si_initialize_smc_cac_tables(rdev); |
if (ret) { |
DRM_ERROR("si_initialize_smc_cac_tables failed\n"); |
return ret; |
} |
ret = si_initialize_hardware_cac_manager(rdev); |
if (ret) { |
DRM_ERROR("si_initialize_hardware_cac_manager failed\n"); |
return ret; |
} |
ret = si_initialize_smc_dte_tables(rdev); |
if (ret) { |
DRM_ERROR("si_initialize_smc_dte_tables failed\n"); |
return ret; |
} |
ret = si_populate_smc_tdp_limits(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("si_populate_smc_tdp_limits failed\n"); |
return ret; |
} |
ret = si_populate_smc_tdp_limits_2(rdev, boot_ps); |
if (ret) { |
DRM_ERROR("si_populate_smc_tdp_limits_2 failed\n"); |
return ret; |
} |
si_program_response_times(rdev); |
si_program_ds_registers(rdev); |
si_dpm_start_smc(rdev); |
ret = si_notify_smc_display_change(rdev, false); |
if (ret) { |
DRM_ERROR("si_notify_smc_display_change failed\n"); |
return ret; |
} |
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; |
ret = si_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 = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); |
if (result != PPSMC_Result_OK) |
DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); |
} |
return 0; |
} |
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; |
if (!si_is_smc_running(rdev)) |
return; |
si_disable_ulv(rdev); |
si_clear_vc(rdev); |
if (pi->thermal_protection) |
si_enable_thermal_protection(rdev, false); |
si_enable_power_containment(rdev, boot_ps, false); |
si_enable_smc_cac(rdev, boot_ps, false); |
si_enable_spread_spectrum(rdev, false); |
si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false); |
si_stop_dpm(rdev); |
si_reset_to_default(rdev); |
si_dpm_stop_smc(rdev); |
si_force_switch_to_arb_f0(rdev); |
ni_update_current_ps(rdev, boot_ps); |
} |
int si_dpm_pre_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; |
struct radeon_ps *new_ps = &requested_ps; |
ni_update_requested_ps(rdev, new_ps); |
si_apply_state_adjust_rules(rdev, &eg_pi->requested_rps); |
return 0; |
} |
static int si_power_control_set_level(struct radeon_device *rdev) |
{ |
struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; |
int ret; |
ret = si_restrict_performance_levels_before_switch(rdev); |
if (ret) |
return ret; |
ret = si_halt_smc(rdev); |
if (ret) |
return ret; |
ret = si_populate_smc_tdp_limits(rdev, new_ps); |
if (ret) |
return ret; |
ret = si_populate_smc_tdp_limits_2(rdev, new_ps); |
if (ret) |
return ret; |
ret = si_resume_smc(rdev); |
if (ret) |
return ret; |
ret = si_set_sw_state(rdev); |
if (ret) |
return ret; |
return 0; |
} |
int si_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *new_ps = &eg_pi->requested_rps; |
struct radeon_ps *old_ps = &eg_pi->current_rps; |
int ret; |
ret = si_disable_ulv(rdev); |
if (ret) { |
DRM_ERROR("si_disable_ulv failed\n"); |
return ret; |
} |
ret = si_restrict_performance_levels_before_switch(rdev); |
if (ret) { |
DRM_ERROR("si_restrict_performance_levels_before_switch failed\n"); |
return ret; |
} |
if (eg_pi->pcie_performance_request) |
si_request_link_speed_change_before_state_change(rdev, new_ps, old_ps); |
ni_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
ret = si_enable_power_containment(rdev, new_ps, false); |
if (ret) { |
DRM_ERROR("si_enable_power_containment failed\n"); |
return ret; |
} |
ret = si_enable_smc_cac(rdev, new_ps, false); |
if (ret) { |
DRM_ERROR("si_enable_smc_cac failed\n"); |
return ret; |
} |
ret = si_halt_smc(rdev); |
if (ret) { |
DRM_ERROR("si_halt_smc failed\n"); |
return ret; |
} |
ret = si_upload_sw_state(rdev, new_ps); |
if (ret) { |
DRM_ERROR("si_upload_sw_state failed\n"); |
return ret; |
} |
ret = si_upload_smc_data(rdev); |
if (ret) { |
DRM_ERROR("si_upload_smc_data failed\n"); |
return ret; |
} |
ret = si_upload_ulv_state(rdev); |
if (ret) { |
DRM_ERROR("si_upload_ulv_state failed\n"); |
return ret; |
} |
if (eg_pi->dynamic_ac_timing) { |
ret = si_upload_mc_reg_table(rdev, new_ps); |
if (ret) { |
DRM_ERROR("si_upload_mc_reg_table failed\n"); |
return ret; |
} |
} |
ret = si_program_memory_timing_parameters(rdev, new_ps); |
if (ret) { |
DRM_ERROR("si_program_memory_timing_parameters failed\n"); |
return ret; |
} |
si_set_pcie_lane_width_in_smc(rdev, new_ps, old_ps); |
ret = si_resume_smc(rdev); |
if (ret) { |
DRM_ERROR("si_resume_smc failed\n"); |
return ret; |
} |
ret = si_set_sw_state(rdev); |
if (ret) { |
DRM_ERROR("si_set_sw_state failed\n"); |
return ret; |
} |
ni_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
if (eg_pi->pcie_performance_request) |
si_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps); |
ret = si_set_power_state_conditionally_enable_ulv(rdev, new_ps); |
if (ret) { |
DRM_ERROR("si_set_power_state_conditionally_enable_ulv failed\n"); |
return ret; |
} |
ret = si_enable_smc_cac(rdev, new_ps, true); |
if (ret) { |
DRM_ERROR("si_enable_smc_cac failed\n"); |
return ret; |
} |
ret = si_enable_power_containment(rdev, new_ps, true); |
if (ret) { |
DRM_ERROR("si_enable_power_containment failed\n"); |
return ret; |
} |
ret = si_power_control_set_level(rdev); |
if (ret) { |
DRM_ERROR("si_power_control_set_level failed\n"); |
return ret; |
} |
return 0; |
} |
void si_dpm_post_set_power_state(struct radeon_device *rdev) |
{ |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct radeon_ps *new_ps = &eg_pi->requested_rps; |
ni_update_current_ps(rdev, new_ps); |
} |
void si_dpm_reset_asic(struct radeon_device *rdev) |
{ |
si_restrict_performance_levels_before_switch(rdev); |
si_disable_ulv(rdev); |
si_set_boot_state(rdev); |
} |
void si_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
si_program_display_gap(rdev); |
} |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
struct _ATOM_PPLIB_SI_CLOCK_INFO si; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void si_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, |
u8 table_rev) |
{ |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { |
rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); |
rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); |
} else if (r600_is_uvd_state(rps->class, rps->class2)) { |
rps->vclk = RV770_DEFAULT_VCLK_FREQ; |
rps->dclk = RV770_DEFAULT_DCLK_FREQ; |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) |
rdev->pm.dpm.boot_ps = rps; |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void si_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, int index, |
union pplib_clock_info *clock_info) |
{ |
struct rv7xx_power_info *pi = rv770_get_pi(rdev); |
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); |
struct si_power_info *si_pi = si_get_pi(rdev); |
struct ni_ps *ps = ni_get_ps(rps); |
u16 leakage_voltage; |
struct rv7xx_pl *pl = &ps->performance_levels[index]; |
int ret; |
ps->performance_level_count = index + 1; |
pl->sclk = le16_to_cpu(clock_info->si.usEngineClockLow); |
pl->sclk |= clock_info->si.ucEngineClockHigh << 16; |
pl->mclk = le16_to_cpu(clock_info->si.usMemoryClockLow); |
pl->mclk |= clock_info->si.ucMemoryClockHigh << 16; |
pl->vddc = le16_to_cpu(clock_info->si.usVDDC); |
pl->vddci = le16_to_cpu(clock_info->si.usVDDCI); |
pl->flags = le32_to_cpu(clock_info->si.ulFlags); |
pl->pcie_gen = r600_get_pcie_gen_support(rdev, |
si_pi->sys_pcie_mask, |
si_pi->boot_pcie_gen, |
clock_info->si.ucPCIEGen); |
/* patch up vddc if necessary */ |
ret = si_get_leakage_voltage_from_leakage_index(rdev, pl->vddc, |
&leakage_voltage); |
if (ret == 0) |
pl->vddc = leakage_voltage; |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { |
pi->acpi_vddc = pl->vddc; |
eg_pi->acpi_vddci = pl->vddci; |
si_pi->acpi_pcie_gen = pl->pcie_gen; |
} |
if ((rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) && |
index == 0) { |
/* XXX disable for A0 tahiti */ |
si_pi->ulv.supported = true; |
si_pi->ulv.pl = *pl; |
si_pi->ulv.one_pcie_lane_in_ulv = false; |
si_pi->ulv.volt_change_delay = SISLANDS_ULVVOLTAGECHANGEDELAY_DFLT; |
si_pi->ulv.cg_ulv_parameter = SISLANDS_CGULVPARAMETER_DFLT; |
si_pi->ulv.cg_ulv_control = SISLANDS_CGULVCONTROL_DFLT; |
} |
if (pi->min_vddc_in_table > pl->vddc) |
pi->min_vddc_in_table = pl->vddc; |
if (pi->max_vddc_in_table < pl->vddc) |
pi->max_vddc_in_table = pl->vddc; |
/* patch up boot state */ |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
u16 vddc, vddci, mvdd; |
radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); |
pl->mclk = rdev->clock.default_mclk; |
pl->sclk = rdev->clock.default_sclk; |
pl->vddc = vddc; |
pl->vddci = vddci; |
si_pi->mvdd_bootup_value = mvdd; |
} |
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; |
} |
} |
static int si_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i, j, k, non_clock_array_index, clock_array_index; |
union pplib_clock_info *clock_info; |
struct _StateArray *state_array; |
struct _ClockInfoArray *clock_info_array; |
struct _NonClockInfoArray *non_clock_info_array; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
u8 *power_state_offset; |
struct ni_ps *ps; |
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); |
state_array = (struct _StateArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset)); |
clock_info_array = (struct _ClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); |
non_clock_info_array = (struct _NonClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); |
rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * |
state_array->ucNumEntries, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
power_state_offset = (u8 *)state_array->states; |
for (i = 0; i < state_array->ucNumEntries; i++) { |
u8 *idx; |
power_state = (union pplib_power_state *)power_state_offset; |
non_clock_array_index = power_state->v2.nonClockInfoIndex; |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
&non_clock_info_array->nonClockInfo[non_clock_array_index]; |
if (!rdev->pm.power_state[i].clock_info) |
return -EINVAL; |
ps = kzalloc(sizeof(struct ni_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
si_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info, |
non_clock_info_array->ucEntrySize); |
k = 0; |
idx = (u8 *)&power_state->v2.clockInfoIndex[0]; |
for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { |
clock_array_index = idx[j]; |
if (clock_array_index >= clock_info_array->ucNumEntries) |
continue; |
if (k >= SISLANDS_MAX_HARDWARE_POWERLEVELS) |
break; |
clock_info = (union pplib_clock_info *) |
((u8 *)&clock_info_array->clockInfo[0] + |
(clock_array_index * clock_info_array->ucEntrySize)); |
si_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], k, |
clock_info); |
k++; |
} |
power_state_offset += 2 + power_state->v2.ucNumDPMLevels; |
} |
rdev->pm.dpm.num_ps = state_array->ucNumEntries; |
return 0; |
} |
int si_dpm_init(struct radeon_device *rdev) |
{ |
struct rv7xx_power_info *pi; |
struct evergreen_power_info *eg_pi; |
struct ni_power_info *ni_pi; |
struct si_power_info *si_pi; |
struct atom_clock_dividers dividers; |
int ret; |
u32 mask; |
si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); |
if (si_pi == NULL) |
return -ENOMEM; |
rdev->pm.dpm.priv = si_pi; |
ni_pi = &si_pi->ni; |
eg_pi = &ni_pi->eg; |
pi = &eg_pi->rv7xx; |
ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); |
if (ret) |
si_pi->sys_pcie_mask = 0; |
else |
si_pi->sys_pcie_mask = mask; |
si_pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID; |
si_pi->boot_pcie_gen = si_get_current_pcie_speed(rdev); |
si_set_max_cu_value(rdev); |
rv770_get_max_vddc(rdev); |
si_get_leakage_vddc(rdev); |
si_patch_dependency_tables_based_on_leakage(rdev); |
pi->acpi_vddc = 0; |
eg_pi->acpi_vddci = 0; |
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; |
ret = r600_parse_extended_power_table(rdev); |
if (ret) |
return ret; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = |
kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL); |
if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { |
r600_free_extended_power_table(rdev); |
return -ENOMEM; |
} |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000; |
rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900; |
if (rdev->pm.dpm.voltage_response_time == 0) |
rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; |
if (rdev->pm.dpm.backbias_response_time == 0) |
rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
0, false, ÷rs); |
if (ret) |
pi->ref_div = dividers.ref_div + 1; |
else |
pi->ref_div = R600_REFERENCEDIVIDER_DFLT; |
eg_pi->smu_uvd_hs = false; |
pi->mclk_strobe_mode_threshold = 40000; |
if (si_is_special_1gb_platform(rdev)) |
pi->mclk_stutter_mode_threshold = 0; |
else |
pi->mclk_stutter_mode_threshold = pi->mclk_strobe_mode_threshold; |
pi->mclk_edc_enable_threshold = 40000; |
eg_pi->mclk_edc_wr_enable_threshold = 40000; |
ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold; |
pi->voltage_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, |
VOLTAGE_OBJ_GPIO_LUT); |
if (!pi->voltage_control) { |
si_pi->voltage_control_svi2 = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, |
VOLTAGE_OBJ_SVID2); |
if (si_pi->voltage_control_svi2) |
radeon_atom_get_svi2_info(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, |
&si_pi->svd_gpio_id, &si_pi->svc_gpio_id); |
} |
pi->mvdd_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, |
VOLTAGE_OBJ_GPIO_LUT); |
eg_pi->vddci_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, |
VOLTAGE_OBJ_GPIO_LUT); |
if (!eg_pi->vddci_control) |
si_pi->vddci_control_svi2 = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, |
VOLTAGE_OBJ_SVID2); |
si_pi->vddc_phase_shed_control = |
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, |
VOLTAGE_OBJ_PHASE_LUT); |
rv770_get_engine_memory_ss(rdev); |
pi->asi = RV770_ASI_DFLT; |
pi->pasi = CYPRESS_HASI_DFLT; |
pi->vrc = SISLANDS_VRC_DFLT; |
pi->gfx_clock_gating = true; |
eg_pi->sclk_deep_sleep = true; |
si_pi->sclk_deep_sleep_above_low = false; |
if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) |
pi->thermal_protection = true; |
else |
pi->thermal_protection = false; |
eg_pi->dynamic_ac_timing = true; |
eg_pi->light_sleep = true; |
#if defined(CONFIG_ACPI) |
eg_pi->pcie_performance_request = |
radeon_acpi_is_pcie_performance_request_supported(rdev); |
#else |
eg_pi->pcie_performance_request = false; |
#endif |
si_pi->sram_end = SMC_RAM_END; |
rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 4; |
rdev->pm.dpm.dyn_state.sclk_mclk_delta = 15000; |
rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200; |
rdev->pm.dpm.dyn_state.valid_sclk_values.count = 0; |
rdev->pm.dpm.dyn_state.valid_sclk_values.values = NULL; |
rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0; |
rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL; |
si_initialize_powertune_defaults(rdev); |
/* make sure dc limits are valid */ |
if ((rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) || |
(rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0)) |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc = |
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; |
return 0; |
} |
void si_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries); |
r600_free_extended_power_table(rdev); |
} |
void si_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 ni_ps *ps = ni_get_ps(rps); |
struct rv7xx_pl *pl; |
u32 current_index = |
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >> |
CURRENT_STATE_INDEX_SHIFT; |
if (current_index >= ps->performance_level_count) { |
seq_printf(m, "invalid dpm profile %d\n", current_index); |
} else { |
pl = &ps->performance_levels[current_index]; |
seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n", |
current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1); |
} |
} |
/drivers/video/drm/radeon/si_dpm.h |
---|
0,0 → 1,232 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __SI_DPM_H__ |
#define __SI_DPM_H__ |
#include "ni_dpm.h" |
#include "sislands_smc.h" |
enum si_cac_config_reg_type |
{ |
SISLANDS_CACCONFIG_MMR = 0, |
SISLANDS_CACCONFIG_CGIND, |
SISLANDS_CACCONFIG_MAX |
}; |
struct si_cac_config_reg |
{ |
u32 offset; |
u32 mask; |
u32 shift; |
u32 value; |
enum si_cac_config_reg_type type; |
}; |
struct si_powertune_data |
{ |
u32 cac_window; |
u32 l2_lta_window_size_default; |
u8 lts_truncate_default; |
u8 shift_n_default; |
u8 operating_temp; |
struct ni_leakage_coeffients leakage_coefficients; |
u32 fixed_kt; |
u32 lkge_lut_v0_percent; |
u8 dc_cac[NISLANDS_DCCAC_MAX_LEVELS]; |
bool enable_powertune_by_default; |
}; |
struct si_dyn_powertune_data |
{ |
u32 cac_leakage; |
s32 leakage_minimum_temperature; |
u32 wintime; |
u32 l2_lta_window_size; |
u8 lts_truncate; |
u8 shift_n; |
u8 dc_pwr_value; |
bool disable_uvd_powertune; |
}; |
struct si_dte_data |
{ |
u32 tau[SMC_SISLANDS_DTE_MAX_FILTER_STAGES]; |
u32 r[SMC_SISLANDS_DTE_MAX_FILTER_STAGES]; |
u32 k; |
u32 t0; |
u32 max_t; |
u8 window_size; |
u8 temp_select; |
u8 dte_mode; |
u8 tdep_count; |
u8 t_limits[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE]; |
u32 tdep_tau[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE]; |
u32 tdep_r[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE]; |
u32 t_threshold; |
bool enable_dte_by_default; |
}; |
struct si_clock_registers { |
u32 cg_spll_func_cntl; |
u32 cg_spll_func_cntl_2; |
u32 cg_spll_func_cntl_3; |
u32 cg_spll_func_cntl_4; |
u32 cg_spll_spread_spectrum; |
u32 cg_spll_spread_spectrum_2; |
u32 dll_cntl; |
u32 mclk_pwrmgt_cntl; |
u32 mpll_ad_func_cntl; |
u32 mpll_dq_func_cntl; |
u32 mpll_func_cntl; |
u32 mpll_func_cntl_1; |
u32 mpll_func_cntl_2; |
u32 mpll_ss1; |
u32 mpll_ss2; |
}; |
struct si_mc_reg_entry { |
u32 mclk_max; |
u32 mc_data[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE]; |
}; |
struct si_mc_reg_table { |
u8 last; |
u8 num_entries; |
u16 valid_flag; |
struct si_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES]; |
SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE]; |
}; |
#define SISLANDS_MCREGISTERTABLE_INITIAL_SLOT 0 |
#define SISLANDS_MCREGISTERTABLE_ACPI_SLOT 1 |
#define SISLANDS_MCREGISTERTABLE_ULV_SLOT 2 |
#define SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT 3 |
struct si_leakage_voltage_entry |
{ |
u16 voltage; |
u16 leakage_index; |
}; |
#define SISLANDS_LEAKAGE_INDEX0 0xff01 |
#define SISLANDS_MAX_LEAKAGE_COUNT 4 |
struct si_leakage_voltage |
{ |
u16 count; |
struct si_leakage_voltage_entry entries[SISLANDS_MAX_LEAKAGE_COUNT]; |
}; |
#define SISLANDS_MAX_HARDWARE_POWERLEVELS 5 |
struct si_ulv_param { |
bool supported; |
u32 cg_ulv_control; |
u32 cg_ulv_parameter; |
u32 volt_change_delay; |
struct rv7xx_pl pl; |
bool one_pcie_lane_in_ulv; |
}; |
struct si_power_info { |
/* must be first! */ |
struct ni_power_info ni; |
struct si_clock_registers clock_registers; |
struct si_mc_reg_table mc_reg_table; |
struct atom_voltage_table mvdd_voltage_table; |
struct atom_voltage_table vddc_phase_shed_table; |
struct si_leakage_voltage leakage_voltage; |
u16 mvdd_bootup_value; |
struct si_ulv_param ulv; |
u32 max_cu; |
/* pcie gen */ |
enum radeon_pcie_gen force_pcie_gen; |
enum radeon_pcie_gen boot_pcie_gen; |
enum radeon_pcie_gen acpi_pcie_gen; |
u32 sys_pcie_mask; |
/* flags */ |
bool enable_dte; |
bool enable_ppm; |
bool vddc_phase_shed_control; |
bool pspp_notify_required; |
bool sclk_deep_sleep_above_low; |
bool voltage_control_svi2; |
bool vddci_control_svi2; |
/* smc offsets */ |
u32 sram_end; |
u32 state_table_start; |
u32 soft_regs_start; |
u32 mc_reg_table_start; |
u32 arb_table_start; |
u32 cac_table_start; |
u32 dte_table_start; |
u32 spll_table_start; |
u32 papm_cfg_table_start; |
/* CAC stuff */ |
const struct si_cac_config_reg *cac_weights; |
const struct si_cac_config_reg *lcac_config; |
const struct si_cac_config_reg *cac_override; |
const struct si_powertune_data *powertune_data; |
struct si_dyn_powertune_data dyn_powertune_data; |
/* DTE stuff */ |
struct si_dte_data dte_data; |
/* scratch structs */ |
SMC_SIslands_MCRegisters smc_mc_reg_table; |
SISLANDS_SMC_STATETABLE smc_statetable; |
PP_SIslands_PAPMParameters papm_parm; |
/* SVI2 */ |
u8 svd_gpio_id; |
u8 svc_gpio_id; |
}; |
#define SISLANDS_INITIAL_STATE_ARB_INDEX 0 |
#define SISLANDS_ACPI_STATE_ARB_INDEX 1 |
#define SISLANDS_ULV_STATE_ARB_INDEX 2 |
#define SISLANDS_DRIVER_STATE_ARB_INDEX 3 |
#define SISLANDS_DPM2_MAX_PULSE_SKIP 256 |
#define SISLANDS_DPM2_NEAR_TDP_DEC 10 |
#define SISLANDS_DPM2_ABOVE_SAFE_INC 5 |
#define SISLANDS_DPM2_BELOW_SAFE_INC 20 |
#define SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT 80 |
#define SISLANDS_DPM2_MAXPS_PERCENT_H 99 |
#define SISLANDS_DPM2_MAXPS_PERCENT_M 99 |
#define SISLANDS_DPM2_SQ_RAMP_MAX_POWER 0x3FFF |
#define SISLANDS_DPM2_SQ_RAMP_MIN_POWER 0x12 |
#define SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15 |
#define SISLANDS_DPM2_SQ_RAMP_STI_SIZE 0x1E |
#define SISLANDS_DPM2_SQ_RAMP_LTI_RATIO 0xF |
#define SISLANDS_DPM2_PWREFFICIENCYRATIO_MARGIN 10 |
#define SISLANDS_VRC_DFLT 0xC000B3 |
#define SISLANDS_ULVVOLTAGECHANGEDELAY_DFLT 1687 |
#define SISLANDS_CGULVPARAMETER_DFLT 0x00040035 |
#define SISLANDS_CGULVCONTROL_DFLT 0x1f007550 |
#endif |
/drivers/video/drm/radeon/si_smc.c |
---|
0,0 → 1,310 |
/* |
* Copyright 2011 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#include <linux/firmware.h> |
#include "drmP.h" |
#include "radeon.h" |
#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) |
{ |
if (smc_address & 3) |
return -EINVAL; |
if ((smc_address + 3) > limit) |
return -EINVAL; |
WREG32(SMC_IND_INDEX_0, smc_address); |
WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); |
return 0; |
} |
int si_copy_bytes_to_smc(struct radeon_device *rdev, |
u32 smc_start_address, |
const u8 *src, u32 byte_count, u32 limit) |
{ |
unsigned long flags; |
int ret = 0; |
u32 data, original_data, addr, extra_shift; |
if (smc_start_address & 3) |
return -EINVAL; |
if ((smc_start_address + byte_count) > limit) |
return -EINVAL; |
addr = smc_start_address; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
while (byte_count >= 4) { |
/* SMC address space is BE */ |
data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; |
ret = si_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
WREG32(SMC_IND_DATA_0, data); |
src += 4; |
byte_count -= 4; |
addr += 4; |
} |
/* RMW for the final bytes */ |
if (byte_count > 0) { |
data = 0; |
ret = si_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
original_data = RREG32(SMC_IND_DATA_0); |
extra_shift = 8 * (4 - byte_count); |
while (byte_count > 0) { |
/* SMC address space is BE */ |
data = (data << 8) + *src++; |
byte_count--; |
} |
data <<= extra_shift; |
data |= (original_data & ~((~0UL) << extra_shift)); |
ret = si_set_smc_sram_address(rdev, addr, limit); |
if (ret) |
goto done; |
WREG32(SMC_IND_DATA_0, data); |
} |
done: |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
void si_start_smc(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL); |
tmp &= ~RST_REG; |
WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp); |
} |
void si_reset_smc(struct radeon_device *rdev) |
{ |
u32 tmp; |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
RREG32(CB_CGTT_SCLK_CTRL); |
tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL); |
tmp |= RST_REG; |
WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp); |
} |
int si_program_jump_on_start(struct radeon_device *rdev) |
{ |
static u8 data[] = { 0x0E, 0x00, 0x40, 0x40 }; |
return si_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1); |
} |
void si_stop_smc_clock(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0); |
tmp |= CK_DISABLE; |
WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp); |
} |
void si_start_smc_clock(struct radeon_device *rdev) |
{ |
u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0); |
tmp &= ~CK_DISABLE; |
WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp); |
} |
bool si_is_smc_running(struct radeon_device *rdev) |
{ |
u32 rst = RREG32_SMC(SMC_SYSCON_RESET_CNTL); |
u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0); |
if (!(rst & RST_REG) && !(clk & CK_DISABLE)) |
return true; |
return false; |
} |
PPSMC_Result si_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg) |
{ |
u32 tmp; |
int i; |
if (!si_is_smc_running(rdev)) |
return PPSMC_Result_Failed; |
WREG32(SMC_MESSAGE_0, msg); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(SMC_RESP_0); |
if (tmp != 0) |
break; |
udelay(1); |
} |
tmp = RREG32(SMC_RESP_0); |
return (PPSMC_Result)tmp; |
} |
PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev) |
{ |
u32 tmp; |
int i; |
if (!si_is_smc_running(rdev)) |
return PPSMC_Result_OK; |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0); |
if ((tmp & CKEN) == 0) |
break; |
udelay(1); |
} |
return PPSMC_Result_OK; |
} |
int si_load_smc_ucode(struct radeon_device *rdev, u32 limit) |
{ |
unsigned long flags; |
u32 ucode_start_address; |
u32 ucode_size; |
const u8 *src; |
u32 data; |
if (!rdev->smc_fw) |
return -EINVAL; |
if (rdev->new_fw) { |
const struct smc_firmware_header_v1_0 *hdr = |
(const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data; |
radeon_ucode_print_smc_hdr(&hdr->header); |
ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); |
ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); |
src = (const u8 *) |
(rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); |
} else { |
switch (rdev->family) { |
case CHIP_TAHITI: |
ucode_start_address = TAHITI_SMC_UCODE_START; |
ucode_size = TAHITI_SMC_UCODE_SIZE; |
break; |
case CHIP_PITCAIRN: |
ucode_start_address = PITCAIRN_SMC_UCODE_START; |
ucode_size = PITCAIRN_SMC_UCODE_SIZE; |
break; |
case CHIP_VERDE: |
ucode_start_address = VERDE_SMC_UCODE_START; |
ucode_size = VERDE_SMC_UCODE_SIZE; |
break; |
case CHIP_OLAND: |
ucode_start_address = OLAND_SMC_UCODE_START; |
ucode_size = OLAND_SMC_UCODE_SIZE; |
break; |
case CHIP_HAINAN: |
ucode_start_address = HAINAN_SMC_UCODE_START; |
ucode_size = HAINAN_SMC_UCODE_SIZE; |
break; |
default: |
DRM_ERROR("unknown asic in smc ucode loader\n"); |
BUG(); |
} |
src = (const u8 *)rdev->smc_fw->data; |
} |
if (ucode_size & 3) |
return -EINVAL; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
WREG32(SMC_IND_INDEX_0, ucode_start_address); |
WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); |
while (ucode_size >= 4) { |
/* SMC address space is BE */ |
data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; |
WREG32(SMC_IND_DATA_0, data); |
src += 4; |
ucode_size -= 4; |
} |
WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return 0; |
} |
int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, |
u32 *value, u32 limit) |
{ |
unsigned long flags; |
int ret; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
ret = si_set_smc_sram_address(rdev, smc_address, limit); |
if (ret == 0) |
*value = RREG32(SMC_IND_DATA_0); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, |
u32 value, u32 limit) |
{ |
unsigned long flags; |
int ret; |
spin_lock_irqsave(&rdev->smc_idx_lock, flags); |
ret = si_set_smc_sram_address(rdev, smc_address, limit); |
if (ret == 0) |
WREG32(SMC_IND_DATA_0, value); |
spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); |
return ret; |
} |
/drivers/video/drm/radeon/sid.h |
---|
30,6 → 30,99 |
#define VERDE_GB_ADDR_CONFIG_GOLDEN 0x12010002 |
#define HAINAN_GB_ADDR_CONFIG_GOLDEN 0x02010001 |
#define SI_MAX_SH_GPRS 256 |
#define SI_MAX_TEMP_GPRS 16 |
#define SI_MAX_SH_THREADS 256 |
#define SI_MAX_SH_STACK_ENTRIES 4096 |
#define SI_MAX_FRC_EOV_CNT 16384 |
#define SI_MAX_BACKENDS 8 |
#define SI_MAX_BACKENDS_MASK 0xFF |
#define SI_MAX_BACKENDS_PER_SE_MASK 0x0F |
#define SI_MAX_SIMDS 12 |
#define SI_MAX_SIMDS_MASK 0x0FFF |
#define SI_MAX_SIMDS_PER_SE_MASK 0x00FF |
#define SI_MAX_PIPES 8 |
#define SI_MAX_PIPES_MASK 0xFF |
#define SI_MAX_PIPES_PER_SIMD_MASK 0x3F |
#define SI_MAX_LDS_NUM 0xFFFF |
#define SI_MAX_TCC 16 |
#define SI_MAX_TCC_MASK 0xFFFF |
/* SMC IND accessor regs */ |
#define SMC_IND_INDEX_0 0x200 |
#define SMC_IND_DATA_0 0x204 |
#define SMC_IND_ACCESS_CNTL 0x228 |
# define AUTO_INCREMENT_IND_0 (1 << 0) |
#define SMC_MESSAGE_0 0x22c |
#define SMC_RESP_0 0x230 |
/* CG IND registers are accessed via SMC indirect space + SMC_CG_IND_START */ |
#define SMC_CG_IND_START 0xc0030000 |
#define SMC_CG_IND_END 0xc0040000 |
#define CG_CGTT_LOCAL_0 0x400 |
#define CG_CGTT_LOCAL_1 0x401 |
/* SMC IND registers */ |
#define SMC_SYSCON_RESET_CNTL 0x80000000 |
# define RST_REG (1 << 0) |
#define SMC_SYSCON_CLOCK_CNTL_0 0x80000004 |
# define CK_DISABLE (1 << 0) |
# define CKEN (1 << 24) |
#define VGA_HDP_CONTROL 0x328 |
#define VGA_MEMORY_DISABLE (1 << 4) |
#define DCCG_DISP_SLOW_SELECT_REG 0x4fc |
#define DCCG_DISP1_SLOW_SELECT(x) ((x) << 0) |
#define DCCG_DISP1_SLOW_SELECT_MASK (7 << 0) |
#define DCCG_DISP1_SLOW_SELECT_SHIFT 0 |
#define DCCG_DISP2_SLOW_SELECT(x) ((x) << 4) |
#define DCCG_DISP2_SLOW_SELECT_MASK (7 << 4) |
#define DCCG_DISP2_SLOW_SELECT_SHIFT 4 |
#define CG_SPLL_FUNC_CNTL 0x600 |
#define SPLL_RESET (1 << 0) |
#define SPLL_SLEEP (1 << 1) |
#define SPLL_BYPASS_EN (1 << 3) |
#define SPLL_REF_DIV(x) ((x) << 4) |
#define SPLL_REF_DIV_MASK (0x3f << 4) |
#define SPLL_PDIV_A(x) ((x) << 20) |
#define SPLL_PDIV_A_MASK (0x7f << 20) |
#define SPLL_PDIV_A_SHIFT 20 |
#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) |
#define SPLL_FB_DIV_SHIFT 0 |
#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_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) |
#define CLK_S(x) ((x) << 4) |
#define CLK_S_MASK (0xfff << 4) |
#define CLK_S_SHIFT 4 |
#define CG_SPLL_SPREAD_SPECTRUM_2 0x624 |
#define CLK_V(x) ((x) << 0) |
#define CLK_V_MASK (0x3ffffff << 0) |
#define CLK_V_SHIFT 0 |
#define CG_SPLL_AUTOSCALE_CNTL 0x62c |
# define AUTOSCALE_ON_SS_CLEAR (1 << 9) |
/* discrete uvd clocks */ |
#define CG_UPLL_FUNC_CNTL 0x634 |
# define UPLL_RESET_MASK 0x00000001 |
59,6 → 152,45 |
#define CG_UPLL_SPREAD_SPECTRUM 0x650 |
# define SSEN_MASK 0x00000001 |
#define MPLL_BYPASSCLK_SEL 0x65c |
# define MPLL_CLKOUT_SEL(x) ((x) << 8) |
# define MPLL_CLKOUT_SEL_MASK 0xFF00 |
#define CG_CLKPIN_CNTL 0x660 |
# define XTALIN_DIVIDE (1 << 1) |
# define BCLK_AS_XCLK (1 << 2) |
#define CG_CLKPIN_CNTL_2 0x664 |
# define FORCE_BIF_REFCLK_EN (1 << 3) |
# define MUX_TCLK_TO_XCLK (1 << 8) |
#define THM_CLK_CNTL 0x66c |
# define CMON_CLK_SEL(x) ((x) << 0) |
# define CMON_CLK_SEL_MASK 0xFF |
# define TMON_CLK_SEL(x) ((x) << 8) |
# define TMON_CLK_SEL_MASK 0xFF00 |
#define MISC_CLK_CNTL 0x670 |
# define DEEP_SLEEP_CLK_SEL(x) ((x) << 0) |
# define DEEP_SLEEP_CLK_SEL_MASK 0xFF |
# define ZCLK_SEL(x) ((x) << 8) |
# define ZCLK_SEL_MASK 0xFF00 |
#define CG_THERMAL_CTRL 0x700 |
#define DPM_EVENT_SRC(x) ((x) << 0) |
#define DPM_EVENT_SRC_MASK (7 << 0) |
#define DIG_THERM_DPM(x) ((x) << 14) |
#define DIG_THERM_DPM_MASK 0x003FC000 |
#define DIG_THERM_DPM_SHIFT 14 |
#define CG_THERMAL_INT 0x708 |
#define DIG_THERM_INTH(x) ((x) << 8) |
#define DIG_THERM_INTH_MASK 0x0000FF00 |
#define DIG_THERM_INTH_SHIFT 8 |
#define DIG_THERM_INTL(x) ((x) << 16) |
#define DIG_THERM_INTL_MASK 0x00FF0000 |
#define DIG_THERM_INTL_SHIFT 16 |
#define THERM_INT_MASK_HIGH (1 << 24) |
#define THERM_INT_MASK_LOW (1 << 25) |
#define CG_MULT_THERMAL_STATUS 0x714 |
#define ASIC_MAX_TEMP(x) ((x) << 0) |
#define ASIC_MAX_TEMP_MASK 0x000001ff |
67,36 → 199,98 |
#define CTF_TEMP_MASK 0x0003fe00 |
#define CTF_TEMP_SHIFT 9 |
#define SI_MAX_SH_GPRS 256 |
#define SI_MAX_TEMP_GPRS 16 |
#define SI_MAX_SH_THREADS 256 |
#define SI_MAX_SH_STACK_ENTRIES 4096 |
#define SI_MAX_FRC_EOV_CNT 16384 |
#define SI_MAX_BACKENDS 8 |
#define SI_MAX_BACKENDS_MASK 0xFF |
#define SI_MAX_BACKENDS_PER_SE_MASK 0x0F |
#define SI_MAX_SIMDS 12 |
#define SI_MAX_SIMDS_MASK 0x0FFF |
#define SI_MAX_SIMDS_PER_SE_MASK 0x00FF |
#define SI_MAX_PIPES 8 |
#define SI_MAX_PIPES_MASK 0xFF |
#define SI_MAX_PIPES_PER_SIMD_MASK 0x3F |
#define SI_MAX_LDS_NUM 0xFFFF |
#define SI_MAX_TCC 16 |
#define SI_MAX_TCC_MASK 0xFFFF |
#define GENERAL_PWRMGT 0x780 |
# define GLOBAL_PWRMGT_EN (1 << 0) |
# define STATIC_PM_EN (1 << 1) |
# define THERMAL_PROTECTION_DIS (1 << 2) |
# define THERMAL_PROTECTION_TYPE (1 << 3) |
# define SW_SMIO_INDEX(x) ((x) << 6) |
# define SW_SMIO_INDEX_MASK (1 << 6) |
# define SW_SMIO_INDEX_SHIFT 6 |
# define VOLT_PWRMGT_EN (1 << 10) |
# define DYN_SPREAD_SPECTRUM_EN (1 << 23) |
#define CG_TPC 0x784 |
#define SCLK_PWRMGT_CNTL 0x788 |
# define SCLK_PWRMGT_OFF (1 << 0) |
# define SCLK_LOW_D1 (1 << 1) |
# define FIR_RESET (1 << 4) |
# define FIR_FORCE_TREND_SEL (1 << 5) |
# define FIR_TREND_MODE (1 << 6) |
# define DYN_GFX_CLK_OFF_EN (1 << 7) |
# define GFX_CLK_FORCE_ON (1 << 8) |
# define GFX_CLK_REQUEST_OFF (1 << 9) |
# define GFX_CLK_FORCE_OFF (1 << 10) |
# define GFX_CLK_OFF_ACPI_D1 (1 << 11) |
# define GFX_CLK_OFF_ACPI_D2 (1 << 12) |
# define GFX_CLK_OFF_ACPI_D3 (1 << 13) |
# define DYN_LIGHT_SLEEP_EN (1 << 14) |
#define VGA_HDP_CONTROL 0x328 |
#define VGA_MEMORY_DISABLE (1 << 4) |
#define TARGET_AND_CURRENT_PROFILE_INDEX 0x798 |
# define CURRENT_STATE_INDEX_MASK (0xf << 4) |
# define CURRENT_STATE_INDEX_SHIFT 4 |
#define CG_CLKPIN_CNTL 0x660 |
# define XTALIN_DIVIDE (1 << 1) |
#define CG_CLKPIN_CNTL_2 0x664 |
# define MUX_TCLK_TO_XCLK (1 << 8) |
#define CG_FTV 0x7bc |
#define CG_FFCT_0 0x7c0 |
# define UTC_0(x) ((x) << 0) |
# define UTC_0_MASK (0x3ff << 0) |
# define DTC_0(x) ((x) << 10) |
# define DTC_0_MASK (0x3ff << 10) |
#define CG_BSP 0x7fc |
# define BSP(x) ((x) << 0) |
# define BSP_MASK (0xffff << 0) |
# define BSU(x) ((x) << 16) |
# define BSU_MASK (0xf << 16) |
#define CG_AT 0x800 |
# define CG_R(x) ((x) << 0) |
# define CG_R_MASK (0xffff << 0) |
# define CG_L(x) ((x) << 16) |
# define CG_L_MASK (0xffff << 16) |
#define CG_GIT 0x804 |
# define CG_GICST(x) ((x) << 0) |
# define CG_GICST_MASK (0xffff << 0) |
# define CG_GIPOT(x) ((x) << 16) |
# define CG_GIPOT_MASK (0xffff << 16) |
#define CG_SSP 0x80c |
# define SST(x) ((x) << 0) |
# define SST_MASK (0xffff << 0) |
# define SSTU(x) ((x) << 16) |
# define SSTU_MASK (0xf << 16) |
#define CG_DISPLAY_GAP_CNTL 0x828 |
# define DISP1_GAP(x) ((x) << 0) |
# define DISP1_GAP_MASK (3 << 0) |
# define DISP2_GAP(x) ((x) << 2) |
# define DISP2_GAP_MASK (3 << 2) |
# define VBI_TIMER_COUNT(x) ((x) << 4) |
# define VBI_TIMER_COUNT_MASK (0x3fff << 4) |
# define VBI_TIMER_UNIT(x) ((x) << 20) |
# define VBI_TIMER_UNIT_MASK (7 << 20) |
# define DISP1_GAP_MCHG(x) ((x) << 24) |
# define DISP1_GAP_MCHG_MASK (3 << 24) |
# define DISP2_GAP_MCHG(x) ((x) << 26) |
# define DISP2_GAP_MCHG_MASK (3 << 26) |
#define CG_ULV_CONTROL 0x878 |
#define CG_ULV_PARAMETER 0x87c |
#define SMC_SCRATCH0 0x884 |
#define CG_CAC_CTRL 0x8b8 |
# define CAC_WINDOW(x) ((x) << 0) |
# define CAC_WINDOW_MASK 0x00ffffff |
#define DMIF_ADDR_CONFIG 0xBD4 |
#define DMIF_ADDR_CALC 0xC00 |
#define PIPE0_DMIF_BUFFER_CONTROL 0x0ca0 |
# define DMIF_BUFFERS_ALLOCATED(x) ((x) << 0) |
# define DMIF_BUFFERS_ALLOCATED_COMPLETED (1 << 4) |
#define SRBM_STATUS 0xE50 |
#define GRBM_RQ_PENDING (1 << 5) |
#define VMC_BUSY (1 << 8) |
168,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 |
182,6 → 377,20 |
#define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC |
#define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC |
#define PROTECTIONS_MASK (0xf << 0) |
#define PROTECTIONS_SHIFT 0 |
/* bit 0: range |
* bit 1: pde0 |
* bit 2: valid |
* bit 3: read |
* bit 4: write |
*/ |
#define MEMORY_CLIENT_ID_MASK (0xff << 12) |
#define MEMORY_CLIENT_ID_SHIFT 12 |
#define MEMORY_CLIENT_RW_MASK (1 << 24) |
#define MEMORY_CLIENT_RW_SHIFT 24 |
#define FAULT_VMID_MASK (0xf << 25) |
#define FAULT_VMID_SHIFT 25 |
#define VM_INVALIDATE_REQUEST 0x1478 |
#define VM_INVALIDATE_RESPONSE 0x147c |
203,6 → 412,10 |
#define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157C |
#define VM_CONTEXT1_PAGE_TABLE_END_ADDR 0x1580 |
#define VM_L2_CG 0x15c0 |
#define MC_CG_ENABLE (1 << 18) |
#define MC_LS_ENABLE (1 << 19) |
#define MC_SHARED_CHMAP 0x2004 |
#define NOOFCHAN_SHIFT 12 |
#define NOOFCHAN_MASK 0x0000f000 |
228,6 → 441,17 |
#define MC_SHARED_BLACKOUT_CNTL 0x20ac |
#define MC_HUB_MISC_HUB_CG 0x20b8 |
#define MC_HUB_MISC_VM_CG 0x20bc |
#define MC_HUB_MISC_SIP_CG 0x20c0 |
#define MC_XPB_CLK_GAT 0x2478 |
#define MC_CITF_MISC_RD_CG 0x2648 |
#define MC_CITF_MISC_WR_CG 0x264c |
#define MC_CITF_MISC_VM_CG 0x2650 |
#define MC_ARB_RAMCFG 0x2760 |
#define NOOFBANK_SHIFT 0 |
#define NOOFBANK_MASK 0x00000003 |
243,7 → 467,24 |
#define NOOFGROUPS_SHIFT 12 |
#define NOOFGROUPS_MASK 0x00001000 |
#define MC_SEQ_TRAIN_WAKEUP_CNTL 0x2808 |
#define MC_ARB_DRAM_TIMING 0x2774 |
#define MC_ARB_DRAM_TIMING2 0x2778 |
#define MC_ARB_BURST_TIME 0x2808 |
#define STATE0(x) ((x) << 0) |
#define STATE0_MASK (0x1f << 0) |
#define STATE0_SHIFT 0 |
#define STATE1(x) ((x) << 5) |
#define STATE1_MASK (0x1f << 5) |
#define STATE1_SHIFT 5 |
#define STATE2(x) ((x) << 10) |
#define STATE2_MASK (0x1f << 10) |
#define STATE2_SHIFT 10 |
#define STATE3(x) ((x) << 15) |
#define STATE3_MASK (0x1f << 15) |
#define STATE3_SHIFT 15 |
#define MC_SEQ_TRAIN_WAKEUP_CNTL 0x28e8 |
#define TRAIN_DONE_D0 (1 << 30) |
#define TRAIN_DONE_D1 (1 << 31) |
250,14 → 491,109 |
#define MC_SEQ_SUP_CNTL 0x28c8 |
#define RUN_MASK (1 << 0) |
#define MC_SEQ_SUP_PGM 0x28cc |
#define MC_PMG_AUTO_CMD 0x28d0 |
#define MC_IO_PAD_CNTL_D0 0x29d0 |
#define MEM_FALL_OUT_CMD (1 << 8) |
#define MC_SEQ_RAS_TIMING 0x28a0 |
#define MC_SEQ_CAS_TIMING 0x28a4 |
#define MC_SEQ_MISC_TIMING 0x28a8 |
#define MC_SEQ_MISC_TIMING2 0x28ac |
#define MC_SEQ_PMG_TIMING 0x28b0 |
#define MC_SEQ_RD_CTL_D0 0x28b4 |
#define MC_SEQ_RD_CTL_D1 0x28b8 |
#define MC_SEQ_WR_CTL_D0 0x28bc |
#define MC_SEQ_WR_CTL_D1 0x28c0 |
#define MC_SEQ_MISC0 0x2a00 |
#define MC_SEQ_MISC0_VEN_ID_SHIFT 8 |
#define MC_SEQ_MISC0_VEN_ID_MASK 0x00000f00 |
#define MC_SEQ_MISC0_VEN_ID_VALUE 3 |
#define MC_SEQ_MISC0_REV_ID_SHIFT 12 |
#define MC_SEQ_MISC0_REV_ID_MASK 0x0000f000 |
#define MC_SEQ_MISC0_REV_ID_VALUE 1 |
#define MC_SEQ_MISC0_GDDR5_SHIFT 28 |
#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000 |
#define MC_SEQ_MISC0_GDDR5_VALUE 5 |
#define MC_SEQ_MISC1 0x2a04 |
#define MC_SEQ_RESERVE_M 0x2a08 |
#define MC_PMG_CMD_EMRS 0x2a0c |
#define MC_SEQ_IO_DEBUG_INDEX 0x2a44 |
#define MC_SEQ_IO_DEBUG_DATA 0x2a48 |
#define MC_SEQ_MISC5 0x2a54 |
#define MC_SEQ_MISC6 0x2a58 |
#define MC_SEQ_MISC7 0x2a64 |
#define MC_SEQ_RAS_TIMING_LP 0x2a6c |
#define MC_SEQ_CAS_TIMING_LP 0x2a70 |
#define MC_SEQ_MISC_TIMING_LP 0x2a74 |
#define MC_SEQ_MISC_TIMING2_LP 0x2a78 |
#define MC_SEQ_WR_CTL_D0_LP 0x2a7c |
#define MC_SEQ_WR_CTL_D1_LP 0x2a80 |
#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84 |
#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88 |
#define MC_PMG_CMD_MRS 0x2aac |
#define MC_SEQ_RD_CTL_D0_LP 0x2b1c |
#define MC_SEQ_RD_CTL_D1_LP 0x2b20 |
#define MC_PMG_CMD_MRS1 0x2b44 |
#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48 |
#define MC_SEQ_PMG_TIMING_LP 0x2b4c |
#define MC_SEQ_WR_CTL_2 0x2b54 |
#define MC_SEQ_WR_CTL_2_LP 0x2b58 |
#define MC_PMG_CMD_MRS2 0x2b5c |
#define MC_SEQ_PMG_CMD_MRS2_LP 0x2b60 |
#define MCLK_PWRMGT_CNTL 0x2ba0 |
# define DLL_SPEED(x) ((x) << 0) |
# define DLL_SPEED_MASK (0x1f << 0) |
# define DLL_READY (1 << 6) |
# define MC_INT_CNTL (1 << 7) |
# define MRDCK0_PDNB (1 << 8) |
# define MRDCK1_PDNB (1 << 9) |
# define MRDCK0_RESET (1 << 16) |
# define MRDCK1_RESET (1 << 17) |
# define DLL_READY_READ (1 << 24) |
#define DLL_CNTL 0x2ba4 |
# 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) |
#define MPLL_FUNC_CNTL_1 0x2bb8 |
#define VCO_MODE(x) ((x) << 0) |
#define VCO_MODE_MASK (3 << 0) |
#define CLKFRAC(x) ((x) << 4) |
#define CLKFRAC_MASK (0xfff << 4) |
#define CLKF(x) ((x) << 16) |
#define CLKF_MASK (0xfff << 16) |
#define MPLL_FUNC_CNTL_2 0x2bbc |
#define MPLL_AD_FUNC_CNTL 0x2bc0 |
#define YCLK_POST_DIV(x) ((x) << 0) |
#define YCLK_POST_DIV_MASK (7 << 0) |
#define MPLL_DQ_FUNC_CNTL 0x2bc4 |
#define YCLK_SEL(x) ((x) << 4) |
#define YCLK_SEL_MASK (1 << 4) |
#define MPLL_SS1 0x2bcc |
#define CLKV(x) ((x) << 0) |
#define CLKV_MASK (0x3ffffff << 0) |
#define MPLL_SS2 0x2bd0 |
#define CLKS(x) ((x) << 0) |
#define CLKS_MASK (0xfff << 0) |
#define HDP_HOST_PATH_CNTL 0x2C00 |
#define CLOCK_GATING_DIS (1 << 23) |
#define HDP_NONSURFACE_BASE 0x2C04 |
#define HDP_NONSURFACE_INFO 0x2C08 |
#define HDP_NONSURFACE_SIZE 0x2C0C |
265,7 → 601,11 |
#define HDP_ADDR_CONFIG 0x2F48 |
#define HDP_MISC_CNTL 0x2F4C |
#define HDP_FLUSH_INVALIDATE_CACHE (1 << 0) |
#define HDP_MEM_POWER_LS 0x2F50 |
#define HDP_LS_ENABLE (1 << 0) |
#define ATC_MISC_CG 0x3350 |
#define IH_RB_CNTL 0x3e00 |
# define IH_RB_ENABLE (1 << 0) |
# define IH_IB_SIZE(x) ((x) << 1) /* log2 */ |
310,6 → 650,99 |
#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 |
/* DCE6 ELD audio interface */ |
#define AZ_F0_CODEC_ENDPOINT_INDEX 0x5E00 |
# define AZ_ENDPOINT_REG_INDEX(x) (((x) & 0xff) << 0) |
# define AZ_ENDPOINT_REG_WRITE_EN (1 << 8) |
#define AZ_F0_CODEC_ENDPOINT_DATA 0x5E04 |
#define AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER 0x25 |
#define SPEAKER_ALLOCATION(x) (((x) & 0x7f) << 0) |
#define SPEAKER_ALLOCATION_MASK (0x7f << 0) |
#define SPEAKER_ALLOCATION_SHIFT 0 |
#define HDMI_CONNECTION (1 << 16) |
#define DP_CONNECTION (1 << 17) |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 0x28 /* LPCM */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1 0x29 /* AC3 */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2 0x2A /* MPEG1 */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3 0x2B /* MP3 */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4 0x2C /* MPEG2 */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5 0x2D /* AAC */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6 0x2E /* DTS */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7 0x2F /* ATRAC */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR8 0x30 /* one bit audio - leave at 0 (default) */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9 0x31 /* Dolby Digital */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10 0x32 /* DTS-HD */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11 0x33 /* MAT-MLP */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR12 0x34 /* DTS */ |
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13 0x35 /* WMA Pro */ |
# define MAX_CHANNELS(x) (((x) & 0x7) << 0) |
/* max channels minus one. 7 = 8 channels */ |
# define SUPPORTED_FREQUENCIES(x) (((x) & 0xff) << 8) |
# define DESCRIPTOR_BYTE_2(x) (((x) & 0xff) << 16) |
# define SUPPORTED_FREQUENCIES_STEREO(x) (((x) & 0xff) << 24) /* LPCM only */ |
/* SUPPORTED_FREQUENCIES, SUPPORTED_FREQUENCIES_STEREO |
* bit0 = 32 kHz |
* bit1 = 44.1 kHz |
* bit2 = 48 kHz |
* bit3 = 88.2 kHz |
* bit4 = 96 kHz |
* 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) |
#define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT 0x56 |
#define PORT_CONNECTIVITY_MASK (3 << 30) |
#define PORT_CONNECTIVITY_SHIFT 30 |
#define DC_LB_MEMORY_SPLIT 0x6b0c |
#define DC_LB_MEMORY_CONFIG(x) ((x) << 20) |
390,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 |
424,9 → 857,23 |
# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) |
# define DC_HPDx_EN (1 << 28) |
#define DPG_PIPE_STUTTER_CONTROL 0x6cd4 |
# define STUTTER_ENABLE (1 << 0) |
/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */ |
#define CRTC_STATUS_FRAME_COUNT 0x6e98 |
#define AFMT_AUDIO_SRC_CONTROL 0x713c |
#define AFMT_AUDIO_SRC_SELECT(x) (((x) & 7) << 0) |
/* AFMT_AUDIO_SRC_SELECT |
* 0 = stream0 |
* 1 = stream1 |
* 2 = stream2 |
* 3 = stream3 |
* 4 = stream4 |
* 5 = stream5 |
*/ |
#define GRBM_CNTL 0x8000 |
#define GRBM_READ_TIMEOUT(x) ((x) << 0) |
599,6 → 1046,24 |
#define SQC_CACHES 0x8C08 |
#define SQ_POWER_THROTTLE 0x8e58 |
#define MIN_POWER(x) ((x) << 0) |
#define MIN_POWER_MASK (0x3fff << 0) |
#define MIN_POWER_SHIFT 0 |
#define MAX_POWER(x) ((x) << 16) |
#define MAX_POWER_MASK (0x3fff << 16) |
#define MAX_POWER_SHIFT 0 |
#define SQ_POWER_THROTTLE2 0x8e5c |
#define MAX_POWER_DELTA(x) ((x) << 0) |
#define MAX_POWER_DELTA_MASK (0x3fff << 0) |
#define MAX_POWER_DELTA_SHIFT 0 |
#define STI_SIZE(x) ((x) << 16) |
#define STI_SIZE_MASK (0x3ff << 16) |
#define STI_SIZE_SHIFT 16 |
#define LTI_RATIO(x) ((x) << 27) |
#define LTI_RATIO_MASK (0xf << 27) |
#define LTI_RATIO_SHIFT 27 |
#define SX_DEBUG_1 0x9060 |
#define SPI_STATIC_THREAD_MGMT_1 0x90E0 |
616,7 → 1081,12 |
#define CGTS_USER_TCC_DISABLE 0x914C |
#define TCC_DISABLE_MASK 0xFFFF0000 |
#define TCC_DISABLE_SHIFT 16 |
#define CGTS_SM_CTRL_REG 0x9150 |
#define OVERRIDE (1 << 21) |
#define LS_OVERRIDE (1 << 22) |
#define SPI_LB_CU_MASK 0x9354 |
#define TA_CNTL_AUX 0x9508 |
#define CC_RB_BACKEND_DISABLE 0x98F4 |
705,6 → 1175,8 |
#define CB_PERFCOUNTER3_SELECT0 0x9a38 |
#define CB_PERFCOUNTER3_SELECT1 0x9a3c |
#define CB_CGTT_SCLK_CTRL 0x9a60 |
#define GC_USER_RB_BACKEND_DISABLE 0x9B7C |
#define BACKEND_DISABLE_MASK 0x00FF0000 |
#define BACKEND_DISABLE_SHIFT 16 |
762,6 → 1234,9 |
# define CP_RINGID1_INT_STAT (1 << 30) |
# define CP_RINGID0_INT_STAT (1 << 31) |
#define CP_MEM_SLP_CNTL 0xC1E4 |
# define CP_MEM_LS_EN (1 << 0) |
#define CP_DEBUG 0xC1FC |
#define RLC_CNTL 0xC300 |
769,6 → 1244,7 |
#define RLC_RL_BASE 0xC304 |
#define RLC_RL_SIZE 0xC308 |
#define RLC_LB_CNTL 0xC30C |
# define LOAD_BALANCE_ENABLE (1 << 0) |
#define RLC_SAVE_AND_RESTORE_BASE 0xC310 |
#define RLC_LB_CNTR_MAX 0xC314 |
#define RLC_LB_CNTR_INIT 0xC318 |
783,7 → 1259,57 |
#define RLC_CAPTURE_GPU_CLOCK_COUNT 0xC340 |
#define RLC_MC_CNTL 0xC344 |
#define RLC_UCODE_CNTL 0xC348 |
#define RLC_STAT 0xC34C |
# define RLC_BUSY_STATUS (1 << 0) |
# define GFX_POWER_STATUS (1 << 1) |
# define GFX_CLOCK_STATUS (1 << 2) |
# define GFX_LS_STATUS (1 << 3) |
#define RLC_PG_CNTL 0xC35C |
# define GFX_PG_ENABLE (1 << 0) |
# define GFX_PG_SRC (1 << 1) |
#define RLC_CGTT_MGCG_OVERRIDE 0xC400 |
#define RLC_CGCG_CGLS_CTRL 0xC404 |
# define CGCG_EN (1 << 0) |
# define CGLS_EN (1 << 1) |
#define RLC_TTOP_D 0xC414 |
# define RLC_PUD(x) ((x) << 0) |
# define RLC_PUD_MASK (0xff << 0) |
# define RLC_PDD(x) ((x) << 8) |
# define RLC_PDD_MASK (0xff << 8) |
# define RLC_TTPD(x) ((x) << 16) |
# define RLC_TTPD_MASK (0xff << 16) |
# define RLC_MSD(x) ((x) << 24) |
# define RLC_MSD_MASK (0xff << 24) |
#define RLC_LB_INIT_CU_MASK 0xC41C |
#define RLC_PG_AO_CU_MASK 0xC42C |
#define RLC_MAX_PG_CU 0xC430 |
# define MAX_PU_CU(x) ((x) << 0) |
# define MAX_PU_CU_MASK (0xff << 0) |
#define RLC_AUTO_PG_CTRL 0xC434 |
# define AUTO_PG_EN (1 << 0) |
# define GRBM_REG_SGIT(x) ((x) << 3) |
# define GRBM_REG_SGIT_MASK (0xffff << 3) |
# define PG_AFTER_GRBM_REG_ST(x) ((x) << 19) |
# define PG_AFTER_GRBM_REG_ST_MASK (0x1fff << 19) |
#define RLC_SERDES_WR_MASTER_MASK_0 0xC454 |
#define RLC_SERDES_WR_MASTER_MASK_1 0xC458 |
#define RLC_SERDES_WR_CTRL 0xC45C |
#define RLC_SERDES_MASTER_BUSY_0 0xC464 |
#define RLC_SERDES_MASTER_BUSY_1 0xC468 |
#define RLC_GCPM_GENERAL_3 0xC478 |
#define DB_RENDER_CONTROL 0x28000 |
#define DB_DEPTH_INFO 0x2803c |
#define PA_SC_RASTER_CONFIG 0x28350 |
# define RASTER_CONFIG_RB_MAP_0 0 |
# define RASTER_CONFIG_RB_MAP_1 1 |
829,6 → 1355,147 |
# define THREAD_TRACE_FLUSH (54 << 0) |
# define THREAD_TRACE_FINISH (55 << 0) |
/* PIF PHY0 registers idx/data 0x8/0xc */ |
#define PB0_PIF_CNTL 0x10 |
# define LS2_EXIT_TIME(x) ((x) << 17) |
# define LS2_EXIT_TIME_MASK (0x7 << 17) |
# define LS2_EXIT_TIME_SHIFT 17 |
#define PB0_PIF_PAIRING 0x11 |
# define MULTI_PIF (1 << 25) |
#define PB0_PIF_PWRDOWN_0 0x12 |
# define PLL_POWER_STATE_IN_TXS2_0(x) ((x) << 7) |
# define PLL_POWER_STATE_IN_TXS2_0_MASK (0x7 << 7) |
# define PLL_POWER_STATE_IN_TXS2_0_SHIFT 7 |
# define PLL_POWER_STATE_IN_OFF_0(x) ((x) << 10) |
# define PLL_POWER_STATE_IN_OFF_0_MASK (0x7 << 10) |
# define PLL_POWER_STATE_IN_OFF_0_SHIFT 10 |
# define PLL_RAMP_UP_TIME_0(x) ((x) << 24) |
# define PLL_RAMP_UP_TIME_0_MASK (0x7 << 24) |
# define PLL_RAMP_UP_TIME_0_SHIFT 24 |
#define PB0_PIF_PWRDOWN_1 0x13 |
# define PLL_POWER_STATE_IN_TXS2_1(x) ((x) << 7) |
# define PLL_POWER_STATE_IN_TXS2_1_MASK (0x7 << 7) |
# define PLL_POWER_STATE_IN_TXS2_1_SHIFT 7 |
# define PLL_POWER_STATE_IN_OFF_1(x) ((x) << 10) |
# define PLL_POWER_STATE_IN_OFF_1_MASK (0x7 << 10) |
# define PLL_POWER_STATE_IN_OFF_1_SHIFT 10 |
# define PLL_RAMP_UP_TIME_1(x) ((x) << 24) |
# define PLL_RAMP_UP_TIME_1_MASK (0x7 << 24) |
# define PLL_RAMP_UP_TIME_1_SHIFT 24 |
#define PB0_PIF_PWRDOWN_2 0x17 |
# define PLL_POWER_STATE_IN_TXS2_2(x) ((x) << 7) |
# define PLL_POWER_STATE_IN_TXS2_2_MASK (0x7 << 7) |
# define PLL_POWER_STATE_IN_TXS2_2_SHIFT 7 |
# define PLL_POWER_STATE_IN_OFF_2(x) ((x) << 10) |
# define PLL_POWER_STATE_IN_OFF_2_MASK (0x7 << 10) |
# define PLL_POWER_STATE_IN_OFF_2_SHIFT 10 |
# define PLL_RAMP_UP_TIME_2(x) ((x) << 24) |
# define PLL_RAMP_UP_TIME_2_MASK (0x7 << 24) |
# define PLL_RAMP_UP_TIME_2_SHIFT 24 |
#define PB0_PIF_PWRDOWN_3 0x18 |
# define PLL_POWER_STATE_IN_TXS2_3(x) ((x) << 7) |
# define PLL_POWER_STATE_IN_TXS2_3_MASK (0x7 << 7) |
# define PLL_POWER_STATE_IN_TXS2_3_SHIFT 7 |
# define PLL_POWER_STATE_IN_OFF_3(x) ((x) << 10) |
# define PLL_POWER_STATE_IN_OFF_3_MASK (0x7 << 10) |
# define PLL_POWER_STATE_IN_OFF_3_SHIFT 10 |
# define PLL_RAMP_UP_TIME_3(x) ((x) << 24) |
# define PLL_RAMP_UP_TIME_3_MASK (0x7 << 24) |
# define PLL_RAMP_UP_TIME_3_SHIFT 24 |
/* PIF PHY1 registers idx/data 0x10/0x14 */ |
#define PB1_PIF_CNTL 0x10 |
#define PB1_PIF_PAIRING 0x11 |
#define PB1_PIF_PWRDOWN_0 0x12 |
#define PB1_PIF_PWRDOWN_1 0x13 |
#define PB1_PIF_PWRDOWN_2 0x17 |
#define PB1_PIF_PWRDOWN_3 0x18 |
/* PCIE registers idx/data 0x30/0x34 */ |
#define PCIE_CNTL2 0x1c /* PCIE */ |
# define SLV_MEM_LS_EN (1 << 16) |
# define SLV_MEM_AGGRESSIVE_LS_EN (1 << 17) |
# define MST_MEM_LS_EN (1 << 18) |
# define REPLAY_MEM_LS_EN (1 << 19) |
#define PCIE_LC_STATUS1 0x28 /* PCIE */ |
# define LC_REVERSE_RCVR (1 << 0) |
# define LC_REVERSE_XMIT (1 << 1) |
# define LC_OPERATING_LINK_WIDTH_MASK (0x7 << 2) |
# define LC_OPERATING_LINK_WIDTH_SHIFT 2 |
# define LC_DETECTED_LINK_WIDTH_MASK (0x7 << 5) |
# define LC_DETECTED_LINK_WIDTH_SHIFT 5 |
#define PCIE_P_CNTL 0x40 /* PCIE */ |
# define P_IGNORE_EDB_ERR (1 << 6) |
/* PCIE PORT registers idx/data 0x38/0x3c */ |
#define PCIE_LC_CNTL 0xa0 |
# define LC_L0S_INACTIVITY(x) ((x) << 8) |
# define LC_L0S_INACTIVITY_MASK (0xf << 8) |
# define LC_L0S_INACTIVITY_SHIFT 8 |
# define LC_L1_INACTIVITY(x) ((x) << 12) |
# define LC_L1_INACTIVITY_MASK (0xf << 12) |
# define LC_L1_INACTIVITY_SHIFT 12 |
# define LC_PMI_TO_L1_DIS (1 << 16) |
# define LC_ASPM_TO_L1_DIS (1 << 24) |
#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ |
# define LC_LINK_WIDTH_SHIFT 0 |
# define LC_LINK_WIDTH_MASK 0x7 |
# define LC_LINK_WIDTH_X0 0 |
# define LC_LINK_WIDTH_X1 1 |
# define LC_LINK_WIDTH_X2 2 |
# define LC_LINK_WIDTH_X4 3 |
# define LC_LINK_WIDTH_X8 4 |
# define LC_LINK_WIDTH_X16 6 |
# define LC_LINK_WIDTH_RD_SHIFT 4 |
# define LC_LINK_WIDTH_RD_MASK 0x70 |
# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) |
# define LC_RECONFIG_NOW (1 << 8) |
# define LC_RENEGOTIATION_SUPPORT (1 << 9) |
# define LC_RENEGOTIATE_EN (1 << 10) |
# define LC_SHORT_RECONFIG_EN (1 << 11) |
# define LC_UPCONFIGURE_SUPPORT (1 << 12) |
# define LC_UPCONFIGURE_DIS (1 << 13) |
# define LC_DYN_LANES_PWR_STATE(x) ((x) << 21) |
# define LC_DYN_LANES_PWR_STATE_MASK (0x3 << 21) |
# define LC_DYN_LANES_PWR_STATE_SHIFT 21 |
#define PCIE_LC_N_FTS_CNTL 0xa3 /* PCIE_P */ |
# define LC_XMIT_N_FTS(x) ((x) << 0) |
# define LC_XMIT_N_FTS_MASK (0xff << 0) |
# define LC_XMIT_N_FTS_SHIFT 0 |
# define LC_XMIT_N_FTS_OVERRIDE_EN (1 << 8) |
# define LC_N_FTS_MASK (0xff << 24) |
#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ |
# define LC_GEN2_EN_STRAP (1 << 0) |
# define LC_GEN3_EN_STRAP (1 << 1) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 2) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_MASK (0x3 << 3) |
# define LC_TARGET_LINK_SPEED_OVERRIDE_SHIFT 3 |
# define LC_FORCE_EN_SW_SPEED_CHANGE (1 << 5) |
# define LC_FORCE_DIS_SW_SPEED_CHANGE (1 << 6) |
# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 7) |
# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 8) |
# define LC_INITIATE_LINK_SPEED_CHANGE (1 << 9) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 10) |
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 10 |
# define LC_CURRENT_DATA_RATE_MASK (0x3 << 13) /* 0/1/2 = gen1/2/3 */ |
# define LC_CURRENT_DATA_RATE_SHIFT 13 |
# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 16) |
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 18) |
# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 19) |
# define LC_OTHER_SIDE_EVER_SENT_GEN3 (1 << 20) |
# define LC_OTHER_SIDE_SUPPORTS_GEN3 (1 << 21) |
#define PCIE_LC_CNTL2 0xb1 |
# define LC_ALLOW_PDWN_IN_L1 (1 << 17) |
# define LC_ALLOW_PDWN_IN_L23 (1 << 18) |
#define PCIE_LC_CNTL3 0xb5 /* PCIE_P */ |
# define LC_GO_TO_RECOVERY (1 << 30) |
#define PCIE_LC_CNTL4 0xb6 /* PCIE_P */ |
# define LC_REDO_EQ (1 << 5) |
# define LC_SET_QUIESCE (1 << 13) |
/* |
* UVD |
*/ |
838,6 → 1505,21 |
#define UVD_RBC_RB_RPTR 0xF690 |
#define UVD_RBC_RB_WPTR 0xF694 |
#define UVD_CGC_CTRL 0xF4B0 |
# define DCM (1 << 0) |
# define CG_DT(x) ((x) << 2) |
# define CG_DT_MASK (0xf << 2) |
# define CLK_OD(x) ((x) << 6) |
# define CLK_OD_MASK (0x1f << 6) |
/* UVD CTX indirect */ |
#define UVD_CGC_MEM_CTRL 0xC0 |
#define UVD_CGC_CTRL2 0xC1 |
# define DYN_OR_EN (1 << 0) |
# define DYN_RR_EN (1 << 1) |
# define G_DIV_ID(x) ((x) << 2) |
# define G_DIV_ID_MASK (0x7 << 2) |
/* |
* PM4 |
*/ |
924,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) |
939,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 |
1082,6 → 1764,15 |
# define DMA_IDLE (1 << 0) |
#define DMA_TILING_CONFIG 0xd0b8 |
#define DMA_POWER_CNTL 0xd0bc |
# define MEM_POWER_OVERRIDE (1 << 8) |
#define DMA_CLK_CTRL 0xd0c0 |
#define DMA_PG 0xd0d4 |
# define PG_CNTL_ENABLE (1 << 0) |
#define DMA_PGFSM_CONFIG 0xd0d8 |
#define DMA_PGFSM_WRITE 0xd0dc |
#define DMA_PACKET(cmd, b, t, s, n) ((((cmd) & 0xF) << 28) | \ |
(((b) & 0x1) << 26) | \ |
(((t) & 0x1) << 23) | \ |
1108,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 |
/drivers/video/drm/radeon/sislands_smc.h |
---|
0,0 → 1,398 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef PP_SISLANDS_SMC_H |
#define PP_SISLANDS_SMC_H |
#include "ppsmc.h" |
#pragma pack(push, 1) |
#define SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16 |
struct PP_SIslands_Dpm2PerfLevel |
{ |
uint8_t MaxPS; |
uint8_t TgtAct; |
uint8_t MaxPS_StepInc; |
uint8_t MaxPS_StepDec; |
uint8_t PSSamplingTime; |
uint8_t NearTDPDec; |
uint8_t AboveSafeInc; |
uint8_t BelowSafeInc; |
uint8_t PSDeltaLimit; |
uint8_t PSDeltaWin; |
uint16_t PwrEfficiencyRatio; |
uint8_t Reserved[4]; |
}; |
typedef struct PP_SIslands_Dpm2PerfLevel PP_SIslands_Dpm2PerfLevel; |
struct PP_SIslands_DPM2Status |
{ |
uint32_t dpm2Flags; |
uint8_t CurrPSkip; |
uint8_t CurrPSkipPowerShift; |
uint8_t CurrPSkipTDP; |
uint8_t CurrPSkipOCP; |
uint8_t MaxSPLLIndex; |
uint8_t MinSPLLIndex; |
uint8_t CurrSPLLIndex; |
uint8_t InfSweepMode; |
uint8_t InfSweepDir; |
uint8_t TDPexceeded; |
uint8_t reserved; |
uint8_t SwitchDownThreshold; |
uint32_t SwitchDownCounter; |
uint32_t SysScalingFactor; |
}; |
typedef struct PP_SIslands_DPM2Status PP_SIslands_DPM2Status; |
struct PP_SIslands_DPM2Parameters |
{ |
uint32_t TDPLimit; |
uint32_t NearTDPLimit; |
uint32_t SafePowerLimit; |
uint32_t PowerBoostLimit; |
uint32_t MinLimitDelta; |
}; |
typedef struct PP_SIslands_DPM2Parameters PP_SIslands_DPM2Parameters; |
struct PP_SIslands_PAPMStatus |
{ |
uint32_t EstimatedDGPU_T; |
uint32_t EstimatedDGPU_P; |
uint32_t EstimatedAPU_T; |
uint32_t EstimatedAPU_P; |
uint8_t dGPU_T_Limit_Exceeded; |
uint8_t reserved[3]; |
}; |
typedef struct PP_SIslands_PAPMStatus PP_SIslands_PAPMStatus; |
struct PP_SIslands_PAPMParameters |
{ |
uint32_t NearTDPLimitTherm; |
uint32_t NearTDPLimitPAPM; |
uint32_t PlatformPowerLimit; |
uint32_t dGPU_T_Limit; |
uint32_t dGPU_T_Warning; |
uint32_t dGPU_T_Hysteresis; |
}; |
typedef struct PP_SIslands_PAPMParameters PP_SIslands_PAPMParameters; |
struct SISLANDS_SMC_SCLK_VALUE |
{ |
uint32_t vCG_SPLL_FUNC_CNTL; |
uint32_t vCG_SPLL_FUNC_CNTL_2; |
uint32_t vCG_SPLL_FUNC_CNTL_3; |
uint32_t vCG_SPLL_FUNC_CNTL_4; |
uint32_t vCG_SPLL_SPREAD_SPECTRUM; |
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2; |
uint32_t sclk_value; |
}; |
typedef struct SISLANDS_SMC_SCLK_VALUE SISLANDS_SMC_SCLK_VALUE; |
struct SISLANDS_SMC_MCLK_VALUE |
{ |
uint32_t vMPLL_FUNC_CNTL; |
uint32_t vMPLL_FUNC_CNTL_1; |
uint32_t vMPLL_FUNC_CNTL_2; |
uint32_t vMPLL_AD_FUNC_CNTL; |
uint32_t vMPLL_DQ_FUNC_CNTL; |
uint32_t vMCLK_PWRMGT_CNTL; |
uint32_t vDLL_CNTL; |
uint32_t vMPLL_SS; |
uint32_t vMPLL_SS2; |
uint32_t mclk_value; |
}; |
typedef struct SISLANDS_SMC_MCLK_VALUE SISLANDS_SMC_MCLK_VALUE; |
struct SISLANDS_SMC_VOLTAGE_VALUE |
{ |
uint16_t value; |
uint8_t index; |
uint8_t phase_settings; |
}; |
typedef struct SISLANDS_SMC_VOLTAGE_VALUE SISLANDS_SMC_VOLTAGE_VALUE; |
struct SISLANDS_SMC_HW_PERFORMANCE_LEVEL |
{ |
uint8_t ACIndex; |
uint8_t displayWatermark; |
uint8_t gen2PCIE; |
uint8_t UVDWatermark; |
uint8_t VCEWatermark; |
uint8_t strobeMode; |
uint8_t mcFlags; |
uint8_t padding; |
uint32_t aT; |
uint32_t bSP; |
SISLANDS_SMC_SCLK_VALUE sclk; |
SISLANDS_SMC_MCLK_VALUE mclk; |
SISLANDS_SMC_VOLTAGE_VALUE vddc; |
SISLANDS_SMC_VOLTAGE_VALUE mvdd; |
SISLANDS_SMC_VOLTAGE_VALUE vddci; |
SISLANDS_SMC_VOLTAGE_VALUE std_vddc; |
uint8_t hysteresisUp; |
uint8_t hysteresisDown; |
uint8_t stateFlags; |
uint8_t arbRefreshState; |
uint32_t SQPowerThrottle; |
uint32_t SQPowerThrottle_2; |
uint32_t MaxPoweredUpCU; |
SISLANDS_SMC_VOLTAGE_VALUE high_temp_vddc; |
SISLANDS_SMC_VOLTAGE_VALUE low_temp_vddc; |
uint32_t reserved[2]; |
PP_SIslands_Dpm2PerfLevel dpm2; |
}; |
#define SISLANDS_SMC_STROBE_RATIO 0x0F |
#define SISLANDS_SMC_STROBE_ENABLE 0x10 |
#define SISLANDS_SMC_MC_EDC_RD_FLAG 0x01 |
#define SISLANDS_SMC_MC_EDC_WR_FLAG 0x02 |
#define SISLANDS_SMC_MC_RTT_ENABLE 0x04 |
#define SISLANDS_SMC_MC_STUTTER_EN 0x08 |
#define SISLANDS_SMC_MC_PG_EN 0x10 |
typedef struct SISLANDS_SMC_HW_PERFORMANCE_LEVEL SISLANDS_SMC_HW_PERFORMANCE_LEVEL; |
struct SISLANDS_SMC_SWSTATE |
{ |
uint8_t flags; |
uint8_t levelCount; |
uint8_t padding2; |
uint8_t padding3; |
SISLANDS_SMC_HW_PERFORMANCE_LEVEL levels[1]; |
}; |
typedef struct SISLANDS_SMC_SWSTATE SISLANDS_SMC_SWSTATE; |
#define SISLANDS_SMC_VOLTAGEMASK_VDDC 0 |
#define SISLANDS_SMC_VOLTAGEMASK_MVDD 1 |
#define SISLANDS_SMC_VOLTAGEMASK_VDDCI 2 |
#define SISLANDS_SMC_VOLTAGEMASK_MAX 4 |
struct SISLANDS_SMC_VOLTAGEMASKTABLE |
{ |
uint32_t lowMask[SISLANDS_SMC_VOLTAGEMASK_MAX]; |
}; |
typedef struct SISLANDS_SMC_VOLTAGEMASKTABLE SISLANDS_SMC_VOLTAGEMASKTABLE; |
#define SISLANDS_MAX_NO_VREG_STEPS 32 |
struct SISLANDS_SMC_STATETABLE |
{ |
uint8_t thermalProtectType; |
uint8_t systemFlags; |
uint8_t maxVDDCIndexInPPTable; |
uint8_t extraFlags; |
uint32_t lowSMIO[SISLANDS_MAX_NO_VREG_STEPS]; |
SISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable; |
SISLANDS_SMC_VOLTAGEMASKTABLE phaseMaskTable; |
PP_SIslands_DPM2Parameters dpm2Params; |
SISLANDS_SMC_SWSTATE initialState; |
SISLANDS_SMC_SWSTATE ACPIState; |
SISLANDS_SMC_SWSTATE ULVState; |
SISLANDS_SMC_SWSTATE driverState; |
SISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1]; |
}; |
typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE; |
#define SI_SMC_SOFT_REGISTER_mclk_chg_timeout 0x0 |
#define SI_SMC_SOFT_REGISTER_delay_vreg 0xC |
#define SI_SMC_SOFT_REGISTER_delay_acpi 0x28 |
#define SI_SMC_SOFT_REGISTER_seq_index 0x5C |
#define SI_SMC_SOFT_REGISTER_mvdd_chg_time 0x60 |
#define SI_SMC_SOFT_REGISTER_mclk_switch_lim 0x70 |
#define SI_SMC_SOFT_REGISTER_watermark_threshold 0x78 |
#define SI_SMC_SOFT_REGISTER_phase_shedding_delay 0x88 |
#define SI_SMC_SOFT_REGISTER_ulv_volt_change_delay 0x8C |
#define SI_SMC_SOFT_REGISTER_mc_block_delay 0x98 |
#define SI_SMC_SOFT_REGISTER_ticks_per_us 0xA8 |
#define SI_SMC_SOFT_REGISTER_crtc_index 0xC4 |
#define SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min 0xC8 |
#define SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max 0xCC |
#define SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width 0xF4 |
#define SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen 0xFC |
#define SI_SMC_SOFT_REGISTER_vr_hot_gpio 0x100 |
#define SI_SMC_SOFT_REGISTER_svi_rework_plat_type 0x118 |
#define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd 0x11c |
#define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc 0x120 |
#define SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16 |
#define SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 32 |
#define SMC_SISLANDS_SCALE_I 7 |
#define SMC_SISLANDS_SCALE_R 12 |
struct PP_SIslands_CacConfig |
{ |
uint16_t cac_lkge_lut[SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES]; |
uint32_t lkge_lut_V0; |
uint32_t lkge_lut_Vstep; |
uint32_t WinTime; |
uint32_t R_LL; |
uint32_t calculation_repeats; |
uint32_t l2numWin_TDP; |
uint32_t dc_cac; |
uint8_t lts_truncate_n; |
uint8_t SHIFT_N; |
uint8_t log2_PG_LKG_SCALE; |
uint8_t cac_temp; |
uint32_t lkge_lut_T0; |
uint32_t lkge_lut_Tstep; |
}; |
typedef struct PP_SIslands_CacConfig PP_SIslands_CacConfig; |
#define SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE 16 |
#define SMC_SISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20 |
struct SMC_SIslands_MCRegisterAddress |
{ |
uint16_t s0; |
uint16_t s1; |
}; |
typedef struct SMC_SIslands_MCRegisterAddress SMC_SIslands_MCRegisterAddress; |
struct SMC_SIslands_MCRegisterSet |
{ |
uint32_t value[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE]; |
}; |
typedef struct SMC_SIslands_MCRegisterSet SMC_SIslands_MCRegisterSet; |
struct SMC_SIslands_MCRegisters |
{ |
uint8_t last; |
uint8_t reserved[3]; |
SMC_SIslands_MCRegisterAddress address[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE]; |
SMC_SIslands_MCRegisterSet data[SMC_SISLANDS_MC_REGISTER_ARRAY_SET_COUNT]; |
}; |
typedef struct SMC_SIslands_MCRegisters SMC_SIslands_MCRegisters; |
struct SMC_SIslands_MCArbDramTimingRegisterSet |
{ |
uint32_t mc_arb_dram_timing; |
uint32_t mc_arb_dram_timing2; |
uint8_t mc_arb_rfsh_rate; |
uint8_t mc_arb_burst_time; |
uint8_t padding[2]; |
}; |
typedef struct SMC_SIslands_MCArbDramTimingRegisterSet SMC_SIslands_MCArbDramTimingRegisterSet; |
struct SMC_SIslands_MCArbDramTimingRegisters |
{ |
uint8_t arb_current; |
uint8_t reserved[3]; |
SMC_SIslands_MCArbDramTimingRegisterSet data[16]; |
}; |
typedef struct SMC_SIslands_MCArbDramTimingRegisters SMC_SIslands_MCArbDramTimingRegisters; |
struct SMC_SISLANDS_SPLL_DIV_TABLE |
{ |
uint32_t freq[256]; |
uint32_t ss[256]; |
}; |
#define SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK 0x01ffffff |
#define SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT 0 |
#define SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK 0xfe000000 |
#define SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT 25 |
#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK 0x000fffff |
#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT 0 |
#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK 0xfff00000 |
#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT 20 |
typedef struct SMC_SISLANDS_SPLL_DIV_TABLE SMC_SISLANDS_SPLL_DIV_TABLE; |
#define SMC_SISLANDS_DTE_MAX_FILTER_STAGES 5 |
#define SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE 16 |
struct Smc_SIslands_DTE_Configuration |
{ |
uint32_t tau[SMC_SISLANDS_DTE_MAX_FILTER_STAGES]; |
uint32_t R[SMC_SISLANDS_DTE_MAX_FILTER_STAGES]; |
uint32_t K; |
uint32_t T0; |
uint32_t MaxT; |
uint8_t WindowSize; |
uint8_t Tdep_count; |
uint8_t temp_select; |
uint8_t DTE_mode; |
uint8_t T_limits[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE]; |
uint32_t Tdep_tau[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE]; |
uint32_t Tdep_R[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE]; |
uint32_t Tthreshold; |
}; |
typedef struct Smc_SIslands_DTE_Configuration Smc_SIslands_DTE_Configuration; |
#define SMC_SISLANDS_DTE_STATUS_FLAG_DTE_ON 1 |
#define SISLANDS_SMC_FIRMWARE_HEADER_LOCATION 0x10000 |
#define SISLANDS_SMC_FIRMWARE_HEADER_version 0x0 |
#define SISLANDS_SMC_FIRMWARE_HEADER_flags 0x4 |
#define SISLANDS_SMC_FIRMWARE_HEADER_softRegisters 0xC |
#define SISLANDS_SMC_FIRMWARE_HEADER_stateTable 0x10 |
#define SISLANDS_SMC_FIRMWARE_HEADER_fanTable 0x14 |
#define SISLANDS_SMC_FIRMWARE_HEADER_CacConfigTable 0x18 |
#define SISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable 0x24 |
#define SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable 0x30 |
#define SISLANDS_SMC_FIRMWARE_HEADER_spllTable 0x38 |
#define SISLANDS_SMC_FIRMWARE_HEADER_DteConfiguration 0x40 |
#define SISLANDS_SMC_FIRMWARE_HEADER_PAPMParameters 0x48 |
#pragma pack(pop) |
int si_copy_bytes_to_smc(struct radeon_device *rdev, |
u32 smc_start_address, |
const u8 *src, u32 byte_count, u32 limit); |
void si_start_smc(struct radeon_device *rdev); |
void si_reset_smc(struct radeon_device *rdev); |
int si_program_jump_on_start(struct radeon_device *rdev); |
void si_stop_smc_clock(struct radeon_device *rdev); |
void si_start_smc_clock(struct radeon_device *rdev); |
bool si_is_smc_running(struct radeon_device *rdev); |
PPSMC_Result si_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg); |
PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev); |
int si_load_smc_ucode(struct radeon_device *rdev, u32 limit); |
int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, |
u32 *value, u32 limit); |
int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, |
u32 value, u32 limit); |
#endif |
/drivers/video/drm/radeon/smu7.h |
---|
0,0 → 1,170 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef SMU7_H |
#define SMU7_H |
#pragma pack(push, 1) |
#define SMU7_CONTEXT_ID_SMC 1 |
#define SMU7_CONTEXT_ID_VBIOS 2 |
#define SMU7_CONTEXT_ID_SMC 1 |
#define SMU7_CONTEXT_ID_VBIOS 2 |
#define SMU7_MAX_LEVELS_VDDC 8 |
#define SMU7_MAX_LEVELS_VDDCI 4 |
#define SMU7_MAX_LEVELS_MVDD 4 |
#define SMU7_MAX_LEVELS_VDDNB 8 |
#define SMU7_MAX_LEVELS_GRAPHICS SMU__NUM_SCLK_DPM_STATE // SCLK + SQ DPM + ULV |
#define SMU7_MAX_LEVELS_MEMORY SMU__NUM_MCLK_DPM_LEVELS // MCLK Levels DPM |
#define SMU7_MAX_LEVELS_GIO SMU__NUM_LCLK_DPM_LEVELS // LCLK Levels |
#define SMU7_MAX_LEVELS_LINK SMU__NUM_PCIE_DPM_LEVELS // PCIe speed and number of lanes. |
#define SMU7_MAX_LEVELS_UVD 8 // VCLK/DCLK levels for UVD. |
#define SMU7_MAX_LEVELS_VCE 8 // ECLK levels for VCE. |
#define SMU7_MAX_LEVELS_ACP 8 // ACLK levels for ACP. |
#define SMU7_MAX_LEVELS_SAMU 8 // SAMCLK levels for SAMU. |
#define SMU7_MAX_ENTRIES_SMIO 32 // Number of entries in SMIO table. |
#define DPM_NO_LIMIT 0 |
#define DPM_NO_UP 1 |
#define DPM_GO_DOWN 2 |
#define DPM_GO_UP 3 |
#define SMU7_FIRST_DPM_GRAPHICS_LEVEL 0 |
#define SMU7_FIRST_DPM_MEMORY_LEVEL 0 |
#define GPIO_CLAMP_MODE_VRHOT 1 |
#define GPIO_CLAMP_MODE_THERM 2 |
#define GPIO_CLAMP_MODE_DC 4 |
#define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0 |
#define SCRATCH_B_TARG_PCIE_INDEX_MASK (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT) |
#define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3 |
#define SCRATCH_B_CURR_PCIE_INDEX_MASK (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT) |
#define SCRATCH_B_TARG_UVD_INDEX_SHIFT 6 |
#define SCRATCH_B_TARG_UVD_INDEX_MASK (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT) |
#define SCRATCH_B_CURR_UVD_INDEX_SHIFT 9 |
#define SCRATCH_B_CURR_UVD_INDEX_MASK (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT) |
#define SCRATCH_B_TARG_VCE_INDEX_SHIFT 12 |
#define SCRATCH_B_TARG_VCE_INDEX_MASK (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT) |
#define SCRATCH_B_CURR_VCE_INDEX_SHIFT 15 |
#define SCRATCH_B_CURR_VCE_INDEX_MASK (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT) |
#define SCRATCH_B_TARG_ACP_INDEX_SHIFT 18 |
#define SCRATCH_B_TARG_ACP_INDEX_MASK (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT) |
#define SCRATCH_B_CURR_ACP_INDEX_SHIFT 21 |
#define SCRATCH_B_CURR_ACP_INDEX_MASK (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT) |
#define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24 |
#define SCRATCH_B_TARG_SAMU_INDEX_MASK (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT) |
#define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27 |
#define SCRATCH_B_CURR_SAMU_INDEX_MASK (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT) |
struct SMU7_PIDController |
{ |
uint32_t Ki; |
int32_t LFWindupUL; |
int32_t LFWindupLL; |
uint32_t StatePrecision; |
uint32_t LfPrecision; |
uint32_t LfOffset; |
uint32_t MaxState; |
uint32_t MaxLfFraction; |
uint32_t StateShift; |
}; |
typedef struct SMU7_PIDController SMU7_PIDController; |
// ------------------------------------------------------------------------------------------------------------------------- |
#define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */ |
#define SMU7_SCLK_DPM_CONFIG_MASK 0x01 |
#define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK 0x02 |
#define SMU7_THERMAL_CONTROLLER_CONFIG_MASK 0x04 |
#define SMU7_MCLK_DPM_CONFIG_MASK 0x08 |
#define SMU7_UVD_DPM_CONFIG_MASK 0x10 |
#define SMU7_VCE_DPM_CONFIG_MASK 0x20 |
#define SMU7_ACP_DPM_CONFIG_MASK 0x40 |
#define SMU7_SAMU_DPM_CONFIG_MASK 0x80 |
#define SMU7_PCIEGEN_DPM_CONFIG_MASK 0x100 |
#define SMU7_ACP_MCLK_HANDSHAKE_DISABLE 0x00000001 |
#define SMU7_ACP_SCLK_HANDSHAKE_DISABLE 0x00000002 |
#define SMU7_UVD_MCLK_HANDSHAKE_DISABLE 0x00000100 |
#define SMU7_UVD_SCLK_HANDSHAKE_DISABLE 0x00000200 |
#define SMU7_VCE_MCLK_HANDSHAKE_DISABLE 0x00010000 |
#define SMU7_VCE_SCLK_HANDSHAKE_DISABLE 0x00020000 |
struct SMU7_Firmware_Header |
{ |
uint32_t Digest[5]; |
uint32_t Version; |
uint32_t HeaderSize; |
uint32_t Flags; |
uint32_t EntryPoint; |
uint32_t CodeSize; |
uint32_t ImageSize; |
uint32_t Rtos; |
uint32_t SoftRegisters; |
uint32_t DpmTable; |
uint32_t FanTable; |
uint32_t CacConfigTable; |
uint32_t CacStatusTable; |
uint32_t mcRegisterTable; |
uint32_t mcArbDramTimingTable; |
uint32_t PmFuseTable; |
uint32_t Globals; |
uint32_t Reserved[42]; |
uint32_t Signature; |
}; |
typedef struct SMU7_Firmware_Header SMU7_Firmware_Header; |
#define SMU7_FIRMWARE_HEADER_LOCATION 0x20000 |
enum DisplayConfig { |
PowerDown = 1, |
DP54x4, |
DP54x2, |
DP54x1, |
DP27x4, |
DP27x2, |
DP27x1, |
HDMI297, |
HDMI162, |
LVDS, |
DP324x4, |
DP324x2, |
DP324x1 |
}; |
#pragma pack(pop) |
#endif |
/drivers/video/drm/radeon/smu7_discrete.h |
---|
0,0 → 1,486 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef SMU7_DISCRETE_H |
#define SMU7_DISCRETE_H |
#include "smu7.h" |
#pragma pack(push, 1) |
#define SMU7_DTE_ITERATIONS 5 |
#define SMU7_DTE_SOURCES 3 |
#define SMU7_DTE_SINKS 1 |
#define SMU7_NUM_CPU_TES 0 |
#define SMU7_NUM_GPU_TES 1 |
#define SMU7_NUM_NON_TES 2 |
struct SMU7_SoftRegisters |
{ |
uint32_t RefClockFrequency; |
uint32_t PmTimerP; |
uint32_t FeatureEnables; |
uint32_t PreVBlankGap; |
uint32_t VBlankTimeout; |
uint32_t TrainTimeGap; |
uint32_t MvddSwitchTime; |
uint32_t LongestAcpiTrainTime; |
uint32_t AcpiDelay; |
uint32_t G5TrainTime; |
uint32_t DelayMpllPwron; |
uint32_t VoltageChangeTimeout; |
uint32_t HandshakeDisables; |
uint8_t DisplayPhy1Config; |
uint8_t DisplayPhy2Config; |
uint8_t DisplayPhy3Config; |
uint8_t DisplayPhy4Config; |
uint8_t DisplayPhy5Config; |
uint8_t DisplayPhy6Config; |
uint8_t DisplayPhy7Config; |
uint8_t DisplayPhy8Config; |
uint32_t AverageGraphicsA; |
uint32_t AverageMemoryA; |
uint32_t AverageGioA; |
uint8_t SClkDpmEnabledLevels; |
uint8_t MClkDpmEnabledLevels; |
uint8_t LClkDpmEnabledLevels; |
uint8_t PCIeDpmEnabledLevels; |
uint8_t UVDDpmEnabledLevels; |
uint8_t SAMUDpmEnabledLevels; |
uint8_t ACPDpmEnabledLevels; |
uint8_t VCEDpmEnabledLevels; |
uint32_t DRAM_LOG_ADDR_H; |
uint32_t DRAM_LOG_ADDR_L; |
uint32_t DRAM_LOG_PHY_ADDR_H; |
uint32_t DRAM_LOG_PHY_ADDR_L; |
uint32_t DRAM_LOG_BUFF_SIZE; |
uint32_t UlvEnterC; |
uint32_t UlvTime; |
uint32_t Reserved[3]; |
}; |
typedef struct SMU7_SoftRegisters SMU7_SoftRegisters; |
struct SMU7_Discrete_VoltageLevel |
{ |
uint16_t Voltage; |
uint16_t StdVoltageHiSidd; |
uint16_t StdVoltageLoSidd; |
uint8_t Smio; |
uint8_t padding; |
}; |
typedef struct SMU7_Discrete_VoltageLevel SMU7_Discrete_VoltageLevel; |
struct SMU7_Discrete_GraphicsLevel |
{ |
uint32_t Flags; |
uint32_t MinVddc; |
uint32_t MinVddcPhases; |
uint32_t SclkFrequency; |
uint8_t padding1[2]; |
uint16_t ActivityLevel; |
uint32_t CgSpllFuncCntl3; |
uint32_t CgSpllFuncCntl4; |
uint32_t SpllSpreadSpectrum; |
uint32_t SpllSpreadSpectrum2; |
uint32_t CcPwrDynRm; |
uint32_t CcPwrDynRm1; |
uint8_t SclkDid; |
uint8_t DisplayWatermark; |
uint8_t EnabledForActivity; |
uint8_t EnabledForThrottle; |
uint8_t UpH; |
uint8_t DownH; |
uint8_t VoltageDownH; |
uint8_t PowerThrottle; |
uint8_t DeepSleepDivId; |
uint8_t padding[3]; |
}; |
typedef struct SMU7_Discrete_GraphicsLevel SMU7_Discrete_GraphicsLevel; |
struct SMU7_Discrete_ACPILevel |
{ |
uint32_t Flags; |
uint32_t MinVddc; |
uint32_t MinVddcPhases; |
uint32_t SclkFrequency; |
uint8_t SclkDid; |
uint8_t DisplayWatermark; |
uint8_t DeepSleepDivId; |
uint8_t padding; |
uint32_t CgSpllFuncCntl; |
uint32_t CgSpllFuncCntl2; |
uint32_t CgSpllFuncCntl3; |
uint32_t CgSpllFuncCntl4; |
uint32_t SpllSpreadSpectrum; |
uint32_t SpllSpreadSpectrum2; |
uint32_t CcPwrDynRm; |
uint32_t CcPwrDynRm1; |
}; |
typedef struct SMU7_Discrete_ACPILevel SMU7_Discrete_ACPILevel; |
struct SMU7_Discrete_Ulv |
{ |
uint32_t CcPwrDynRm; |
uint32_t CcPwrDynRm1; |
uint16_t VddcOffset; |
uint8_t VddcOffsetVid; |
uint8_t VddcPhase; |
uint32_t Reserved; |
}; |
typedef struct SMU7_Discrete_Ulv SMU7_Discrete_Ulv; |
struct SMU7_Discrete_MemoryLevel |
{ |
uint32_t MinVddc; |
uint32_t MinVddcPhases; |
uint32_t MinVddci; |
uint32_t MinMvdd; |
uint32_t MclkFrequency; |
uint8_t EdcReadEnable; |
uint8_t EdcWriteEnable; |
uint8_t RttEnable; |
uint8_t StutterEnable; |
uint8_t StrobeEnable; |
uint8_t StrobeRatio; |
uint8_t EnabledForThrottle; |
uint8_t EnabledForActivity; |
uint8_t UpH; |
uint8_t DownH; |
uint8_t VoltageDownH; |
uint8_t padding; |
uint16_t ActivityLevel; |
uint8_t DisplayWatermark; |
uint8_t padding1; |
uint32_t MpllFuncCntl; |
uint32_t MpllFuncCntl_1; |
uint32_t MpllFuncCntl_2; |
uint32_t MpllAdFuncCntl; |
uint32_t MpllDqFuncCntl; |
uint32_t MclkPwrmgtCntl; |
uint32_t DllCntl; |
uint32_t MpllSs1; |
uint32_t MpllSs2; |
}; |
typedef struct SMU7_Discrete_MemoryLevel SMU7_Discrete_MemoryLevel; |
struct SMU7_Discrete_LinkLevel |
{ |
uint8_t PcieGenSpeed; |
uint8_t PcieLaneCount; |
uint8_t EnabledForActivity; |
uint8_t Padding; |
uint32_t DownT; |
uint32_t UpT; |
uint32_t Reserved; |
}; |
typedef struct SMU7_Discrete_LinkLevel SMU7_Discrete_LinkLevel; |
struct SMU7_Discrete_MCArbDramTimingTableEntry |
{ |
uint32_t McArbDramTiming; |
uint32_t McArbDramTiming2; |
uint8_t McArbBurstTime; |
uint8_t padding[3]; |
}; |
typedef struct SMU7_Discrete_MCArbDramTimingTableEntry SMU7_Discrete_MCArbDramTimingTableEntry; |
struct SMU7_Discrete_MCArbDramTimingTable |
{ |
SMU7_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS]; |
}; |
typedef struct SMU7_Discrete_MCArbDramTimingTable SMU7_Discrete_MCArbDramTimingTable; |
struct SMU7_Discrete_UvdLevel |
{ |
uint32_t VclkFrequency; |
uint32_t DclkFrequency; |
uint16_t MinVddc; |
uint8_t MinVddcPhases; |
uint8_t VclkDivider; |
uint8_t DclkDivider; |
uint8_t padding[3]; |
}; |
typedef struct SMU7_Discrete_UvdLevel SMU7_Discrete_UvdLevel; |
struct SMU7_Discrete_ExtClkLevel |
{ |
uint32_t Frequency; |
uint16_t MinVoltage; |
uint8_t MinPhases; |
uint8_t Divider; |
}; |
typedef struct SMU7_Discrete_ExtClkLevel SMU7_Discrete_ExtClkLevel; |
struct SMU7_Discrete_StateInfo |
{ |
uint32_t SclkFrequency; |
uint32_t MclkFrequency; |
uint32_t VclkFrequency; |
uint32_t DclkFrequency; |
uint32_t SamclkFrequency; |
uint32_t AclkFrequency; |
uint32_t EclkFrequency; |
uint16_t MvddVoltage; |
uint16_t padding16; |
uint8_t DisplayWatermark; |
uint8_t McArbIndex; |
uint8_t McRegIndex; |
uint8_t SeqIndex; |
uint8_t SclkDid; |
int8_t SclkIndex; |
int8_t MclkIndex; |
uint8_t PCIeGen; |
}; |
typedef struct SMU7_Discrete_StateInfo SMU7_Discrete_StateInfo; |
struct SMU7_Discrete_DpmTable |
{ |
SMU7_PIDController GraphicsPIDController; |
SMU7_PIDController MemoryPIDController; |
SMU7_PIDController LinkPIDController; |
uint32_t SystemFlags; |
uint32_t SmioMaskVddcVid; |
uint32_t SmioMaskVddcPhase; |
uint32_t SmioMaskVddciVid; |
uint32_t SmioMaskMvddVid; |
uint32_t VddcLevelCount; |
uint32_t VddciLevelCount; |
uint32_t MvddLevelCount; |
SMU7_Discrete_VoltageLevel VddcLevel [SMU7_MAX_LEVELS_VDDC]; |
// SMU7_Discrete_VoltageLevel VddcStandardReference [SMU7_MAX_LEVELS_VDDC]; |
SMU7_Discrete_VoltageLevel VddciLevel [SMU7_MAX_LEVELS_VDDCI]; |
SMU7_Discrete_VoltageLevel MvddLevel [SMU7_MAX_LEVELS_MVDD]; |
uint8_t GraphicsDpmLevelCount; |
uint8_t MemoryDpmLevelCount; |
uint8_t LinkLevelCount; |
uint8_t UvdLevelCount; |
uint8_t VceLevelCount; |
uint8_t AcpLevelCount; |
uint8_t SamuLevelCount; |
uint8_t MasterDeepSleepControl; |
uint32_t Reserved[5]; |
// uint32_t SamuDefaultLevel; |
SMU7_Discrete_GraphicsLevel GraphicsLevel [SMU7_MAX_LEVELS_GRAPHICS]; |
SMU7_Discrete_MemoryLevel MemoryACPILevel; |
SMU7_Discrete_MemoryLevel MemoryLevel [SMU7_MAX_LEVELS_MEMORY]; |
SMU7_Discrete_LinkLevel LinkLevel [SMU7_MAX_LEVELS_LINK]; |
SMU7_Discrete_ACPILevel ACPILevel; |
SMU7_Discrete_UvdLevel UvdLevel [SMU7_MAX_LEVELS_UVD]; |
SMU7_Discrete_ExtClkLevel VceLevel [SMU7_MAX_LEVELS_VCE]; |
SMU7_Discrete_ExtClkLevel AcpLevel [SMU7_MAX_LEVELS_ACP]; |
SMU7_Discrete_ExtClkLevel SamuLevel [SMU7_MAX_LEVELS_SAMU]; |
SMU7_Discrete_Ulv Ulv; |
uint32_t SclkStepSize; |
uint32_t Smio [SMU7_MAX_ENTRIES_SMIO]; |
uint8_t UvdBootLevel; |
uint8_t VceBootLevel; |
uint8_t AcpBootLevel; |
uint8_t SamuBootLevel; |
uint8_t UVDInterval; |
uint8_t VCEInterval; |
uint8_t ACPInterval; |
uint8_t SAMUInterval; |
uint8_t GraphicsBootLevel; |
uint8_t GraphicsVoltageChangeEnable; |
uint8_t GraphicsThermThrottleEnable; |
uint8_t GraphicsInterval; |
uint8_t VoltageInterval; |
uint8_t ThermalInterval; |
uint16_t TemperatureLimitHigh; |
uint16_t TemperatureLimitLow; |
uint8_t MemoryBootLevel; |
uint8_t MemoryVoltageChangeEnable; |
uint8_t MemoryInterval; |
uint8_t MemoryThermThrottleEnable; |
uint16_t VddcVddciDelta; |
uint16_t VoltageResponseTime; |
uint16_t PhaseResponseTime; |
uint8_t PCIeBootLinkLevel; |
uint8_t PCIeGenInterval; |
uint8_t DTEInterval; |
uint8_t DTEMode; |
uint8_t SVI2Enable; |
uint8_t VRHotGpio; |
uint8_t AcDcGpio; |
uint8_t ThermGpio; |
uint16_t PPM_PkgPwrLimit; |
uint16_t PPM_TemperatureLimit; |
uint16_t DefaultTdp; |
uint16_t TargetTdp; |
uint16_t FpsHighT; |
uint16_t FpsLowT; |
uint16_t BAPMTI_R [SMU7_DTE_ITERATIONS][SMU7_DTE_SOURCES][SMU7_DTE_SINKS]; |
uint16_t BAPMTI_RC [SMU7_DTE_ITERATIONS][SMU7_DTE_SOURCES][SMU7_DTE_SINKS]; |
uint8_t DTEAmbientTempBase; |
uint8_t DTETjOffset; |
uint8_t GpuTjMax; |
uint8_t GpuTjHyst; |
uint16_t BootVddc; |
uint16_t BootVddci; |
uint16_t BootMVdd; |
uint16_t padding; |
uint32_t BAPM_TEMP_GRADIENT; |
uint32_t LowSclkInterruptT; |
}; |
typedef struct SMU7_Discrete_DpmTable SMU7_Discrete_DpmTable; |
#define SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE 16 |
#define SMU7_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT SMU7_MAX_LEVELS_MEMORY |
struct SMU7_Discrete_MCRegisterAddress |
{ |
uint16_t s0; |
uint16_t s1; |
}; |
typedef struct SMU7_Discrete_MCRegisterAddress SMU7_Discrete_MCRegisterAddress; |
struct SMU7_Discrete_MCRegisterSet |
{ |
uint32_t value[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE]; |
}; |
typedef struct SMU7_Discrete_MCRegisterSet SMU7_Discrete_MCRegisterSet; |
struct SMU7_Discrete_MCRegisters |
{ |
uint8_t last; |
uint8_t reserved[3]; |
SMU7_Discrete_MCRegisterAddress address[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE]; |
SMU7_Discrete_MCRegisterSet data[SMU7_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT]; |
}; |
typedef struct SMU7_Discrete_MCRegisters SMU7_Discrete_MCRegisters; |
struct SMU7_Discrete_PmFuses { |
// dw0-dw1 |
uint8_t BapmVddCVidHiSidd[8]; |
// dw2-dw3 |
uint8_t BapmVddCVidLoSidd[8]; |
// dw4-dw5 |
uint8_t VddCVid[8]; |
// dw6 |
uint8_t SviLoadLineEn; |
uint8_t SviLoadLineVddC; |
uint8_t SviLoadLineTrimVddC; |
uint8_t SviLoadLineOffsetVddC; |
// dw7 |
uint16_t TDC_VDDC_PkgLimit; |
uint8_t TDC_VDDC_ThrottleReleaseLimitPerc; |
uint8_t TDC_MAWt; |
// dw8 |
uint8_t TdcWaterfallCtl; |
uint8_t LPMLTemperatureMin; |
uint8_t LPMLTemperatureMax; |
uint8_t Reserved; |
// dw9-dw10 |
uint8_t BapmVddCVidHiSidd2[8]; |
// dw11-dw12 |
uint32_t Reserved6[2]; |
// dw13-dw16 |
uint8_t GnbLPML[16]; |
// dw17 |
uint8_t GnbLPMLMaxVid; |
uint8_t GnbLPMLMinVid; |
uint8_t Reserved1[2]; |
// dw18 |
uint16_t BapmVddCBaseLeakageHiSidd; |
uint16_t BapmVddCBaseLeakageLoSidd; |
}; |
typedef struct SMU7_Discrete_PmFuses SMU7_Discrete_PmFuses; |
#pragma pack(pop) |
#endif |
/drivers/video/drm/radeon/smu7_fusion.h |
---|
0,0 → 1,300 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef SMU7_FUSION_H |
#define SMU7_FUSION_H |
#include "smu7.h" |
#pragma pack(push, 1) |
#define SMU7_DTE_ITERATIONS 5 |
#define SMU7_DTE_SOURCES 5 |
#define SMU7_DTE_SINKS 3 |
#define SMU7_NUM_CPU_TES 2 |
#define SMU7_NUM_GPU_TES 1 |
#define SMU7_NUM_NON_TES 2 |
// All 'soft registers' should be uint32_t. |
struct SMU7_SoftRegisters |
{ |
uint32_t RefClockFrequency; |
uint32_t PmTimerP; |
uint32_t FeatureEnables; |
uint32_t HandshakeDisables; |
uint8_t DisplayPhy1Config; |
uint8_t DisplayPhy2Config; |
uint8_t DisplayPhy3Config; |
uint8_t DisplayPhy4Config; |
uint8_t DisplayPhy5Config; |
uint8_t DisplayPhy6Config; |
uint8_t DisplayPhy7Config; |
uint8_t DisplayPhy8Config; |
uint32_t AverageGraphicsA; |
uint32_t AverageMemoryA; |
uint32_t AverageGioA; |
uint8_t SClkDpmEnabledLevels; |
uint8_t MClkDpmEnabledLevels; |
uint8_t LClkDpmEnabledLevels; |
uint8_t PCIeDpmEnabledLevels; |
uint8_t UVDDpmEnabledLevels; |
uint8_t SAMUDpmEnabledLevels; |
uint8_t ACPDpmEnabledLevels; |
uint8_t VCEDpmEnabledLevels; |
uint32_t DRAM_LOG_ADDR_H; |
uint32_t DRAM_LOG_ADDR_L; |
uint32_t DRAM_LOG_PHY_ADDR_H; |
uint32_t DRAM_LOG_PHY_ADDR_L; |
uint32_t DRAM_LOG_BUFF_SIZE; |
uint32_t UlvEnterC; |
uint32_t UlvTime; |
uint32_t Reserved[3]; |
}; |
typedef struct SMU7_SoftRegisters SMU7_SoftRegisters; |
struct SMU7_Fusion_GraphicsLevel |
{ |
uint32_t MinVddNb; |
uint32_t SclkFrequency; |
uint8_t Vid; |
uint8_t VidOffset; |
uint16_t AT; |
uint8_t PowerThrottle; |
uint8_t GnbSlow; |
uint8_t ForceNbPs1; |
uint8_t SclkDid; |
uint8_t DisplayWatermark; |
uint8_t EnabledForActivity; |
uint8_t EnabledForThrottle; |
uint8_t UpH; |
uint8_t DownH; |
uint8_t VoltageDownH; |
uint8_t DeepSleepDivId; |
uint8_t ClkBypassCntl; |
uint32_t reserved; |
}; |
typedef struct SMU7_Fusion_GraphicsLevel SMU7_Fusion_GraphicsLevel; |
struct SMU7_Fusion_GIOLevel |
{ |
uint8_t EnabledForActivity; |
uint8_t LclkDid; |
uint8_t Vid; |
uint8_t VoltageDownH; |
uint32_t MinVddNb; |
uint16_t ResidencyCounter; |
uint8_t UpH; |
uint8_t DownH; |
uint32_t LclkFrequency; |
uint8_t ActivityLevel; |
uint8_t EnabledForThrottle; |
uint8_t ClkBypassCntl; |
uint8_t padding; |
}; |
typedef struct SMU7_Fusion_GIOLevel SMU7_Fusion_GIOLevel; |
// UVD VCLK/DCLK state (level) definition. |
struct SMU7_Fusion_UvdLevel |
{ |
uint32_t VclkFrequency; |
uint32_t DclkFrequency; |
uint16_t MinVddNb; |
uint8_t VclkDivider; |
uint8_t DclkDivider; |
uint8_t VClkBypassCntl; |
uint8_t DClkBypassCntl; |
uint8_t padding[2]; |
}; |
typedef struct SMU7_Fusion_UvdLevel SMU7_Fusion_UvdLevel; |
// Clocks for other external blocks (VCE, ACP, SAMU). |
struct SMU7_Fusion_ExtClkLevel |
{ |
uint32_t Frequency; |
uint16_t MinVoltage; |
uint8_t Divider; |
uint8_t ClkBypassCntl; |
uint32_t Reserved; |
}; |
typedef struct SMU7_Fusion_ExtClkLevel SMU7_Fusion_ExtClkLevel; |
struct SMU7_Fusion_ACPILevel |
{ |
uint32_t Flags; |
uint32_t MinVddNb; |
uint32_t SclkFrequency; |
uint8_t SclkDid; |
uint8_t GnbSlow; |
uint8_t ForceNbPs1; |
uint8_t DisplayWatermark; |
uint8_t DeepSleepDivId; |
uint8_t padding[3]; |
}; |
typedef struct SMU7_Fusion_ACPILevel SMU7_Fusion_ACPILevel; |
struct SMU7_Fusion_NbDpm |
{ |
uint8_t DpmXNbPsHi; |
uint8_t DpmXNbPsLo; |
uint8_t Dpm0PgNbPsHi; |
uint8_t Dpm0PgNbPsLo; |
uint8_t EnablePsi1; |
uint8_t SkipDPM0; |
uint8_t SkipPG; |
uint8_t Hysteresis; |
uint8_t EnableDpmPstatePoll; |
uint8_t padding[3]; |
}; |
typedef struct SMU7_Fusion_NbDpm SMU7_Fusion_NbDpm; |
struct SMU7_Fusion_StateInfo |
{ |
uint32_t SclkFrequency; |
uint32_t LclkFrequency; |
uint32_t VclkFrequency; |
uint32_t DclkFrequency; |
uint32_t SamclkFrequency; |
uint32_t AclkFrequency; |
uint32_t EclkFrequency; |
uint8_t DisplayWatermark; |
uint8_t McArbIndex; |
int8_t SclkIndex; |
int8_t MclkIndex; |
}; |
typedef struct SMU7_Fusion_StateInfo SMU7_Fusion_StateInfo; |
struct SMU7_Fusion_DpmTable |
{ |
uint32_t SystemFlags; |
SMU7_PIDController GraphicsPIDController; |
SMU7_PIDController GioPIDController; |
uint8_t GraphicsDpmLevelCount; |
uint8_t GIOLevelCount; |
uint8_t UvdLevelCount; |
uint8_t VceLevelCount; |
uint8_t AcpLevelCount; |
uint8_t SamuLevelCount; |
uint16_t FpsHighT; |
SMU7_Fusion_GraphicsLevel GraphicsLevel [SMU__NUM_SCLK_DPM_STATE]; |
SMU7_Fusion_ACPILevel ACPILevel; |
SMU7_Fusion_UvdLevel UvdLevel [SMU7_MAX_LEVELS_UVD]; |
SMU7_Fusion_ExtClkLevel VceLevel [SMU7_MAX_LEVELS_VCE]; |
SMU7_Fusion_ExtClkLevel AcpLevel [SMU7_MAX_LEVELS_ACP]; |
SMU7_Fusion_ExtClkLevel SamuLevel [SMU7_MAX_LEVELS_SAMU]; |
uint8_t UvdBootLevel; |
uint8_t VceBootLevel; |
uint8_t AcpBootLevel; |
uint8_t SamuBootLevel; |
uint8_t UVDInterval; |
uint8_t VCEInterval; |
uint8_t ACPInterval; |
uint8_t SAMUInterval; |
uint8_t GraphicsBootLevel; |
uint8_t GraphicsInterval; |
uint8_t GraphicsThermThrottleEnable; |
uint8_t GraphicsVoltageChangeEnable; |
uint8_t GraphicsClkSlowEnable; |
uint8_t GraphicsClkSlowDivider; |
uint16_t FpsLowT; |
uint32_t DisplayCac; |
uint32_t LowSclkInterruptT; |
uint32_t DRAM_LOG_ADDR_H; |
uint32_t DRAM_LOG_ADDR_L; |
uint32_t DRAM_LOG_PHY_ADDR_H; |
uint32_t DRAM_LOG_PHY_ADDR_L; |
uint32_t DRAM_LOG_BUFF_SIZE; |
}; |
struct SMU7_Fusion_GIODpmTable |
{ |
SMU7_Fusion_GIOLevel GIOLevel [SMU7_MAX_LEVELS_GIO]; |
SMU7_PIDController GioPIDController; |
uint32_t GIOLevelCount; |
uint8_t Enable; |
uint8_t GIOVoltageChangeEnable; |
uint8_t GIOBootLevel; |
uint8_t padding; |
uint8_t padding1[2]; |
uint8_t TargetState; |
uint8_t CurrenttState; |
uint8_t ThrottleOnHtc; |
uint8_t ThermThrottleStatus; |
uint8_t ThermThrottleTempSelect; |
uint8_t ThermThrottleEnable; |
uint16_t TemperatureLimitHigh; |
uint16_t TemperatureLimitLow; |
}; |
typedef struct SMU7_Fusion_DpmTable SMU7_Fusion_DpmTable; |
typedef struct SMU7_Fusion_GIODpmTable SMU7_Fusion_GIODpmTable; |
#pragma pack(pop) |
#endif |
/drivers/video/drm/radeon/sumo_dpm.c |
---|
0,0 → 1,1912 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "sumod.h" |
#include "r600_dpm.h" |
#include "cypress_dpm.h" |
#include "sumo_dpm.h" |
#include <linux/seq_file.h> |
#define SUMO_MAX_DEEPSLEEP_DIVIDER_ID 5 |
#define SUMO_MINIMUM_ENGINE_CLOCK 800 |
#define BOOST_DPM_LEVEL 7 |
static const u32 sumo_utc[SUMO_PM_NUMBER_OF_TC] = |
{ |
SUMO_UTC_DFLT_00, |
SUMO_UTC_DFLT_01, |
SUMO_UTC_DFLT_02, |
SUMO_UTC_DFLT_03, |
SUMO_UTC_DFLT_04, |
SUMO_UTC_DFLT_05, |
SUMO_UTC_DFLT_06, |
SUMO_UTC_DFLT_07, |
SUMO_UTC_DFLT_08, |
SUMO_UTC_DFLT_09, |
SUMO_UTC_DFLT_10, |
SUMO_UTC_DFLT_11, |
SUMO_UTC_DFLT_12, |
SUMO_UTC_DFLT_13, |
SUMO_UTC_DFLT_14, |
}; |
static const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] = |
{ |
SUMO_DTC_DFLT_00, |
SUMO_DTC_DFLT_01, |
SUMO_DTC_DFLT_02, |
SUMO_DTC_DFLT_03, |
SUMO_DTC_DFLT_04, |
SUMO_DTC_DFLT_05, |
SUMO_DTC_DFLT_06, |
SUMO_DTC_DFLT_07, |
SUMO_DTC_DFLT_08, |
SUMO_DTC_DFLT_09, |
SUMO_DTC_DFLT_10, |
SUMO_DTC_DFLT_11, |
SUMO_DTC_DFLT_12, |
SUMO_DTC_DFLT_13, |
SUMO_DTC_DFLT_14, |
}; |
static struct sumo_ps *sumo_get_ps(struct radeon_ps *rps) |
{ |
struct sumo_ps *ps = rps->ps_priv; |
return ps; |
} |
struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
static void sumo_gfx_clockgating_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); |
else { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); |
RREG32(GB_ADDR_CONFIG); |
} |
} |
#define CGCG_CGTT_LOCAL0_MASK 0xE5BFFFFF |
#define CGCG_CGTT_LOCAL1_MASK 0xEFFF07FF |
static void sumo_mg_clockgating_enable(struct radeon_device *rdev, bool enable) |
{ |
u32 local0; |
u32 local1; |
local0 = RREG32(CG_CGTT_LOCAL_0); |
local1 = RREG32(CG_CGTT_LOCAL_1); |
if (enable) { |
WREG32(CG_CGTT_LOCAL_0, (0 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) ); |
WREG32(CG_CGTT_LOCAL_1, (0 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) ); |
} else { |
WREG32(CG_CGTT_LOCAL_0, (0xFFFFFFFF & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) ); |
WREG32(CG_CGTT_LOCAL_1, (0xFFFFCFFF & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) ); |
} |
} |
static void sumo_program_git(struct radeon_device *rdev) |
{ |
u32 p, u; |
u32 xclk = radeon_get_xclk(rdev); |
r600_calculate_u_and_p(SUMO_GICST_DFLT, |
xclk, 16, &p, &u); |
WREG32_P(CG_GIT, CG_GICST(p), ~CG_GICST_MASK); |
} |
static void sumo_program_grsd(struct radeon_device *rdev) |
{ |
u32 p, u; |
u32 xclk = radeon_get_xclk(rdev); |
u32 grs = 256 * 25 / 100; |
r600_calculate_u_and_p(1, xclk, 14, &p, &u); |
WREG32(CG_GCOOR, PHC(grs) | SDC(p) | SU(u)); |
} |
void sumo_gfx_clockgating_initialize(struct radeon_device *rdev) |
{ |
sumo_program_git(rdev); |
sumo_program_grsd(rdev); |
} |
static void sumo_gfx_powergating_initialize(struct radeon_device *rdev) |
{ |
u32 rcu_pwr_gating_cntl; |
u32 p, u; |
u32 p_c, p_p, d_p; |
u32 r_t, i_t; |
u32 xclk = radeon_get_xclk(rdev); |
if (rdev->family == CHIP_PALM) { |
p_c = 4; |
d_p = 10; |
r_t = 10; |
i_t = 4; |
p_p = 50 + 1000/200 + 6 * 32; |
} else { |
p_c = 16; |
d_p = 50; |
r_t = 50; |
i_t = 50; |
p_p = 113; |
} |
WREG32(CG_SCRATCH2, 0x01B60A17); |
r600_calculate_u_and_p(SUMO_GFXPOWERGATINGT_DFLT, |
xclk, 16, &p, &u); |
WREG32_P(CG_PWR_GATING_CNTL, PGP(p) | PGU(u), |
~(PGP_MASK | PGU_MASK)); |
r600_calculate_u_and_p(SUMO_VOLTAGEDROPT_DFLT, |
xclk, 16, &p, &u); |
WREG32_P(CG_CG_VOLTAGE_CNTL, PGP(p) | PGU(u), |
~(PGP_MASK | PGU_MASK)); |
if (rdev->family == CHIP_PALM) { |
WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x10103210); |
WREG32_RCU(RCU_PWR_GATING_SEQ1, 0x10101010); |
} else { |
WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x76543210); |
WREG32_RCU(RCU_PWR_GATING_SEQ1, 0xFEDCBA98); |
} |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL); |
rcu_pwr_gating_cntl &= |
~(RSVD_MASK | PCV_MASK | PGS_MASK); |
rcu_pwr_gating_cntl |= PCV(p_c) | PGS(1) | PWR_GATING_EN; |
if (rdev->family == CHIP_PALM) { |
rcu_pwr_gating_cntl &= ~PCP_MASK; |
rcu_pwr_gating_cntl |= PCP(0x77); |
} |
WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl); |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2); |
rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK); |
rcu_pwr_gating_cntl |= MPPU(p_p) | MPPD(50); |
WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl); |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3); |
rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK); |
rcu_pwr_gating_cntl |= DPPU(d_p) | DPPD(50); |
WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl); |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_4); |
rcu_pwr_gating_cntl &= ~(RT_MASK | IT_MASK); |
rcu_pwr_gating_cntl |= RT(r_t) | IT(i_t); |
WREG32_RCU(RCU_PWR_GATING_CNTL_4, rcu_pwr_gating_cntl); |
if (rdev->family == CHIP_PALM) |
WREG32_RCU(RCU_PWR_GATING_CNTL_5, 0xA02); |
sumo_smu_pg_init(rdev); |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL); |
rcu_pwr_gating_cntl &= |
~(RSVD_MASK | PCV_MASK | PGS_MASK); |
rcu_pwr_gating_cntl |= PCV(p_c) | PGS(4) | PWR_GATING_EN; |
if (rdev->family == CHIP_PALM) { |
rcu_pwr_gating_cntl &= ~PCP_MASK; |
rcu_pwr_gating_cntl |= PCP(0x77); |
} |
WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl); |
if (rdev->family == CHIP_PALM) { |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2); |
rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK); |
rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50); |
WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl); |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3); |
rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK); |
rcu_pwr_gating_cntl |= DPPU(16) | DPPD(50); |
WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl); |
} |
sumo_smu_pg_init(rdev); |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL); |
rcu_pwr_gating_cntl &= |
~(RSVD_MASK | PCV_MASK | PGS_MASK); |
rcu_pwr_gating_cntl |= PGS(5) | PWR_GATING_EN; |
if (rdev->family == CHIP_PALM) { |
rcu_pwr_gating_cntl |= PCV(4); |
rcu_pwr_gating_cntl &= ~PCP_MASK; |
rcu_pwr_gating_cntl |= PCP(0x77); |
} else |
rcu_pwr_gating_cntl |= PCV(11); |
WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl); |
if (rdev->family == CHIP_PALM) { |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2); |
rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK); |
rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50); |
WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl); |
rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3); |
rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK); |
rcu_pwr_gating_cntl |= DPPU(22) | DPPD(50); |
WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl); |
} |
sumo_smu_pg_init(rdev); |
} |
static void sumo_gfx_powergating_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(CG_PWR_GATING_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN); |
else { |
WREG32_P(CG_PWR_GATING_CNTL, 0, ~DYN_PWR_DOWN_EN); |
RREG32(GB_ADDR_CONFIG); |
} |
} |
static int sumo_enable_clock_power_gating(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
if (pi->enable_gfx_clock_gating) |
sumo_gfx_clockgating_initialize(rdev); |
if (pi->enable_gfx_power_gating) |
sumo_gfx_powergating_initialize(rdev); |
if (pi->enable_mg_clock_gating) |
sumo_mg_clockgating_enable(rdev, true); |
if (pi->enable_gfx_clock_gating) |
sumo_gfx_clockgating_enable(rdev, true); |
if (pi->enable_gfx_power_gating) |
sumo_gfx_powergating_enable(rdev, true); |
return 0; |
} |
static void sumo_disable_clock_power_gating(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
if (pi->enable_gfx_clock_gating) |
sumo_gfx_clockgating_enable(rdev, false); |
if (pi->enable_gfx_power_gating) |
sumo_gfx_powergating_enable(rdev, false); |
if (pi->enable_mg_clock_gating) |
sumo_mg_clockgating_enable(rdev, false); |
} |
static void sumo_calculate_bsp(struct radeon_device *rdev, |
u32 high_clk) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 xclk = radeon_get_xclk(rdev); |
pi->pasi = 65535 * 100 / high_clk; |
pi->asi = 65535 * 100 / high_clk; |
r600_calculate_u_and_p(pi->asi, |
xclk, 16, &pi->bsp, &pi->bsu); |
r600_calculate_u_and_p(pi->pasi, |
xclk, 16, &pi->pbsp, &pi->pbsu); |
pi->dsp = BSP(pi->bsp) | BSU(pi->bsu); |
pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu); |
} |
static void sumo_init_bsp(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
WREG32(CG_BSP_0, pi->psp); |
} |
static void sumo_program_bsp(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct sumo_ps *ps = sumo_get_ps(rps); |
u32 i; |
u32 highest_engine_clock = ps->levels[ps->num_levels - 1].sclk; |
if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) |
highest_engine_clock = pi->boost_pl.sclk; |
sumo_calculate_bsp(rdev, highest_engine_clock); |
for (i = 0; i < ps->num_levels - 1; i++) |
WREG32(CG_BSP_0 + (i * 4), pi->dsp); |
WREG32(CG_BSP_0 + (i * 4), pi->psp); |
if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) |
WREG32(CG_BSP_0 + (BOOST_DPM_LEVEL * 4), pi->psp); |
} |
static void sumo_write_at(struct radeon_device *rdev, |
u32 index, u32 value) |
{ |
if (index == 0) |
WREG32(CG_AT_0, value); |
else if (index == 1) |
WREG32(CG_AT_1, value); |
else if (index == 2) |
WREG32(CG_AT_2, value); |
else if (index == 3) |
WREG32(CG_AT_3, value); |
else if (index == 4) |
WREG32(CG_AT_4, value); |
else if (index == 5) |
WREG32(CG_AT_5, value); |
else if (index == 6) |
WREG32(CG_AT_6, value); |
else if (index == 7) |
WREG32(CG_AT_7, value); |
} |
static void sumo_program_at(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct sumo_ps *ps = sumo_get_ps(rps); |
u32 asi; |
u32 i; |
u32 m_a; |
u32 a_t; |
u32 r[SUMO_MAX_HARDWARE_POWERLEVELS]; |
u32 l[SUMO_MAX_HARDWARE_POWERLEVELS]; |
r[0] = SUMO_R_DFLT0; |
r[1] = SUMO_R_DFLT1; |
r[2] = SUMO_R_DFLT2; |
r[3] = SUMO_R_DFLT3; |
r[4] = SUMO_R_DFLT4; |
l[0] = SUMO_L_DFLT0; |
l[1] = SUMO_L_DFLT1; |
l[2] = SUMO_L_DFLT2; |
l[3] = SUMO_L_DFLT3; |
l[4] = SUMO_L_DFLT4; |
for (i = 0; i < ps->num_levels; i++) { |
asi = (i == ps->num_levels - 1) ? pi->pasi : pi->asi; |
m_a = asi * ps->levels[i].sclk / 100; |
a_t = CG_R(m_a * r[i] / 100) | CG_L(m_a * l[i] / 100); |
sumo_write_at(rdev, i, a_t); |
} |
if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) { |
asi = pi->pasi; |
m_a = asi * pi->boost_pl.sclk / 100; |
a_t = CG_R(m_a * r[ps->num_levels - 1] / 100) | |
CG_L(m_a * l[ps->num_levels - 1] / 100); |
sumo_write_at(rdev, BOOST_DPM_LEVEL, a_t); |
} |
} |
static void sumo_program_tp(struct radeon_device *rdev) |
{ |
int i; |
enum r600_td td = R600_TD_DFLT; |
for (i = 0; i < SUMO_PM_NUMBER_OF_TC; i++) { |
WREG32_P(CG_FFCT_0 + (i * 4), UTC_0(sumo_utc[i]), ~UTC_0_MASK); |
WREG32_P(CG_FFCT_0 + (i * 4), DTC_0(sumo_dtc[i]), ~DTC_0_MASK); |
} |
if (td == R600_TD_AUTO) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL); |
else |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL); |
if (td == R600_TD_UP) |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE); |
if (td == R600_TD_DOWN) |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE); |
} |
void sumo_program_vc(struct radeon_device *rdev, u32 vrc) |
{ |
WREG32(CG_FTV, vrc); |
} |
void sumo_clear_vc(struct radeon_device *rdev) |
{ |
WREG32(CG_FTV, 0); |
} |
void sumo_program_sstp(struct radeon_device *rdev) |
{ |
u32 p, u; |
u32 xclk = radeon_get_xclk(rdev); |
r600_calculate_u_and_p(SUMO_SST_DFLT, |
xclk, 16, &p, &u); |
WREG32(CG_SSP, SSTU(u) | SST(p)); |
} |
static void sumo_set_divider_value(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
u32 reg_index = index / 4; |
u32 field_index = index % 4; |
if (field_index == 0) |
WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), |
SCLK_FSTATE_0_DIV(divider), ~SCLK_FSTATE_0_DIV_MASK); |
else if (field_index == 1) |
WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), |
SCLK_FSTATE_1_DIV(divider), ~SCLK_FSTATE_1_DIV_MASK); |
else if (field_index == 2) |
WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), |
SCLK_FSTATE_2_DIV(divider), ~SCLK_FSTATE_2_DIV_MASK); |
else if (field_index == 3) |
WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), |
SCLK_FSTATE_3_DIV(divider), ~SCLK_FSTATE_3_DIV_MASK); |
} |
static void sumo_set_ds_dividers(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
if (pi->enable_sclk_ds) { |
u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_6); |
dpm_ctrl &= ~(0x7 << (index * 3)); |
dpm_ctrl |= (divider << (index * 3)); |
WREG32(CG_SCLK_DPM_CTRL_6, dpm_ctrl); |
} |
} |
static void sumo_set_ss_dividers(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
if (pi->enable_sclk_ds) { |
u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_11); |
dpm_ctrl &= ~(0x7 << (index * 3)); |
dpm_ctrl |= (divider << (index * 3)); |
WREG32(CG_SCLK_DPM_CTRL_11, dpm_ctrl); |
} |
} |
static void sumo_set_vid(struct radeon_device *rdev, u32 index, u32 vid) |
{ |
u32 voltage_cntl = RREG32(CG_DPM_VOLTAGE_CNTL); |
voltage_cntl &= ~(DPM_STATE0_LEVEL_MASK << (index * 2)); |
voltage_cntl |= (vid << (DPM_STATE0_LEVEL_SHIFT + index * 2)); |
WREG32(CG_DPM_VOLTAGE_CNTL, voltage_cntl); |
} |
static void sumo_set_allos_gnb_slow(struct radeon_device *rdev, u32 index, u32 gnb_slow) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 temp = gnb_slow; |
u32 cg_sclk_dpm_ctrl_3; |
if (pi->driver_nbps_policy_disable) |
temp = 1; |
cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3); |
cg_sclk_dpm_ctrl_3 &= ~(GNB_SLOW_FSTATE_0_MASK << index); |
cg_sclk_dpm_ctrl_3 |= (temp << (GNB_SLOW_FSTATE_0_SHIFT + index)); |
WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3); |
} |
static void sumo_program_power_level(struct radeon_device *rdev, |
struct sumo_pl *pl, u32 index) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
int ret; |
struct atom_clock_dividers dividers; |
u32 ds_en = RREG32(DEEP_SLEEP_CNTL) & ENABLE_DS; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
pl->sclk, false, ÷rs); |
if (ret) |
return; |
sumo_set_divider_value(rdev, index, dividers.post_div); |
sumo_set_vid(rdev, index, pl->vddc_index); |
if (pl->ss_divider_index == 0 || pl->ds_divider_index == 0) { |
if (ds_en) |
WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS); |
} else { |
sumo_set_ss_dividers(rdev, index, pl->ss_divider_index); |
sumo_set_ds_dividers(rdev, index, pl->ds_divider_index); |
if (!ds_en) |
WREG32_P(DEEP_SLEEP_CNTL, ENABLE_DS, ~ENABLE_DS); |
} |
sumo_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow); |
if (pi->enable_boost) |
sumo_set_tdp_limit(rdev, index, pl->sclk_dpm_tdp_limit); |
} |
static void sumo_power_level_enable(struct radeon_device *rdev, u32 index, bool enable) |
{ |
u32 reg_index = index / 4; |
u32 field_index = index % 4; |
if (field_index == 0) |
WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), |
enable ? SCLK_FSTATE_0_VLD : 0, ~SCLK_FSTATE_0_VLD); |
else if (field_index == 1) |
WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), |
enable ? SCLK_FSTATE_1_VLD : 0, ~SCLK_FSTATE_1_VLD); |
else if (field_index == 2) |
WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), |
enable ? SCLK_FSTATE_2_VLD : 0, ~SCLK_FSTATE_2_VLD); |
else if (field_index == 3) |
WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), |
enable ? SCLK_FSTATE_3_VLD : 0, ~SCLK_FSTATE_3_VLD); |
} |
static bool sumo_dpm_enabled(struct radeon_device *rdev) |
{ |
if (RREG32(CG_SCLK_DPM_CTRL_3) & DPM_SCLK_ENABLE) |
return true; |
else |
return false; |
} |
static void sumo_start_dpm(struct radeon_device *rdev) |
{ |
WREG32_P(CG_SCLK_DPM_CTRL_3, DPM_SCLK_ENABLE, ~DPM_SCLK_ENABLE); |
} |
static void sumo_stop_dpm(struct radeon_device *rdev) |
{ |
WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~DPM_SCLK_ENABLE); |
} |
static void sumo_set_forced_mode(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE_EN, ~FORCE_SCLK_STATE_EN); |
else |
WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_SCLK_STATE_EN); |
} |
static void sumo_set_forced_mode_enabled(struct radeon_device *rdev) |
{ |
int i; |
sumo_set_forced_mode(rdev, true); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(CG_SCLK_STATUS) & SCLK_OVERCLK_DETECT) |
break; |
udelay(1); |
} |
} |
static void sumo_wait_for_level_0(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) == 0) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) == 0) |
break; |
udelay(1); |
} |
} |
static void sumo_set_forced_mode_disabled(struct radeon_device *rdev) |
{ |
sumo_set_forced_mode(rdev, false); |
} |
static void sumo_enable_power_level_0(struct radeon_device *rdev) |
{ |
sumo_power_level_enable(rdev, 0, true); |
} |
static void sumo_patch_boost_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct sumo_ps *new_ps = sumo_get_ps(rps); |
if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) { |
pi->boost_pl = new_ps->levels[new_ps->num_levels - 1]; |
pi->boost_pl.sclk = pi->sys_info.boost_sclk; |
pi->boost_pl.vddc_index = pi->sys_info.boost_vid_2bit; |
pi->boost_pl.sclk_dpm_tdp_limit = pi->sys_info.sclk_dpm_tdp_limit_boost; |
} |
} |
static void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct sumo_ps *new_ps = sumo_get_ps(new_rps); |
struct sumo_ps *old_ps = sumo_get_ps(old_rps); |
u32 nbps1_old = 0; |
u32 nbps1_new = 0; |
if (old_ps != NULL) |
nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0; |
nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0; |
if (nbps1_old == 1 && nbps1_new == 0) |
sumo_smu_notify_alt_vddnb_change(rdev, 0, 0); |
} |
static void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct sumo_ps *new_ps = sumo_get_ps(new_rps); |
struct sumo_ps *old_ps = sumo_get_ps(old_rps); |
u32 nbps1_old = 0; |
u32 nbps1_new = 0; |
if (old_ps != NULL) |
nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0; |
nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0; |
if (nbps1_old == 0 && nbps1_new == 1) |
sumo_smu_notify_alt_vddnb_change(rdev, 1, 1); |
} |
static void sumo_enable_boost(struct radeon_device *rdev, |
struct radeon_ps *rps, |
bool enable) |
{ |
struct sumo_ps *new_ps = sumo_get_ps(rps); |
if (enable) { |
if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) |
sumo_boost_state_enable(rdev, true); |
} else |
sumo_boost_state_enable(rdev, false); |
} |
static void sumo_set_forced_level(struct radeon_device *rdev, u32 index) |
{ |
WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE(index), ~FORCE_SCLK_STATE_MASK); |
} |
static void sumo_set_forced_level_0(struct radeon_device *rdev) |
{ |
sumo_set_forced_level(rdev, 0); |
} |
static void sumo_program_wl(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct sumo_ps *new_ps = sumo_get_ps(rps); |
u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4); |
dpm_ctrl4 &= 0xFFFFFF00; |
dpm_ctrl4 |= (1 << (new_ps->num_levels - 1)); |
if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) |
dpm_ctrl4 |= (1 << BOOST_DPM_LEVEL); |
WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4); |
} |
static void sumo_program_power_levels_0_to_n(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct sumo_ps *new_ps = sumo_get_ps(new_rps); |
struct sumo_ps *old_ps = sumo_get_ps(old_rps); |
u32 i; |
u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels; |
for (i = 0; i < new_ps->num_levels; i++) { |
sumo_program_power_level(rdev, &new_ps->levels[i], i); |
sumo_power_level_enable(rdev, i, true); |
} |
for (i = new_ps->num_levels; i < n_current_state_levels; i++) |
sumo_power_level_enable(rdev, i, false); |
if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) |
sumo_program_power_level(rdev, &pi->boost_pl, BOOST_DPM_LEVEL); |
} |
static void sumo_enable_acpi_pm(struct radeon_device *rdev) |
{ |
WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN); |
} |
static void sumo_program_power_level_enter_state(struct radeon_device *rdev) |
{ |
WREG32_P(CG_SCLK_DPM_CTRL_5, SCLK_FSTATE_BOOTUP(0), ~SCLK_FSTATE_BOOTUP_MASK); |
} |
static void sumo_program_acpi_power_level(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct atom_clock_dividers dividers; |
int ret; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
pi->acpi_pl.sclk, |
false, ÷rs); |
if (ret) |
return; |
WREG32_P(CG_ACPI_CNTL, SCLK_ACPI_DIV(dividers.post_div), ~SCLK_ACPI_DIV_MASK); |
WREG32_P(CG_ACPI_VOLTAGE_CNTL, 0, ~ACPI_VOLTAGE_EN); |
} |
static void sumo_program_bootup_state(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4); |
u32 i; |
sumo_program_power_level(rdev, &pi->boot_pl, 0); |
dpm_ctrl4 &= 0xFFFFFF00; |
WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4); |
for (i = 1; i < 8; i++) |
sumo_power_level_enable(rdev, i, false); |
} |
static void sumo_setup_uvd_clocks(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
if (pi->enable_gfx_power_gating) { |
sumo_gfx_powergating_enable(rdev, false); |
} |
radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk); |
if (pi->enable_gfx_power_gating) { |
if (!pi->disable_gfx_power_gating_in_uvd || |
!r600_is_uvd_state(new_rps->class, new_rps->class2)) |
sumo_gfx_powergating_enable(rdev, true); |
} |
} |
static void sumo_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct sumo_ps *new_ps = sumo_get_ps(new_rps); |
struct sumo_ps *current_ps = sumo_get_ps(old_rps); |
if ((new_rps->vclk == old_rps->vclk) && |
(new_rps->dclk == old_rps->dclk)) |
return; |
if (new_ps->levels[new_ps->num_levels - 1].sclk >= |
current_ps->levels[current_ps->num_levels - 1].sclk) |
return; |
sumo_setup_uvd_clocks(rdev, new_rps, old_rps); |
} |
static void sumo_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct sumo_ps *new_ps = sumo_get_ps(new_rps); |
struct sumo_ps *current_ps = sumo_get_ps(old_rps); |
if ((new_rps->vclk == old_rps->vclk) && |
(new_rps->dclk == old_rps->dclk)) |
return; |
if (new_ps->levels[new_ps->num_levels - 1].sclk < |
current_ps->levels[current_ps->num_levels - 1].sclk) |
return; |
sumo_setup_uvd_clocks(rdev, new_rps, old_rps); |
} |
void sumo_take_smu_control(struct radeon_device *rdev, bool enable) |
{ |
/* This bit selects who handles display phy powergating. |
* Clear the bit to let atom handle it. |
* Set it to let the driver handle it. |
* For now we just let atom handle it. |
*/ |
#if 0 |
u32 v = RREG32(DOUT_SCRATCH3); |
if (enable) |
v |= 0x4; |
else |
v &= 0xFFFFFFFB; |
WREG32(DOUT_SCRATCH3, v); |
#endif |
} |
static void sumo_enable_sclk_ds(struct radeon_device *rdev, bool enable) |
{ |
if (enable) { |
u32 deep_sleep_cntl = RREG32(DEEP_SLEEP_CNTL); |
u32 deep_sleep_cntl2 = RREG32(DEEP_SLEEP_CNTL2); |
u32 t = 1; |
deep_sleep_cntl &= ~R_DIS; |
deep_sleep_cntl &= ~HS_MASK; |
deep_sleep_cntl |= HS(t > 4095 ? 4095 : t); |
deep_sleep_cntl2 |= LB_UFP_EN; |
deep_sleep_cntl2 &= INOUT_C_MASK; |
deep_sleep_cntl2 |= INOUT_C(0xf); |
WREG32(DEEP_SLEEP_CNTL2, deep_sleep_cntl2); |
WREG32(DEEP_SLEEP_CNTL, deep_sleep_cntl); |
} else |
WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS); |
} |
static void sumo_program_bootup_at(struct radeon_device *rdev) |
{ |
WREG32_P(CG_AT_0, CG_R(0xffff), ~CG_R_MASK); |
WREG32_P(CG_AT_0, CG_L(0), ~CG_L_MASK); |
} |
static void sumo_reset_am(struct radeon_device *rdev) |
{ |
WREG32_P(SCLK_PWRMGT_CNTL, FIR_RESET, ~FIR_RESET); |
} |
static void sumo_start_am(struct radeon_device *rdev) |
{ |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_RESET); |
} |
static void sumo_program_ttp(struct radeon_device *rdev) |
{ |
u32 xclk = radeon_get_xclk(rdev); |
u32 p, u; |
u32 cg_sclk_dpm_ctrl_5 = RREG32(CG_SCLK_DPM_CTRL_5); |
r600_calculate_u_and_p(1000, |
xclk, 16, &p, &u); |
cg_sclk_dpm_ctrl_5 &= ~(TT_TP_MASK | TT_TU_MASK); |
cg_sclk_dpm_ctrl_5 |= TT_TP(p) | TT_TU(u); |
WREG32(CG_SCLK_DPM_CTRL_5, cg_sclk_dpm_ctrl_5); |
} |
static void sumo_program_ttt(struct radeon_device *rdev) |
{ |
u32 cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3); |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
cg_sclk_dpm_ctrl_3 &= ~(GNB_TT_MASK | GNB_THERMTHRO_MASK); |
cg_sclk_dpm_ctrl_3 |= GNB_TT(pi->thermal_auto_throttling + 49); |
WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3); |
} |
static void sumo_enable_voltage_scaling(struct radeon_device *rdev, bool enable) |
{ |
if (enable) { |
WREG32_P(CG_DPM_VOLTAGE_CNTL, DPM_VOLTAGE_EN, ~DPM_VOLTAGE_EN); |
WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~CG_VOLTAGE_EN); |
} else { |
WREG32_P(CG_CG_VOLTAGE_CNTL, CG_VOLTAGE_EN, ~CG_VOLTAGE_EN); |
WREG32_P(CG_DPM_VOLTAGE_CNTL, 0, ~DPM_VOLTAGE_EN); |
} |
} |
static void sumo_override_cnb_thermal_events(struct radeon_device *rdev) |
{ |
WREG32_P(CG_SCLK_DPM_CTRL_3, CNB_THERMTHRO_MASK_SCLK, |
~CNB_THERMTHRO_MASK_SCLK); |
} |
static void sumo_program_dc_hto(struct radeon_device *rdev) |
{ |
u32 cg_sclk_dpm_ctrl_4 = RREG32(CG_SCLK_DPM_CTRL_4); |
u32 p, u; |
u32 xclk = radeon_get_xclk(rdev); |
r600_calculate_u_and_p(100000, |
xclk, 14, &p, &u); |
cg_sclk_dpm_ctrl_4 &= ~(DC_HDC_MASK | DC_HU_MASK); |
cg_sclk_dpm_ctrl_4 |= DC_HDC(p) | DC_HU(u); |
WREG32(CG_SCLK_DPM_CTRL_4, cg_sclk_dpm_ctrl_4); |
} |
static void sumo_force_nbp_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct sumo_ps *new_ps = sumo_get_ps(rps); |
if (!pi->driver_nbps_policy_disable) { |
if (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) |
WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_NB_PSTATE_1, ~FORCE_NB_PSTATE_1); |
else |
WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_NB_PSTATE_1); |
} |
} |
u32 sumo_get_sleep_divider_from_id(u32 id) |
{ |
return 1 << id; |
} |
u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev, |
u32 sclk, |
u32 min_sclk_in_sr) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 i; |
u32 temp; |
u32 min = (min_sclk_in_sr > SUMO_MINIMUM_ENGINE_CLOCK) ? |
min_sclk_in_sr : SUMO_MINIMUM_ENGINE_CLOCK; |
if (sclk < min) |
return 0; |
if (!pi->enable_sclk_ds) |
return 0; |
for (i = SUMO_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) { |
temp = sclk / sumo_get_sleep_divider_from_id(i); |
if (temp >= min || i == 0) |
break; |
} |
return i; |
} |
static u32 sumo_get_valid_engine_clock(struct radeon_device *rdev, |
u32 lower_limit) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 i; |
for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) { |
if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit) |
return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency; |
} |
return pi->sys_info.sclk_voltage_mapping_table.entries[pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1].sclk_frequency; |
} |
static void sumo_patch_thermal_state(struct radeon_device *rdev, |
struct sumo_ps *ps, |
struct sumo_ps *current_ps) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ |
u32 current_vddc; |
u32 current_sclk; |
u32 current_index = 0; |
if (current_ps) { |
current_vddc = current_ps->levels[current_index].vddc_index; |
current_sclk = current_ps->levels[current_index].sclk; |
} else { |
current_vddc = pi->boot_pl.vddc_index; |
current_sclk = pi->boot_pl.sclk; |
} |
ps->levels[0].vddc_index = current_vddc; |
if (ps->levels[0].sclk > current_sclk) |
ps->levels[0].sclk = current_sclk; |
ps->levels[0].ss_divider_index = |
sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr); |
ps->levels[0].ds_divider_index = |
sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, SUMO_MINIMUM_ENGINE_CLOCK); |
if (ps->levels[0].ds_divider_index > ps->levels[0].ss_divider_index + 1) |
ps->levels[0].ds_divider_index = ps->levels[0].ss_divider_index + 1; |
if (ps->levels[0].ss_divider_index == ps->levels[0].ds_divider_index) { |
if (ps->levels[0].ss_divider_index > 1) |
ps->levels[0].ss_divider_index = ps->levels[0].ss_divider_index - 1; |
} |
if (ps->levels[0].ss_divider_index == 0) |
ps->levels[0].ds_divider_index = 0; |
if (ps->levels[0].ds_divider_index == 0) |
ps->levels[0].ss_divider_index = 0; |
} |
static void sumo_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct sumo_ps *ps = sumo_get_ps(new_rps); |
struct sumo_ps *current_ps = sumo_get_ps(old_rps); |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 min_voltage = 0; /* ??? */ |
u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */ |
u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ |
u32 i; |
if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) |
return sumo_patch_thermal_state(rdev, ps, current_ps); |
if (pi->enable_boost) { |
if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) |
ps->flags |= SUMO_POWERSTATE_FLAGS_BOOST_STATE; |
} |
if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) || |
(new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) || |
(new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)) |
ps->flags |= SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE; |
for (i = 0; i < ps->num_levels; i++) { |
if (ps->levels[i].vddc_index < min_voltage) |
ps->levels[i].vddc_index = min_voltage; |
if (ps->levels[i].sclk < min_sclk) |
ps->levels[i].sclk = |
sumo_get_valid_engine_clock(rdev, min_sclk); |
ps->levels[i].ss_divider_index = |
sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr); |
ps->levels[i].ds_divider_index = |
sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, SUMO_MINIMUM_ENGINE_CLOCK); |
if (ps->levels[i].ds_divider_index > ps->levels[i].ss_divider_index + 1) |
ps->levels[i].ds_divider_index = ps->levels[i].ss_divider_index + 1; |
if (ps->levels[i].ss_divider_index == ps->levels[i].ds_divider_index) { |
if (ps->levels[i].ss_divider_index > 1) |
ps->levels[i].ss_divider_index = ps->levels[i].ss_divider_index - 1; |
} |
if (ps->levels[i].ss_divider_index == 0) |
ps->levels[i].ds_divider_index = 0; |
if (ps->levels[i].ds_divider_index == 0) |
ps->levels[i].ss_divider_index = 0; |
if (ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) |
ps->levels[i].allow_gnb_slow = 1; |
else if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) || |
(new_rps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)) |
ps->levels[i].allow_gnb_slow = 0; |
else if (i == ps->num_levels - 1) |
ps->levels[i].allow_gnb_slow = 0; |
else |
ps->levels[i].allow_gnb_slow = 1; |
} |
} |
static void sumo_cleanup_asic(struct radeon_device *rdev) |
{ |
sumo_take_smu_control(rdev, false); |
} |
static int sumo_set_thermal_temperature_range(struct radeon_device *rdev, |
int min_temp, int max_temp) |
{ |
int low_temp = 0 * 1000; |
int high_temp = 255 * 1000; |
if (low_temp < min_temp) |
low_temp = min_temp; |
if (high_temp > max_temp) |
high_temp = max_temp; |
if (high_temp < low_temp) { |
DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); |
return -EINVAL; |
} |
WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK); |
WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK); |
rdev->pm.dpm.thermal.min_temp = low_temp; |
rdev->pm.dpm.thermal.max_temp = high_temp; |
return 0; |
} |
static void sumo_update_current_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct sumo_ps *new_ps = sumo_get_ps(rps); |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
pi->current_rps = *rps; |
pi->current_ps = *new_ps; |
pi->current_rps.ps_priv = &pi->current_ps; |
} |
static void sumo_update_requested_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct sumo_ps *new_ps = sumo_get_ps(rps); |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
pi->requested_rps = *rps; |
pi->requested_ps = *new_ps; |
pi->requested_rps.ps_priv = &pi->requested_ps; |
} |
int sumo_dpm_enable(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
if (sumo_dpm_enabled(rdev)) |
return -EINVAL; |
sumo_program_bootup_state(rdev); |
sumo_init_bsp(rdev); |
sumo_reset_am(rdev); |
sumo_program_tp(rdev); |
sumo_program_bootup_at(rdev); |
sumo_start_am(rdev); |
if (pi->enable_auto_thermal_throttling) { |
sumo_program_ttp(rdev); |
sumo_program_ttt(rdev); |
} |
sumo_program_dc_hto(rdev); |
sumo_program_power_level_enter_state(rdev); |
sumo_enable_voltage_scaling(rdev, true); |
sumo_program_sstp(rdev); |
sumo_program_vc(rdev, SUMO_VRC_DFLT); |
sumo_override_cnb_thermal_events(rdev); |
sumo_start_dpm(rdev); |
sumo_wait_for_level_0(rdev); |
if (pi->enable_sclk_ds) |
sumo_enable_sclk_ds(rdev, true); |
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); |
if (ret) |
return ret; |
rdev->irq.dpm_thermal = true; |
radeon_irq_set(rdev); |
} |
return 0; |
} |
void sumo_dpm_disable(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
if (!sumo_dpm_enabled(rdev)) |
return; |
sumo_disable_clock_power_gating(rdev); |
if (pi->enable_sclk_ds) |
sumo_enable_sclk_ds(rdev, false); |
sumo_clear_vc(rdev); |
sumo_wait_for_level_0(rdev); |
sumo_stop_dpm(rdev); |
sumo_enable_voltage_scaling(rdev, false); |
if (rdev->irq.installed && |
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { |
rdev->irq.dpm_thermal = false; |
radeon_irq_set(rdev); |
} |
sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps); |
} |
int sumo_dpm_pre_set_power_state(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; |
struct radeon_ps *new_ps = &requested_ps; |
sumo_update_requested_ps(rdev, new_ps); |
if (pi->enable_dynamic_patch_ps) |
sumo_apply_state_adjust_rules(rdev, |
&pi->requested_rps, |
&pi->current_rps); |
return 0; |
} |
int sumo_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct radeon_ps *new_ps = &pi->requested_rps; |
struct radeon_ps *old_ps = &pi->current_rps; |
if (pi->enable_dpm) |
sumo_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
if (pi->enable_boost) { |
sumo_enable_boost(rdev, new_ps, false); |
sumo_patch_boost_state(rdev, new_ps); |
} |
if (pi->enable_dpm) { |
sumo_pre_notify_alt_vddnb_change(rdev, new_ps, old_ps); |
sumo_enable_power_level_0(rdev); |
sumo_set_forced_level_0(rdev); |
sumo_set_forced_mode_enabled(rdev); |
sumo_wait_for_level_0(rdev); |
sumo_program_power_levels_0_to_n(rdev, new_ps, old_ps); |
sumo_program_wl(rdev, new_ps); |
sumo_program_bsp(rdev, new_ps); |
sumo_program_at(rdev, new_ps); |
sumo_force_nbp_state(rdev, new_ps); |
sumo_set_forced_mode_disabled(rdev); |
sumo_set_forced_mode_enabled(rdev); |
sumo_set_forced_mode_disabled(rdev); |
sumo_post_notify_alt_vddnb_change(rdev, new_ps, old_ps); |
} |
if (pi->enable_boost) |
sumo_enable_boost(rdev, new_ps, true); |
if (pi->enable_dpm) |
sumo_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
return 0; |
} |
void sumo_dpm_post_set_power_state(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct radeon_ps *new_ps = &pi->requested_rps; |
sumo_update_current_ps(rdev, new_ps); |
} |
void sumo_dpm_reset_asic(struct radeon_device *rdev) |
{ |
sumo_program_bootup_state(rdev); |
sumo_enable_power_level_0(rdev); |
sumo_set_forced_level_0(rdev); |
sumo_set_forced_mode_enabled(rdev); |
sumo_wait_for_level_0(rdev); |
sumo_set_forced_mode_disabled(rdev); |
sumo_set_forced_mode_enabled(rdev); |
sumo_set_forced_mode_disabled(rdev); |
} |
void sumo_dpm_setup_asic(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
sumo_initialize_m3_arb(rdev); |
pi->fw_version = sumo_get_running_fw_version(rdev); |
DRM_INFO("Found smc ucode version: 0x%08x\n", pi->fw_version); |
sumo_program_acpi_power_level(rdev); |
sumo_enable_acpi_pm(rdev); |
sumo_take_smu_control(rdev, true); |
} |
void sumo_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
} |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void sumo_patch_boot_state(struct radeon_device *rdev, |
struct sumo_ps *ps) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
ps->num_levels = 1; |
ps->flags = 0; |
ps->levels[0] = pi->boot_pl; |
} |
static void sumo_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, |
u8 table_rev) |
{ |
struct sumo_ps *ps = sumo_get_ps(rps); |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { |
rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); |
rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
rdev->pm.dpm.boot_ps = rps; |
sumo_patch_boot_state(rdev, ps); |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void sumo_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, int index, |
union pplib_clock_info *clock_info) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct sumo_ps *ps = sumo_get_ps(rps); |
struct sumo_pl *pl = &ps->levels[index]; |
u32 sclk; |
sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); |
sclk |= clock_info->sumo.ucEngineClockHigh << 16; |
pl->sclk = sclk; |
pl->vddc_index = clock_info->sumo.vddcIndex; |
pl->sclk_dpm_tdp_limit = clock_info->sumo.tdpLimit; |
ps->num_levels = index + 1; |
if (pi->enable_sclk_ds) { |
pl->ds_divider_index = 5; |
pl->ss_divider_index = 4; |
} |
} |
static int sumo_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i, j, k, non_clock_array_index, clock_array_index; |
union pplib_clock_info *clock_info; |
struct _StateArray *state_array; |
struct _ClockInfoArray *clock_info_array; |
struct _NonClockInfoArray *non_clock_info_array; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
u8 *power_state_offset; |
struct sumo_ps *ps; |
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); |
state_array = (struct _StateArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset)); |
clock_info_array = (struct _ClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); |
non_clock_info_array = (struct _NonClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); |
rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * |
state_array->ucNumEntries, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
power_state_offset = (u8 *)state_array->states; |
for (i = 0; i < state_array->ucNumEntries; i++) { |
u8 *idx; |
power_state = (union pplib_power_state *)power_state_offset; |
non_clock_array_index = power_state->v2.nonClockInfoIndex; |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
&non_clock_info_array->nonClockInfo[non_clock_array_index]; |
if (!rdev->pm.power_state[i].clock_info) |
return -EINVAL; |
ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
k = 0; |
idx = (u8 *)&power_state->v2.clockInfoIndex[0]; |
for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { |
clock_array_index = idx[j]; |
if (k >= SUMO_MAX_HARDWARE_POWERLEVELS) |
break; |
clock_info = (union pplib_clock_info *) |
((u8 *)&clock_info_array->clockInfo[0] + |
(clock_array_index * clock_info_array->ucEntrySize)); |
sumo_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], k, |
clock_info); |
k++; |
} |
sumo_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info, |
non_clock_info_array->ucEntrySize); |
power_state_offset += 2 + power_state->v2.ucNumDPMLevels; |
} |
rdev->pm.dpm.num_ps = state_array->ucNumEntries; |
return 0; |
} |
u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev, |
struct sumo_vid_mapping_table *vid_mapping_table, |
u32 vid_2bit) |
{ |
u32 i; |
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; |
} |
u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev, |
struct sumo_vid_mapping_table *vid_mapping_table, |
u32 vid_7bit) |
{ |
u32 i; |
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 sumo_convert_voltage_index_to_value(struct radeon_device *rdev, |
u32 vid_2bit) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit); |
if (vid_7bit > 0x7C) |
return 0; |
return (15500 - vid_7bit * 125 + 5) / 10; |
} |
static void sumo_construct_display_voltage_mapping_table(struct radeon_device *rdev, |
struct sumo_disp_clock_voltage_mapping_table *disp_clk_voltage_mapping_table, |
ATOM_CLK_VOLT_CAPABILITY *table) |
{ |
u32 i; |
for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) { |
if (table[i].ulMaximumSupportedCLK == 0) |
break; |
disp_clk_voltage_mapping_table->display_clock_frequency[i] = |
table[i].ulMaximumSupportedCLK; |
} |
disp_clk_voltage_mapping_table->num_max_voltage_levels = i; |
if (disp_clk_voltage_mapping_table->num_max_voltage_levels == 0) { |
disp_clk_voltage_mapping_table->display_clock_frequency[0] = 80000; |
disp_clk_voltage_mapping_table->num_max_voltage_levels = 1; |
} |
} |
void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev, |
struct sumo_sclk_voltage_mapping_table *sclk_voltage_mapping_table, |
ATOM_AVAILABLE_SCLK_LIST *table) |
{ |
u32 i; |
u32 n = 0; |
u32 prev_sclk = 0; |
for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) { |
if (table[i].ulSupportedSCLK > prev_sclk) { |
sclk_voltage_mapping_table->entries[n].sclk_frequency = |
table[i].ulSupportedSCLK; |
sclk_voltage_mapping_table->entries[n].vid_2bit = |
table[i].usVoltageIndex; |
prev_sclk = table[i].ulSupportedSCLK; |
n++; |
} |
} |
sclk_voltage_mapping_table->num_max_dpm_entries = n; |
} |
void sumo_construct_vid_mapping_table(struct radeon_device *rdev, |
struct sumo_vid_mapping_table *vid_mapping_table, |
ATOM_AVAILABLE_SCLK_LIST *table) |
{ |
u32 i, j; |
for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) { |
if (table[i].ulSupportedSCLK != 0) { |
vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit = |
table[i].usVoltageID; |
vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit = |
table[i].usVoltageIndex; |
} |
} |
for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) { |
if (vid_mapping_table->entries[i].vid_7bit == 0) { |
for (j = i + 1; j < SUMO_MAX_NUMBER_VOLTAGES; j++) { |
if (vid_mapping_table->entries[j].vid_7bit != 0) { |
vid_mapping_table->entries[i] = |
vid_mapping_table->entries[j]; |
vid_mapping_table->entries[j].vid_7bit = 0; |
break; |
} |
} |
if (j == SUMO_MAX_NUMBER_VOLTAGES) |
break; |
} |
} |
vid_mapping_table->num_entries = i; |
} |
union igp_info { |
struct _ATOM_INTEGRATED_SYSTEM_INFO info; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; |
}; |
static int sumo_parse_sys_info_table(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); |
union igp_info *igp_info; |
u8 frev, crev; |
u16 data_offset; |
int i; |
if (atom_parse_data_header(mode_info->atom_context, index, NULL, |
&frev, &crev, &data_offset)) { |
igp_info = (union igp_info *)(mode_info->atom_context->bios + |
data_offset); |
if (crev != 6) { |
DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); |
return -EINVAL; |
} |
pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_6.ulBootUpEngineClock); |
pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_6.ulMinEngineClock); |
pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_6.ulBootUpUMAClock); |
pi->sys_info.bootup_nb_voltage_index = |
le16_to_cpu(igp_info->info_6.usBootUpNBVoltage); |
if (igp_info->info_6.ucHtcTmpLmt == 0) |
pi->sys_info.htc_tmp_lmt = 203; |
else |
pi->sys_info.htc_tmp_lmt = igp_info->info_6.ucHtcTmpLmt; |
if (igp_info->info_6.ucHtcHystLmt == 0) |
pi->sys_info.htc_hyst_lmt = 5; |
else |
pi->sys_info.htc_hyst_lmt = igp_info->info_6.ucHtcHystLmt; |
if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { |
DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); |
} |
for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++) { |
pi->sys_info.csr_m3_arb_cntl_default[i] = |
le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_DEFAULT[i]); |
pi->sys_info.csr_m3_arb_cntl_uvd[i] = |
le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_UVD[i]); |
pi->sys_info.csr_m3_arb_cntl_fs3d[i] = |
le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_FS3D[i]); |
} |
pi->sys_info.sclk_dpm_boost_margin = |
le32_to_cpu(igp_info->info_6.SclkDpmBoostMargin); |
pi->sys_info.sclk_dpm_throttle_margin = |
le32_to_cpu(igp_info->info_6.SclkDpmThrottleMargin); |
pi->sys_info.sclk_dpm_tdp_limit_pg = |
le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitPG); |
pi->sys_info.gnb_tdp_limit = le16_to_cpu(igp_info->info_6.GnbTdpLimit); |
pi->sys_info.sclk_dpm_tdp_limit_boost = |
le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitBoost); |
pi->sys_info.boost_sclk = le32_to_cpu(igp_info->info_6.ulBoostEngineCLock); |
pi->sys_info.boost_vid_2bit = igp_info->info_6.ulBoostVid_2bit; |
if (igp_info->info_6.EnableBoost) |
pi->sys_info.enable_boost = true; |
else |
pi->sys_info.enable_boost = false; |
sumo_construct_display_voltage_mapping_table(rdev, |
&pi->sys_info.disp_clk_voltage_mapping_table, |
igp_info->info_6.sDISPCLK_Voltage); |
sumo_construct_sclk_voltage_mapping_table(rdev, |
&pi->sys_info.sclk_voltage_mapping_table, |
igp_info->info_6.sAvail_SCLK); |
sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table, |
igp_info->info_6.sAvail_SCLK); |
} |
return 0; |
} |
static void sumo_construct_boot_and_acpi_state(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
pi->boot_pl.sclk = pi->sys_info.bootup_sclk; |
pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index; |
pi->boot_pl.ds_divider_index = 0; |
pi->boot_pl.ss_divider_index = 0; |
pi->boot_pl.allow_gnb_slow = 1; |
pi->acpi_pl = pi->boot_pl; |
pi->current_ps.num_levels = 1; |
pi->current_ps.levels[0] = pi->boot_pl; |
} |
int sumo_dpm_init(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi; |
u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT; |
int ret; |
pi = kzalloc(sizeof(struct sumo_power_info), GFP_KERNEL); |
if (pi == NULL) |
return -ENOMEM; |
rdev->pm.dpm.priv = pi; |
pi->driver_nbps_policy_disable = false; |
if ((rdev->family == CHIP_PALM) && (hw_rev < 3)) |
pi->disable_gfx_power_gating_in_uvd = true; |
else |
pi->disable_gfx_power_gating_in_uvd = false; |
pi->enable_alt_vddnb = true; |
pi->enable_sclk_ds = true; |
pi->enable_dynamic_m3_arbiter = false; |
pi->enable_dynamic_patch_ps = true; |
/* Some PALM chips don't seem to properly ungate gfx when UVD is in use; |
* for now just disable gfx PG. |
*/ |
if (rdev->family == CHIP_PALM) |
pi->enable_gfx_power_gating = false; |
else |
pi->enable_gfx_power_gating = true; |
pi->enable_gfx_clock_gating = true; |
pi->enable_mg_clock_gating = true; |
pi->enable_auto_thermal_throttling = true; |
ret = sumo_parse_sys_info_table(rdev); |
if (ret) |
return ret; |
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; |
pi->pasi = CYPRESS_HASI_DFLT; |
pi->asi = RV770_ASI_DFLT; |
pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt; |
pi->enable_boost = pi->sys_info.enable_boost; |
pi->enable_dpm = true; |
return 0; |
} |
void sumo_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
int i; |
struct sumo_ps *ps = sumo_get_ps(rps); |
r600_dpm_print_class_info(rps->class, rps->class2); |
r600_dpm_print_cap_info(rps->caps); |
printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
for (i = 0; i < ps->num_levels; i++) { |
struct sumo_pl *pl = &ps->levels[i]; |
printk("\t\tpower level %d sclk: %u vddc: %u\n", |
i, pl->sclk, |
sumo_convert_voltage_index_to_value(rdev, pl->vddc_index)); |
} |
r600_dpm_print_ps_status(rdev, rps); |
} |
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 = &pi->current_rps; |
struct sumo_ps *ps = sumo_get_ps(rps); |
struct sumo_pl *pl; |
u32 current_index = |
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >> |
CURR_INDEX_SHIFT; |
if (current_index == BOOST_DPM_LEVEL) { |
pl = &pi->boost_pl; |
seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
seq_printf(m, "power level %d sclk: %u vddc: %u\n", |
current_index, pl->sclk, |
sumo_convert_voltage_index_to_value(rdev, pl->vddc_index)); |
} else if (current_index >= ps->num_levels) { |
seq_printf(m, "invalid dpm profile %d\n", current_index); |
} else { |
pl = &ps->levels[current_index]; |
seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
seq_printf(m, "power level %d sclk: %u vddc: %u\n", |
current_index, pl->sclk, |
sumo_convert_voltage_index_to_value(rdev, pl->vddc_index)); |
} |
} |
void sumo_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
sumo_cleanup_asic(rdev); /* ??? */ |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
} |
u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct sumo_ps *requested_state = sumo_get_ps(&pi->requested_rps); |
if (low) |
return requested_state->levels[0].sclk; |
else |
return requested_state->levels[requested_state->num_levels - 1].sclk; |
} |
u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
return pi->sys_info.bootup_uma_clk; |
} |
int sumo_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
struct radeon_ps *rps = &pi->current_rps; |
struct sumo_ps *ps = sumo_get_ps(rps); |
int i; |
if (ps->num_levels <= 1) |
return 0; |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
if (pi->enable_boost) |
sumo_enable_boost(rdev, rps, false); |
sumo_power_level_enable(rdev, ps->num_levels - 1, true); |
sumo_set_forced_level(rdev, ps->num_levels - 1); |
sumo_set_forced_mode_enabled(rdev); |
for (i = 0; i < ps->num_levels - 1; i++) { |
sumo_power_level_enable(rdev, i, false); |
} |
sumo_set_forced_mode(rdev, false); |
sumo_set_forced_mode_enabled(rdev); |
sumo_set_forced_mode(rdev, false); |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
if (pi->enable_boost) |
sumo_enable_boost(rdev, rps, false); |
sumo_power_level_enable(rdev, 0, true); |
sumo_set_forced_level(rdev, 0); |
sumo_set_forced_mode_enabled(rdev); |
for (i = 1; i < ps->num_levels; i++) { |
sumo_power_level_enable(rdev, i, false); |
} |
sumo_set_forced_mode(rdev, false); |
sumo_set_forced_mode_enabled(rdev); |
sumo_set_forced_mode(rdev, false); |
} else { |
for (i = 0; i < ps->num_levels; i++) { |
sumo_power_level_enable(rdev, i, true); |
} |
if (pi->enable_boost) |
sumo_enable_boost(rdev, rps, true); |
} |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
/drivers/video/drm/radeon/sumo_dpm.h |
---|
0,0 → 1,223 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __SUMO_DPM_H__ |
#define __SUMO_DPM_H__ |
#include "atom.h" |
#define SUMO_MAX_HARDWARE_POWERLEVELS 5 |
#define SUMO_PM_NUMBER_OF_TC 15 |
struct sumo_pl { |
u32 sclk; |
u32 vddc_index; |
u32 ds_divider_index; |
u32 ss_divider_index; |
u32 allow_gnb_slow; |
u32 sclk_dpm_tdp_limit; |
}; |
/* used for the flags field */ |
#define SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE (1 << 0) |
#define SUMO_POWERSTATE_FLAGS_BOOST_STATE (1 << 1) |
struct sumo_ps { |
struct sumo_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS]; |
u32 num_levels; |
/* flags */ |
u32 flags; |
}; |
#define NUMBER_OF_M3ARB_PARAM_SETS 10 |
#define SUMO_MAX_NUMBER_VOLTAGES 4 |
struct sumo_disp_clock_voltage_mapping_table { |
u32 num_max_voltage_levels; |
u32 display_clock_frequency[SUMO_MAX_NUMBER_VOLTAGES]; |
}; |
struct sumo_vid_mapping_entry { |
u16 vid_2bit; |
u16 vid_7bit; |
}; |
struct sumo_vid_mapping_table { |
u32 num_entries; |
struct sumo_vid_mapping_entry entries[SUMO_MAX_NUMBER_VOLTAGES]; |
}; |
struct sumo_sclk_voltage_mapping_entry { |
u32 sclk_frequency; |
u16 vid_2bit; |
u16 rsv; |
}; |
struct sumo_sclk_voltage_mapping_table { |
u32 num_max_dpm_entries; |
struct sumo_sclk_voltage_mapping_entry entries[SUMO_MAX_HARDWARE_POWERLEVELS]; |
}; |
struct sumo_sys_info { |
u32 bootup_sclk; |
u32 min_sclk; |
u32 bootup_uma_clk; |
u16 bootup_nb_voltage_index; |
u8 htc_tmp_lmt; |
u8 htc_hyst_lmt; |
struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table; |
struct sumo_disp_clock_voltage_mapping_table disp_clk_voltage_mapping_table; |
struct sumo_vid_mapping_table vid_mapping_table; |
u32 csr_m3_arb_cntl_default[NUMBER_OF_M3ARB_PARAM_SETS]; |
u32 csr_m3_arb_cntl_uvd[NUMBER_OF_M3ARB_PARAM_SETS]; |
u32 csr_m3_arb_cntl_fs3d[NUMBER_OF_M3ARB_PARAM_SETS]; |
u32 sclk_dpm_boost_margin; |
u32 sclk_dpm_throttle_margin; |
u32 sclk_dpm_tdp_limit_pg; |
u32 gnb_tdp_limit; |
u32 sclk_dpm_tdp_limit_boost; |
u32 boost_sclk; |
u32 boost_vid_2bit; |
bool enable_boost; |
}; |
struct sumo_power_info { |
u32 asi; |
u32 pasi; |
u32 bsp; |
u32 bsu; |
u32 pbsp; |
u32 pbsu; |
u32 dsp; |
u32 psp; |
u32 thermal_auto_throttling; |
u32 uvd_m3_arbiter; |
u32 fw_version; |
struct sumo_sys_info sys_info; |
struct sumo_pl acpi_pl; |
struct sumo_pl boot_pl; |
struct sumo_pl boost_pl; |
bool disable_gfx_power_gating_in_uvd; |
bool driver_nbps_policy_disable; |
bool enable_alt_vddnb; |
bool enable_dynamic_m3_arbiter; |
bool enable_gfx_clock_gating; |
bool enable_gfx_power_gating; |
bool enable_mg_clock_gating; |
bool enable_sclk_ds; |
bool enable_auto_thermal_throttling; |
bool enable_dynamic_patch_ps; |
bool enable_dpm; |
bool enable_boost; |
struct radeon_ps current_rps; |
struct sumo_ps current_ps; |
struct radeon_ps requested_rps; |
struct sumo_ps requested_ps; |
}; |
#define SUMO_UTC_DFLT_00 0x48 |
#define SUMO_UTC_DFLT_01 0x44 |
#define SUMO_UTC_DFLT_02 0x44 |
#define SUMO_UTC_DFLT_03 0x44 |
#define SUMO_UTC_DFLT_04 0x44 |
#define SUMO_UTC_DFLT_05 0x44 |
#define SUMO_UTC_DFLT_06 0x44 |
#define SUMO_UTC_DFLT_07 0x44 |
#define SUMO_UTC_DFLT_08 0x44 |
#define SUMO_UTC_DFLT_09 0x44 |
#define SUMO_UTC_DFLT_10 0x44 |
#define SUMO_UTC_DFLT_11 0x44 |
#define SUMO_UTC_DFLT_12 0x44 |
#define SUMO_UTC_DFLT_13 0x44 |
#define SUMO_UTC_DFLT_14 0x44 |
#define SUMO_DTC_DFLT_00 0x48 |
#define SUMO_DTC_DFLT_01 0x44 |
#define SUMO_DTC_DFLT_02 0x44 |
#define SUMO_DTC_DFLT_03 0x44 |
#define SUMO_DTC_DFLT_04 0x44 |
#define SUMO_DTC_DFLT_05 0x44 |
#define SUMO_DTC_DFLT_06 0x44 |
#define SUMO_DTC_DFLT_07 0x44 |
#define SUMO_DTC_DFLT_08 0x44 |
#define SUMO_DTC_DFLT_09 0x44 |
#define SUMO_DTC_DFLT_10 0x44 |
#define SUMO_DTC_DFLT_11 0x44 |
#define SUMO_DTC_DFLT_12 0x44 |
#define SUMO_DTC_DFLT_13 0x44 |
#define SUMO_DTC_DFLT_14 0x44 |
#define SUMO_AH_DFLT 5 |
#define SUMO_R_DFLT0 70 |
#define SUMO_R_DFLT1 70 |
#define SUMO_R_DFLT2 70 |
#define SUMO_R_DFLT3 70 |
#define SUMO_R_DFLT4 100 |
#define SUMO_L_DFLT0 0 |
#define SUMO_L_DFLT1 20 |
#define SUMO_L_DFLT2 20 |
#define SUMO_L_DFLT3 20 |
#define SUMO_L_DFLT4 20 |
#define SUMO_VRC_DFLT 0x30033 |
#define SUMO_MGCGTTLOCAL0_DFLT 0 |
#define SUMO_MGCGTTLOCAL1_DFLT 0 |
#define SUMO_GICST_DFLT 19 |
#define SUMO_SST_DFLT 8 |
#define SUMO_VOLTAGEDROPT_DFLT 1 |
#define SUMO_GFXPOWERGATINGT_DFLT 100 |
/* sumo_dpm.c */ |
void sumo_gfx_clockgating_initialize(struct radeon_device *rdev); |
void sumo_program_vc(struct radeon_device *rdev, u32 vrc); |
void sumo_clear_vc(struct radeon_device *rdev); |
void sumo_program_sstp(struct radeon_device *rdev); |
void sumo_take_smu_control(struct radeon_device *rdev, bool enable); |
void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev, |
struct sumo_sclk_voltage_mapping_table *sclk_voltage_mapping_table, |
ATOM_AVAILABLE_SCLK_LIST *table); |
void sumo_construct_vid_mapping_table(struct radeon_device *rdev, |
struct sumo_vid_mapping_table *vid_mapping_table, |
ATOM_AVAILABLE_SCLK_LIST *table); |
u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev, |
struct sumo_vid_mapping_table *vid_mapping_table, |
u32 vid_2bit); |
u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev, |
struct sumo_vid_mapping_table *vid_mapping_table, |
u32 vid_7bit); |
u32 sumo_get_sleep_divider_from_id(u32 id); |
u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev, |
u32 sclk, |
u32 min_sclk_in_sr); |
/* sumo_smc.c */ |
void sumo_initialize_m3_arb(struct radeon_device *rdev); |
void sumo_smu_pg_init(struct radeon_device *rdev); |
void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit); |
void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev, |
bool powersaving, bool force_nbps1); |
void sumo_boost_state_enable(struct radeon_device *rdev, bool enable); |
void sumo_enable_boost_timer(struct radeon_device *rdev); |
u32 sumo_get_running_fw_version(struct radeon_device *rdev); |
#endif |
/drivers/video/drm/radeon/sumo_smc.c |
---|
0,0 → 1,221 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "sumod.h" |
#include "sumo_dpm.h" |
#include "ppsmc.h" |
#define SUMO_SMU_SERVICE_ROUTINE_PG_INIT 1 |
#define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY 27 |
#define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20 20 |
struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev); |
static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id) |
{ |
u32 gfx_int_req; |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(GFX_INT_STATUS) & INT_DONE) |
break; |
udelay(1); |
} |
gfx_int_req = SERV_INDEX(id) | INT_REQ; |
WREG32(GFX_INT_REQ, gfx_int_req); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(GFX_INT_REQ) & INT_REQ) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(GFX_INT_STATUS) & INT_ACK) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(GFX_INT_STATUS) & INT_DONE) |
break; |
udelay(1); |
} |
gfx_int_req &= ~INT_REQ; |
WREG32(GFX_INT_REQ, gfx_int_req); |
} |
void sumo_initialize_m3_arb(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 i; |
if (!pi->enable_dynamic_m3_arbiter) |
return; |
for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++) |
WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4), |
pi->sys_info.csr_m3_arb_cntl_default[i]); |
for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 2; i++) |
WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4), |
pi->sys_info.csr_m3_arb_cntl_uvd[i % NUMBER_OF_M3ARB_PARAM_SETS]); |
for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 3; i++) |
WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4), |
pi->sys_info.csr_m3_arb_cntl_fs3d[i % NUMBER_OF_M3ARB_PARAM_SETS]); |
} |
static bool sumo_is_alt_vddnb_supported(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
bool return_code = false; |
if (!pi->enable_alt_vddnb) |
return return_code; |
if ((rdev->family == CHIP_SUMO) || (rdev->family == CHIP_SUMO2)) { |
if (pi->fw_version >= 0x00010C00) |
return_code = true; |
} |
return return_code; |
} |
void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev, |
bool powersaving, bool force_nbps1) |
{ |
u32 param = 0; |
if (!sumo_is_alt_vddnb_supported(rdev)) |
return; |
if (powersaving) |
param |= 1; |
if (force_nbps1) |
param |= 2; |
WREG32_RCU(RCU_ALTVDDNB_NOTIFY, param); |
sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY); |
} |
void sumo_smu_pg_init(struct radeon_device *rdev) |
{ |
sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_PG_INIT); |
} |
static u32 sumo_power_of_4(u32 unit) |
{ |
u32 ret = 1; |
u32 i; |
for (i = 0; i < unit; i++) |
ret *= 4; |
return ret; |
} |
void sumo_enable_boost_timer(struct radeon_device *rdev) |
{ |
struct sumo_power_info *pi = sumo_get_pi(rdev); |
u32 period, unit, timer_value; |
u32 xclk = radeon_get_xclk(rdev); |
unit = (RREG32_RCU(RCU_LCLK_SCALING_CNTL) & LCLK_SCALING_TIMER_PRESCALER_MASK) |
>> LCLK_SCALING_TIMER_PRESCALER_SHIFT; |
period = 100 * (xclk / 100 / sumo_power_of_4(unit)); |
timer_value = (period << 16) | (unit << 4); |
WREG32_RCU(RCU_GNB_PWR_REP_TIMER_CNTL, timer_value); |
WREG32_RCU(RCU_BOOST_MARGIN, pi->sys_info.sclk_dpm_boost_margin); |
WREG32_RCU(RCU_THROTTLE_MARGIN, pi->sys_info.sclk_dpm_throttle_margin); |
WREG32_RCU(GNB_TDP_LIMIT, pi->sys_info.gnb_tdp_limit); |
WREG32_RCU(RCU_SclkDpmTdpLimitPG, pi->sys_info.sclk_dpm_tdp_limit_pg); |
sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20); |
} |
void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit) |
{ |
u32 regoffset = 0; |
u32 shift = 0; |
u32 mask = 0xFFF; |
u32 sclk_dpm_tdp_limit; |
switch (index) { |
case 0: |
regoffset = RCU_SclkDpmTdpLimit01; |
shift = 16; |
break; |
case 1: |
regoffset = RCU_SclkDpmTdpLimit01; |
shift = 0; |
break; |
case 2: |
regoffset = RCU_SclkDpmTdpLimit23; |
shift = 16; |
break; |
case 3: |
regoffset = RCU_SclkDpmTdpLimit23; |
shift = 0; |
break; |
case 4: |
regoffset = RCU_SclkDpmTdpLimit47; |
shift = 16; |
break; |
case 7: |
regoffset = RCU_SclkDpmTdpLimit47; |
shift = 0; |
break; |
default: |
break; |
} |
sclk_dpm_tdp_limit = RREG32_RCU(regoffset); |
sclk_dpm_tdp_limit &= ~(mask << shift); |
sclk_dpm_tdp_limit |= (tdp_limit << shift); |
WREG32_RCU(regoffset, sclk_dpm_tdp_limit); |
} |
void sumo_boost_state_enable(struct radeon_device *rdev, bool enable) |
{ |
u32 boost_disable = RREG32_RCU(RCU_GPU_BOOST_DISABLE); |
boost_disable &= 0xFFFFFFFE; |
boost_disable |= (enable ? 0 : 1); |
WREG32_RCU(RCU_GPU_BOOST_DISABLE, boost_disable); |
} |
u32 sumo_get_running_fw_version(struct radeon_device *rdev) |
{ |
return RREG32_RCU(RCU_FW_VERSION); |
} |
/drivers/video/drm/radeon/sumod.h |
---|
0,0 → 1,372 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#ifndef _SUMOD_H_ |
#define _SUMOD_H_ |
/* pm registers */ |
/* rcu */ |
#define RCU_FW_VERSION 0x30c |
#define RCU_PWR_GATING_SEQ0 0x408 |
#define RCU_PWR_GATING_SEQ1 0x40c |
#define RCU_PWR_GATING_CNTL 0x410 |
# define PWR_GATING_EN (1 << 0) |
# define RSVD_MASK (0x3 << 1) |
# define PCV(x) ((x) << 3) |
# define PCV_MASK (0x1f << 3) |
# define PCV_SHIFT 3 |
# define PCP(x) ((x) << 8) |
# define PCP_MASK (0xf << 8) |
# define PCP_SHIFT 8 |
# define RPW(x) ((x) << 16) |
# define RPW_MASK (0xf << 16) |
# define RPW_SHIFT 16 |
# define ID(x) ((x) << 24) |
# define ID_MASK (0xf << 24) |
# define ID_SHIFT 24 |
# define PGS(x) ((x) << 28) |
# define PGS_MASK (0xf << 28) |
# define PGS_SHIFT 28 |
#define RCU_ALTVDDNB_NOTIFY 0x430 |
#define RCU_LCLK_SCALING_CNTL 0x434 |
# define LCLK_SCALING_EN (1 << 0) |
# define LCLK_SCALING_TYPE (1 << 1) |
# define LCLK_SCALING_TIMER_PRESCALER(x) ((x) << 4) |
# define LCLK_SCALING_TIMER_PRESCALER_MASK (0xf << 4) |
# define LCLK_SCALING_TIMER_PRESCALER_SHIFT 4 |
# define LCLK_SCALING_TIMER_PERIOD(x) ((x) << 16) |
# define LCLK_SCALING_TIMER_PERIOD_MASK (0xf << 16) |
# define LCLK_SCALING_TIMER_PERIOD_SHIFT 16 |
#define RCU_PWR_GATING_CNTL_2 0x4a0 |
# define MPPU(x) ((x) << 0) |
# define MPPU_MASK (0xffff << 0) |
# define MPPU_SHIFT 0 |
# define MPPD(x) ((x) << 16) |
# define MPPD_MASK (0xffff << 16) |
# define MPPD_SHIFT 16 |
#define RCU_PWR_GATING_CNTL_3 0x4a4 |
# define DPPU(x) ((x) << 0) |
# define DPPU_MASK (0xffff << 0) |
# define DPPU_SHIFT 0 |
# define DPPD(x) ((x) << 16) |
# define DPPD_MASK (0xffff << 16) |
# define DPPD_SHIFT 16 |
#define RCU_PWR_GATING_CNTL_4 0x4a8 |
# define RT(x) ((x) << 0) |
# define RT_MASK (0xffff << 0) |
# define RT_SHIFT 0 |
# define IT(x) ((x) << 16) |
# define IT_MASK (0xffff << 16) |
# define IT_SHIFT 16 |
/* yes these two have the same address */ |
#define RCU_PWR_GATING_CNTL_5 0x504 |
#define RCU_GPU_BOOST_DISABLE 0x508 |
#define MCU_M3ARB_INDEX 0x504 |
#define MCU_M3ARB_PARAMS 0x508 |
#define RCU_GNB_PWR_REP_TIMER_CNTL 0x50C |
#define RCU_SclkDpmTdpLimit01 0x514 |
#define RCU_SclkDpmTdpLimit23 0x518 |
#define RCU_SclkDpmTdpLimit47 0x51C |
#define RCU_SclkDpmTdpLimitPG 0x520 |
#define GNB_TDP_LIMIT 0x540 |
#define RCU_BOOST_MARGIN 0x544 |
#define RCU_THROTTLE_MARGIN 0x548 |
#define SMU_PCIE_PG_ARGS 0x58C |
#define SMU_PCIE_PG_ARGS_2 0x598 |
#define SMU_PCIE_PG_ARGS_3 0x59C |
/* mmio */ |
#define RCU_STATUS 0x11c |
# define GMC_PWR_GATER_BUSY (1 << 8) |
# define GFX_PWR_GATER_BUSY (1 << 9) |
# define UVD_PWR_GATER_BUSY (1 << 10) |
# define PCIE_PWR_GATER_BUSY (1 << 11) |
# define GMC_PWR_GATER_STATE (1 << 12) |
# define GFX_PWR_GATER_STATE (1 << 13) |
# define UVD_PWR_GATER_STATE (1 << 14) |
# define PCIE_PWR_GATER_STATE (1 << 15) |
# define GFX1_PWR_GATER_BUSY (1 << 16) |
# define GFX2_PWR_GATER_BUSY (1 << 17) |
# define GFX1_PWR_GATER_STATE (1 << 18) |
# define GFX2_PWR_GATER_STATE (1 << 19) |
#define GFX_INT_REQ 0x120 |
# define INT_REQ (1 << 0) |
# define SERV_INDEX(x) ((x) << 1) |
# define SERV_INDEX_MASK (0xff << 1) |
# define SERV_INDEX_SHIFT 1 |
#define GFX_INT_STATUS 0x124 |
# define INT_ACK (1 << 0) |
# define INT_DONE (1 << 1) |
#define CG_SCLK_CNTL 0x600 |
# define SCLK_DIVIDER(x) ((x) << 0) |
# define SCLK_DIVIDER_MASK (0x7f << 0) |
# define SCLK_DIVIDER_SHIFT 0 |
#define CG_SCLK_STATUS 0x604 |
# define SCLK_OVERCLK_DETECT (1 << 2) |
#define CG_DCLK_CNTL 0x610 |
# define DCLK_DIVIDER_MASK 0x7f |
# define DCLK_DIR_CNTL_EN (1 << 8) |
#define CG_DCLK_STATUS 0x614 |
# define DCLK_STATUS (1 << 0) |
#define CG_VCLK_CNTL 0x618 |
# define VCLK_DIVIDER_MASK 0x7f |
# define VCLK_DIR_CNTL_EN (1 << 8) |
#define CG_VCLK_STATUS 0x61c |
#define GENERAL_PWRMGT 0x63c |
# define STATIC_PM_EN (1 << 1) |
#define SCLK_PWRMGT_CNTL 0x644 |
# define SCLK_PWRMGT_OFF (1 << 0) |
# define SCLK_LOW_D1 (1 << 1) |
# define FIR_RESET (1 << 4) |
# define FIR_FORCE_TREND_SEL (1 << 5) |
# define FIR_TREND_MODE (1 << 6) |
# define DYN_GFX_CLK_OFF_EN (1 << 7) |
# define GFX_CLK_FORCE_ON (1 << 8) |
# define GFX_CLK_REQUEST_OFF (1 << 9) |
# define GFX_CLK_FORCE_OFF (1 << 10) |
# define GFX_CLK_OFF_ACPI_D1 (1 << 11) |
# define GFX_CLK_OFF_ACPI_D2 (1 << 12) |
# define GFX_CLK_OFF_ACPI_D3 (1 << 13) |
# define GFX_VOLTAGE_CHANGE_EN (1 << 16) |
# define GFX_VOLTAGE_CHANGE_MODE (1 << 17) |
#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c |
# define TARG_SCLK_INDEX(x) ((x) << 6) |
# define TARG_SCLK_INDEX_MASK (0x7 << 6) |
# define TARG_SCLK_INDEX_SHIFT 6 |
# define CURR_SCLK_INDEX(x) ((x) << 9) |
# define CURR_SCLK_INDEX_MASK (0x7 << 9) |
# define CURR_SCLK_INDEX_SHIFT 9 |
# define TARG_INDEX(x) ((x) << 12) |
# define TARG_INDEX_MASK (0x7 << 12) |
# define TARG_INDEX_SHIFT 12 |
# define CURR_INDEX(x) ((x) << 15) |
# define CURR_INDEX_MASK (0x7 << 15) |
# define CURR_INDEX_SHIFT 15 |
#define CG_SCLK_DPM_CTRL 0x684 |
# define SCLK_FSTATE_0_DIV(x) ((x) << 0) |
# define SCLK_FSTATE_0_DIV_MASK (0x7f << 0) |
# define SCLK_FSTATE_0_DIV_SHIFT 0 |
# define SCLK_FSTATE_0_VLD (1 << 7) |
# define SCLK_FSTATE_1_DIV(x) ((x) << 8) |
# define SCLK_FSTATE_1_DIV_MASK (0x7f << 8) |
# define SCLK_FSTATE_1_DIV_SHIFT 8 |
# define SCLK_FSTATE_1_VLD (1 << 15) |
# define SCLK_FSTATE_2_DIV(x) ((x) << 16) |
# define SCLK_FSTATE_2_DIV_MASK (0x7f << 16) |
# define SCLK_FSTATE_2_DIV_SHIFT 16 |
# define SCLK_FSTATE_2_VLD (1 << 23) |
# define SCLK_FSTATE_3_DIV(x) ((x) << 24) |
# define SCLK_FSTATE_3_DIV_MASK (0x7f << 24) |
# define SCLK_FSTATE_3_DIV_SHIFT 24 |
# define SCLK_FSTATE_3_VLD (1 << 31) |
#define CG_SCLK_DPM_CTRL_2 0x688 |
#define CG_GCOOR 0x68c |
# define PHC(x) ((x) << 0) |
# define PHC_MASK (0x1f << 0) |
# define PHC_SHIFT 0 |
# define SDC(x) ((x) << 9) |
# define SDC_MASK (0x3ff << 9) |
# define SDC_SHIFT 9 |
# define SU(x) ((x) << 23) |
# define SU_MASK (0xf << 23) |
# define SU_SHIFT 23 |
# define DIV_ID(x) ((x) << 28) |
# define DIV_ID_MASK (0x7 << 28) |
# define DIV_ID_SHIFT 28 |
#define CG_FTV 0x690 |
#define CG_FFCT_0 0x694 |
# define UTC_0(x) ((x) << 0) |
# define UTC_0_MASK (0x3ff << 0) |
# define UTC_0_SHIFT 0 |
# define DTC_0(x) ((x) << 10) |
# define DTC_0_MASK (0x3ff << 10) |
# define DTC_0_SHIFT 10 |
#define CG_GIT 0x6d8 |
# define CG_GICST(x) ((x) << 0) |
# define CG_GICST_MASK (0xffff << 0) |
# define CG_GICST_SHIFT 0 |
# define CG_GIPOT(x) ((x) << 16) |
# define CG_GIPOT_MASK (0xffff << 16) |
# define CG_GIPOT_SHIFT 16 |
#define CG_SCLK_DPM_CTRL_3 0x6e0 |
# define FORCE_SCLK_STATE(x) ((x) << 0) |
# define FORCE_SCLK_STATE_MASK (0x7 << 0) |
# define FORCE_SCLK_STATE_SHIFT 0 |
# define FORCE_SCLK_STATE_EN (1 << 3) |
# define GNB_TT(x) ((x) << 8) |
# define GNB_TT_MASK (0xff << 8) |
# define GNB_TT_SHIFT 8 |
# define GNB_THERMTHRO_MASK (1 << 16) |
# define CNB_THERMTHRO_MASK_SCLK (1 << 17) |
# define DPM_SCLK_ENABLE (1 << 18) |
# define GNB_SLOW_FSTATE_0_MASK (1 << 23) |
# define GNB_SLOW_FSTATE_0_SHIFT 23 |
# define FORCE_NB_PSTATE_1 (1 << 31) |
#define CG_SSP 0x6e8 |
# define SST(x) ((x) << 0) |
# define SST_MASK (0xffff << 0) |
# define SST_SHIFT 0 |
# define SSTU(x) ((x) << 16) |
# define SSTU_MASK (0xffff << 16) |
# define SSTU_SHIFT 16 |
#define CG_ACPI_CNTL 0x70c |
# define SCLK_ACPI_DIV(x) ((x) << 0) |
# define SCLK_ACPI_DIV_MASK (0x7f << 0) |
# define SCLK_ACPI_DIV_SHIFT 0 |
#define CG_SCLK_DPM_CTRL_4 0x71c |
# define DC_HDC(x) ((x) << 14) |
# define DC_HDC_MASK (0x3fff << 14) |
# define DC_HDC_SHIFT 14 |
# define DC_HU(x) ((x) << 28) |
# define DC_HU_MASK (0xf << 28) |
# define DC_HU_SHIFT 28 |
#define CG_SCLK_DPM_CTRL_5 0x720 |
# define SCLK_FSTATE_BOOTUP(x) ((x) << 0) |
# define SCLK_FSTATE_BOOTUP_MASK (0x7 << 0) |
# define SCLK_FSTATE_BOOTUP_SHIFT 0 |
# define TT_TP(x) ((x) << 3) |
# define TT_TP_MASK (0xffff << 3) |
# define TT_TP_SHIFT 3 |
# define TT_TU(x) ((x) << 19) |
# define TT_TU_MASK (0xff << 19) |
# define TT_TU_SHIFT 19 |
#define CG_SCLK_DPM_CTRL_6 0x724 |
#define CG_AT_0 0x728 |
# define CG_R(x) ((x) << 0) |
# define CG_R_MASK (0xffff << 0) |
# define CG_R_SHIFT 0 |
# define CG_L(x) ((x) << 16) |
# define CG_L_MASK (0xffff << 16) |
# define CG_L_SHIFT 16 |
#define CG_AT_1 0x72c |
#define CG_AT_2 0x730 |
#define CG_THERMAL_INT 0x734 |
#define DIG_THERM_INTH(x) ((x) << 8) |
#define DIG_THERM_INTH_MASK 0x0000FF00 |
#define DIG_THERM_INTH_SHIFT 8 |
#define DIG_THERM_INTL(x) ((x) << 16) |
#define DIG_THERM_INTL_MASK 0x00FF0000 |
#define DIG_THERM_INTL_SHIFT 16 |
#define THERM_INT_MASK_HIGH (1 << 24) |
#define THERM_INT_MASK_LOW (1 << 25) |
#define CG_AT_3 0x738 |
#define CG_AT_4 0x73c |
#define CG_AT_5 0x740 |
#define CG_AT_6 0x744 |
#define CG_AT_7 0x748 |
#define CG_BSP_0 0x750 |
# define BSP(x) ((x) << 0) |
# define BSP_MASK (0xffff << 0) |
# define BSP_SHIFT 0 |
# define BSU(x) ((x) << 16) |
# define BSU_MASK (0xf << 16) |
# define BSU_SHIFT 16 |
#define CG_CG_VOLTAGE_CNTL 0x770 |
# define REQ (1 << 0) |
# define LEVEL(x) ((x) << 1) |
# define LEVEL_MASK (0x3 << 1) |
# define LEVEL_SHIFT 1 |
# define CG_VOLTAGE_EN (1 << 3) |
# define FORCE (1 << 4) |
# define PERIOD(x) ((x) << 8) |
# define PERIOD_MASK (0xffff << 8) |
# define PERIOD_SHIFT 8 |
# define UNIT(x) ((x) << 24) |
# define UNIT_MASK (0xf << 24) |
# define UNIT_SHIFT 24 |
#define CG_ACPI_VOLTAGE_CNTL 0x780 |
# define ACPI_VOLTAGE_EN (1 << 8) |
#define CG_DPM_VOLTAGE_CNTL 0x788 |
# define DPM_STATE0_LEVEL_MASK (0x3 << 0) |
# define DPM_STATE0_LEVEL_SHIFT 0 |
# define DPM_VOLTAGE_EN (1 << 16) |
#define CG_PWR_GATING_CNTL 0x7ac |
# define DYN_PWR_DOWN_EN (1 << 0) |
# define ACPI_PWR_DOWN_EN (1 << 1) |
# define GFX_CLK_OFF_PWR_DOWN_EN (1 << 2) |
# define IOC_DISGPU_PWR_DOWN_EN (1 << 3) |
# define FORCE_POWR_ON (1 << 4) |
# define PGP(x) ((x) << 8) |
# define PGP_MASK (0xffff << 8) |
# define PGP_SHIFT 8 |
# define PGU(x) ((x) << 24) |
# define PGU_MASK (0xf << 24) |
# define PGU_SHIFT 24 |
#define CG_CGTT_LOCAL_0 0x7d0 |
#define CG_CGTT_LOCAL_1 0x7d4 |
#define DEEP_SLEEP_CNTL 0x818 |
# define R_DIS (1 << 3) |
# define HS(x) ((x) << 4) |
# define HS_MASK (0xfff << 4) |
# define HS_SHIFT 4 |
# define ENABLE_DS (1 << 31) |
#define DEEP_SLEEP_CNTL2 0x81c |
# define LB_UFP_EN (1 << 0) |
# define INOUT_C(x) ((x) << 4) |
# define INOUT_C_MASK (0xff << 4) |
# define INOUT_C_SHIFT 4 |
#define CG_SCRATCH2 0x824 |
#define CG_SCLK_DPM_CTRL_11 0x830 |
#define HW_REV 0x5564 |
# define ATI_REV_ID_MASK (0xf << 28) |
# define ATI_REV_ID_SHIFT 28 |
/* 0 = A0, 1 = A1, 2 = B0, 3 = C0, etc. */ |
#define DOUT_SCRATCH3 0x611c |
#define GB_ADDR_CONFIG 0x98f8 |
#endif |
/drivers/video/drm/radeon/trinity_dpm.c |
---|
0,0 → 1,1993 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "trinityd.h" |
#include "r600_dpm.h" |
#include "trinity_dpm.h" |
#include <linux/seq_file.h> |
#define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5 |
#define TRINITY_MINIMUM_ENGINE_CLOCK 800 |
#define SCLK_MIN_DIV_INTV_SHIFT 12 |
#define TRINITY_DISPCLK_BYPASS_THRESHOLD 10000 |
#ifndef TRINITY_MGCG_SEQUENCE |
#define TRINITY_MGCG_SEQUENCE 100 |
static const u32 trinity_mgcg_shls_default[] = |
{ |
/* Register, Value, Mask */ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x00003fc4, 0xc0000000, 0xffffffff, |
0x00005448, 0x00000100, 0xffffffff, |
0x000055e4, 0x00000100, 0xffffffff, |
0x0000160c, 0x00000100, 0xffffffff, |
0x00008984, 0x06000100, 0xffffffff, |
0x0000c164, 0x00000100, 0xffffffff, |
0x00008a18, 0x00000100, 0xffffffff, |
0x0000897c, 0x06000100, 0xffffffff, |
0x00008b28, 0x00000100, 0xffffffff, |
0x00009144, 0x00800200, 0xffffffff, |
0x00009a60, 0x00000100, 0xffffffff, |
0x00009868, 0x00000100, 0xffffffff, |
0x00008d58, 0x00000100, 0xffffffff, |
0x00009510, 0x00000100, 0xffffffff, |
0x0000949c, 0x00000100, 0xffffffff, |
0x00009654, 0x00000100, 0xffffffff, |
0x00009030, 0x00000100, 0xffffffff, |
0x00009034, 0x00000100, 0xffffffff, |
0x00009038, 0x00000100, 0xffffffff, |
0x0000903c, 0x00000100, 0xffffffff, |
0x00009040, 0x00000100, 0xffffffff, |
0x0000a200, 0x00000100, 0xffffffff, |
0x0000a204, 0x00000100, 0xffffffff, |
0x0000a208, 0x00000100, 0xffffffff, |
0x0000a20c, 0x00000100, 0xffffffff, |
0x00009744, 0x00000100, 0xffffffff, |
0x00003f80, 0x00000100, 0xffffffff, |
0x0000a210, 0x00000100, 0xffffffff, |
0x0000a214, 0x00000100, 0xffffffff, |
0x000004d8, 0x00000100, 0xffffffff, |
0x00009664, 0x00000100, 0xffffffff, |
0x00009698, 0x00000100, 0xffffffff, |
0x000004d4, 0x00000200, 0xffffffff, |
0x000004d0, 0x00000000, 0xffffffff, |
0x000030cc, 0x00000104, 0xffffffff, |
0x0000d0c0, 0x00000100, 0xffffffff, |
0x0000d8c0, 0x00000100, 0xffffffff, |
0x0000951c, 0x00010000, 0xffffffff, |
0x00009160, 0x00030002, 0xffffffff, |
0x00009164, 0x00050004, 0xffffffff, |
0x00009168, 0x00070006, 0xffffffff, |
0x00009178, 0x00070000, 0xffffffff, |
0x0000917c, 0x00030002, 0xffffffff, |
0x00009180, 0x00050004, 0xffffffff, |
0x0000918c, 0x00010006, 0xffffffff, |
0x00009190, 0x00090008, 0xffffffff, |
0x00009194, 0x00070000, 0xffffffff, |
0x00009198, 0x00030002, 0xffffffff, |
0x0000919c, 0x00050004, 0xffffffff, |
0x000091a8, 0x00010006, 0xffffffff, |
0x000091ac, 0x00090008, 0xffffffff, |
0x000091b0, 0x00070000, 0xffffffff, |
0x000091b4, 0x00030002, 0xffffffff, |
0x000091b8, 0x00050004, 0xffffffff, |
0x000091c4, 0x00010006, 0xffffffff, |
0x000091c8, 0x00090008, 0xffffffff, |
0x000091cc, 0x00070000, 0xffffffff, |
0x000091d0, 0x00030002, 0xffffffff, |
0x000091d4, 0x00050004, 0xffffffff, |
0x000091e0, 0x00010006, 0xffffffff, |
0x000091e4, 0x00090008, 0xffffffff, |
0x000091e8, 0x00000000, 0xffffffff, |
0x000091ec, 0x00070000, 0xffffffff, |
0x000091f0, 0x00030002, 0xffffffff, |
0x000091f4, 0x00050004, 0xffffffff, |
0x00009200, 0x00010006, 0xffffffff, |
0x00009204, 0x00090008, 0xffffffff, |
0x00009208, 0x00070000, 0xffffffff, |
0x0000920c, 0x00030002, 0xffffffff, |
0x00009210, 0x00050004, 0xffffffff, |
0x0000921c, 0x00010006, 0xffffffff, |
0x00009220, 0x00090008, 0xffffffff, |
0x00009294, 0x00000000, 0xffffffff |
}; |
static const u32 trinity_mgcg_shls_enable[] = |
{ |
/* Register, Value, Mask */ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0x00000000, 0x000133FF, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0x00000000, 0xE00B03FC, |
0x00009150, 0x96944200, 0xffffffff |
}; |
static const u32 trinity_mgcg_shls_disable[] = |
{ |
/* Register, Value, Mask */ |
0x0000802c, 0xc0000000, 0xffffffff, |
0x00009150, 0x00600000, 0xffffffff, |
0x000008f8, 0x00000000, 0xffffffff, |
0x000008fc, 0xffffffff, 0x000133FF, |
0x000008f8, 0x00000001, 0xffffffff, |
0x000008fc, 0xffffffff, 0xE00B03FC |
}; |
#endif |
#ifndef TRINITY_SYSLS_SEQUENCE |
#define TRINITY_SYSLS_SEQUENCE 100 |
static const u32 trinity_sysls_default[] = |
{ |
/* Register, Value, Mask */ |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x0000d8bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x000020c0, 0x000c0c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x00002f50, 0x00000404, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x0000641c, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00006dfc, 0x00000000, 0xffffffff |
}; |
static const u32 trinity_sysls_disable[] = |
{ |
/* Register, Value, Mask */ |
0x0000d0c0, 0x00000000, 0xffffffff, |
0x0000d8c0, 0x00000000, 0xffffffff, |
0x000055e8, 0x00000000, 0xffffffff, |
0x0000d0bc, 0x00000000, 0xffffffff, |
0x0000d8bc, 0x00000000, 0xffffffff, |
0x000015c0, 0x00041401, 0xffffffff, |
0x0000264c, 0x00040400, 0xffffffff, |
0x00002648, 0x00040400, 0xffffffff, |
0x00002650, 0x00040400, 0xffffffff, |
0x000020b8, 0x00040400, 0xffffffff, |
0x000020bc, 0x00040400, 0xffffffff, |
0x000020c0, 0x00040c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680000, 0xffffffff, |
0x00002f50, 0x00000404, 0xffffffff, |
0x000004c8, 0x00000001, 0xffffffff, |
0x0000641c, 0x00007ffd, 0xffffffff, |
0x00000c7c, 0x0000ff00, 0xffffffff, |
0x00006dfc, 0x0000007f, 0xffffffff |
}; |
static const u32 trinity_sysls_enable[] = |
{ |
/* Register, Value, Mask */ |
0x000055e8, 0x00000001, 0xffffffff, |
0x0000d0bc, 0x00000100, 0xffffffff, |
0x0000d8bc, 0x00000100, 0xffffffff, |
0x000015c0, 0x000c1401, 0xffffffff, |
0x0000264c, 0x000c0400, 0xffffffff, |
0x00002648, 0x000c0400, 0xffffffff, |
0x00002650, 0x000c0400, 0xffffffff, |
0x000020b8, 0x000c0400, 0xffffffff, |
0x000020bc, 0x000c0400, 0xffffffff, |
0x000020c0, 0x000c0c80, 0xffffffff, |
0x0000f4a0, 0x000000c0, 0xffffffff, |
0x0000f4a4, 0x00680fff, 0xffffffff, |
0x00002f50, 0x00000903, 0xffffffff, |
0x000004c8, 0x00000000, 0xffffffff, |
0x0000641c, 0x00000000, 0xffffffff, |
0x00000c7c, 0x00000000, 0xffffffff, |
0x00006dfc, 0x00000000, 0xffffffff |
}; |
#endif |
static const u32 trinity_override_mgpg_sequences[] = |
{ |
/* Register, Value */ |
0x00000200, 0xE030032C, |
0x00000204, 0x00000FFF, |
0x00000200, 0xE0300058, |
0x00000204, 0x00030301, |
0x00000200, 0xE0300054, |
0x00000204, 0x500010FF, |
0x00000200, 0xE0300074, |
0x00000204, 0x00030301, |
0x00000200, 0xE0300070, |
0x00000204, 0x500010FF, |
0x00000200, 0xE0300090, |
0x00000204, 0x00030301, |
0x00000200, 0xE030008C, |
0x00000204, 0x500010FF, |
0x00000200, 0xE03000AC, |
0x00000204, 0x00030301, |
0x00000200, 0xE03000A8, |
0x00000204, 0x500010FF, |
0x00000200, 0xE03000C8, |
0x00000204, 0x00030301, |
0x00000200, 0xE03000C4, |
0x00000204, 0x500010FF, |
0x00000200, 0xE03000E4, |
0x00000204, 0x00030301, |
0x00000200, 0xE03000E0, |
0x00000204, 0x500010FF, |
0x00000200, 0xE0300100, |
0x00000204, 0x00030301, |
0x00000200, 0xE03000FC, |
0x00000204, 0x500010FF, |
0x00000200, 0xE0300058, |
0x00000204, 0x00030303, |
0x00000200, 0xE0300054, |
0x00000204, 0x600010FF, |
0x00000200, 0xE0300074, |
0x00000204, 0x00030303, |
0x00000200, 0xE0300070, |
0x00000204, 0x600010FF, |
0x00000200, 0xE0300090, |
0x00000204, 0x00030303, |
0x00000200, 0xE030008C, |
0x00000204, 0x600010FF, |
0x00000200, 0xE03000AC, |
0x00000204, 0x00030303, |
0x00000200, 0xE03000A8, |
0x00000204, 0x600010FF, |
0x00000200, 0xE03000C8, |
0x00000204, 0x00030303, |
0x00000200, 0xE03000C4, |
0x00000204, 0x600010FF, |
0x00000200, 0xE03000E4, |
0x00000204, 0x00030303, |
0x00000200, 0xE03000E0, |
0x00000204, 0x600010FF, |
0x00000200, 0xE0300100, |
0x00000204, 0x00030303, |
0x00000200, 0xE03000FC, |
0x00000204, 0x600010FF, |
0x00000200, 0xE0300058, |
0x00000204, 0x00030303, |
0x00000200, 0xE0300054, |
0x00000204, 0x700010FF, |
0x00000200, 0xE0300074, |
0x00000204, 0x00030303, |
0x00000200, 0xE0300070, |
0x00000204, 0x700010FF, |
0x00000200, 0xE0300090, |
0x00000204, 0x00030303, |
0x00000200, 0xE030008C, |
0x00000204, 0x700010FF, |
0x00000200, 0xE03000AC, |
0x00000204, 0x00030303, |
0x00000200, 0xE03000A8, |
0x00000204, 0x700010FF, |
0x00000200, 0xE03000C8, |
0x00000204, 0x00030303, |
0x00000200, 0xE03000C4, |
0x00000204, 0x700010FF, |
0x00000200, 0xE03000E4, |
0x00000204, 0x00030303, |
0x00000200, 0xE03000E0, |
0x00000204, 0x700010FF, |
0x00000200, 0xE0300100, |
0x00000204, 0x00030303, |
0x00000200, 0xE03000FC, |
0x00000204, 0x700010FF, |
0x00000200, 0xE0300058, |
0x00000204, 0x00010303, |
0x00000200, 0xE0300054, |
0x00000204, 0x800010FF, |
0x00000200, 0xE0300074, |
0x00000204, 0x00010303, |
0x00000200, 0xE0300070, |
0x00000204, 0x800010FF, |
0x00000200, 0xE0300090, |
0x00000204, 0x00010303, |
0x00000200, 0xE030008C, |
0x00000204, 0x800010FF, |
0x00000200, 0xE03000AC, |
0x00000204, 0x00010303, |
0x00000200, 0xE03000A8, |
0x00000204, 0x800010FF, |
0x00000200, 0xE03000C4, |
0x00000204, 0x800010FF, |
0x00000200, 0xE03000C8, |
0x00000204, 0x00010303, |
0x00000200, 0xE03000E4, |
0x00000204, 0x00010303, |
0x00000200, 0xE03000E0, |
0x00000204, 0x800010FF, |
0x00000200, 0xE0300100, |
0x00000204, 0x00010303, |
0x00000200, 0xE03000FC, |
0x00000204, 0x800010FF, |
0x00000200, 0x0001f198, |
0x00000204, 0x0003ffff, |
0x00000200, 0x0001f19C, |
0x00000204, 0x3fffffff, |
0x00000200, 0xE030032C, |
0x00000204, 0x00000000, |
}; |
static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev, |
const u32 *seq, u32 count); |
static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev); |
static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps); |
static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps) |
{ |
struct trinity_ps *ps = rps->ps_priv; |
return ps; |
} |
static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = rdev->pm.dpm.priv; |
return pi; |
} |
static void trinity_gfx_powergating_initialize(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 p, u; |
u32 value; |
struct atom_clock_dividers dividers; |
u32 xclk = radeon_get_xclk(rdev); |
u32 sssd = 1; |
int ret; |
u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
25000, false, ÷rs); |
if (ret) |
return; |
value = RREG32_SMC(GFX_POWER_GATING_CNTL); |
value &= ~(SSSD_MASK | PDS_DIV_MASK); |
if (sssd) |
value |= SSSD(1); |
value |= PDS_DIV(dividers.post_div); |
WREG32_SMC(GFX_POWER_GATING_CNTL, value); |
r600_calculate_u_and_p(500, xclk, 16, &p, &u); |
WREG32(CG_PG_CTRL, SP(p) | SU(u)); |
WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK); |
/* XXX double check hw_rev */ |
if (pi->override_dynamic_mgpg && (hw_rev == 0)) |
trinity_override_dynamic_mg_powergating(rdev); |
} |
#define CGCG_CGTT_LOCAL0_MASK 0xFFFF33FF |
#define CGCG_CGTT_LOCAL1_MASK 0xFFFB0FFE |
#define CGTS_SM_CTRL_REG_DISABLE 0x00600000 |
#define CGTS_SM_CTRL_REG_ENABLE 0x96944200 |
static void trinity_mg_clockgating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 local0; |
u32 local1; |
if (enable) { |
local0 = RREG32_CG(CG_CGTT_LOCAL_0); |
local1 = RREG32_CG(CG_CGTT_LOCAL_1); |
WREG32_CG(CG_CGTT_LOCAL_0, |
(0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) ); |
WREG32_CG(CG_CGTT_LOCAL_1, |
(0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) ); |
WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE); |
} else { |
WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE); |
local0 = RREG32_CG(CG_CGTT_LOCAL_0); |
local1 = RREG32_CG(CG_CGTT_LOCAL_1); |
WREG32_CG(CG_CGTT_LOCAL_0, |
CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) ); |
WREG32_CG(CG_CGTT_LOCAL_1, |
CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) ); |
} |
} |
static void trinity_mg_clockgating_initialize(struct radeon_device *rdev) |
{ |
u32 count; |
const u32 *seq = NULL; |
seq = &trinity_mgcg_shls_default[0]; |
count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32)); |
trinity_program_clk_gating_hw_sequence(rdev, seq, count); |
} |
static void trinity_gfx_clockgating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) { |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); |
} else { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); |
WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); |
RREG32(GB_ADDR_CONFIG); |
} |
} |
static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev, |
const u32 *seq, u32 count) |
{ |
u32 i, length = count * 3; |
for (i = 0; i < length; i += 3) |
WREG32_P(seq[i], seq[i+1], ~seq[i+2]); |
} |
static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev, |
const u32 *seq, u32 count) |
{ |
u32 i, length = count * 2; |
for (i = 0; i < length; i += 2) |
WREG32(seq[i], seq[i+1]); |
} |
static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev) |
{ |
u32 count; |
const u32 *seq = NULL; |
seq = &trinity_override_mgpg_sequences[0]; |
count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32)); |
trinity_program_override_mgpg_sequences(rdev, seq, count); |
} |
static void trinity_ls_clockgating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 count; |
const u32 *seq = NULL; |
if (enable) { |
seq = &trinity_sysls_enable[0]; |
count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32)); |
} else { |
seq = &trinity_sysls_disable[0]; |
count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32)); |
} |
trinity_program_clk_gating_hw_sequence(rdev, seq, count); |
} |
static void trinity_gfx_powergating_enable(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) { |
if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK) |
WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01)); |
WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN); |
} else { |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN); |
RREG32(GB_ADDR_CONFIG); |
} |
} |
static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev, |
bool enable) |
{ |
u32 value; |
if (enable) { |
value = RREG32_SMC(PM_I_CNTL_1); |
value &= ~DS_PG_CNTL_MASK; |
value |= DS_PG_CNTL(1); |
WREG32_SMC(PM_I_CNTL_1, value); |
value = RREG32_SMC(SMU_S_PG_CNTL); |
value &= ~DS_PG_EN_MASK; |
value |= DS_PG_EN(1); |
WREG32_SMC(SMU_S_PG_CNTL, value); |
} else { |
value = RREG32_SMC(SMU_S_PG_CNTL); |
value &= ~DS_PG_EN_MASK; |
WREG32_SMC(SMU_S_PG_CNTL, value); |
value = RREG32_SMC(PM_I_CNTL_1); |
value &= ~DS_PG_CNTL_MASK; |
WREG32_SMC(PM_I_CNTL_1, value); |
} |
trinity_gfx_dynamic_mgpg_config(rdev); |
} |
static void trinity_enable_clock_power_gating(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
if (pi->enable_gfx_clock_gating) |
sumo_gfx_clockgating_initialize(rdev); |
if (pi->enable_mg_clock_gating) |
trinity_mg_clockgating_initialize(rdev); |
if (pi->enable_gfx_power_gating) |
trinity_gfx_powergating_initialize(rdev); |
if (pi->enable_mg_clock_gating) { |
trinity_ls_clockgating_enable(rdev, true); |
trinity_mg_clockgating_enable(rdev, true); |
} |
if (pi->enable_gfx_clock_gating) |
trinity_gfx_clockgating_enable(rdev, true); |
if (pi->enable_gfx_dynamic_mgpg) |
trinity_gfx_dynamic_mgpg_enable(rdev, true); |
if (pi->enable_gfx_power_gating) |
trinity_gfx_powergating_enable(rdev, true); |
} |
static void trinity_disable_clock_power_gating(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
if (pi->enable_gfx_power_gating) |
trinity_gfx_powergating_enable(rdev, false); |
if (pi->enable_gfx_dynamic_mgpg) |
trinity_gfx_dynamic_mgpg_enable(rdev, false); |
if (pi->enable_gfx_clock_gating) |
trinity_gfx_clockgating_enable(rdev, false); |
if (pi->enable_mg_clock_gating) { |
trinity_mg_clockgating_enable(rdev, false); |
trinity_ls_clockgating_enable(rdev, false); |
} |
} |
static void trinity_set_divider_value(struct radeon_device *rdev, |
u32 index, u32 sclk) |
{ |
struct atom_clock_dividers dividers; |
int ret; |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
sclk, false, ÷rs); |
if (ret) |
return; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix); |
value &= ~CLK_DIVIDER_MASK; |
value |= CLK_DIVIDER(dividers.post_div); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value); |
ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, |
sclk/2, false, ÷rs); |
if (ret) |
return; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix); |
value &= ~PD_SCLK_DIVIDER_MASK; |
value |= PD_SCLK_DIVIDER(dividers.post_div); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value); |
} |
static void trinity_set_ds_dividers(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix); |
value &= ~DS_DIV_MASK; |
value |= DS_DIV(divider); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value); |
} |
static void trinity_set_ss_dividers(struct radeon_device *rdev, |
u32 index, u32 divider) |
{ |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix); |
value &= ~DS_SH_DIV_MASK; |
value |= DS_SH_DIV(divider); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value); |
} |
static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid); |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix); |
value &= ~VID_MASK; |
value |= VID(vid_7bit); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value); |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix); |
value &= ~LVRT_MASK; |
value |= LVRT(0); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value); |
} |
static void trinity_set_allos_gnb_slow(struct radeon_device *rdev, |
u32 index, u32 gnb_slow) |
{ |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix); |
value &= ~GNB_SLOW_MASK; |
value |= GNB_SLOW(gnb_slow); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value); |
} |
static void trinity_set_force_nbp_state(struct radeon_device *rdev, |
u32 index, u32 force_nbp_state) |
{ |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix); |
value &= ~FORCE_NBPS1_MASK; |
value |= FORCE_NBPS1(force_nbp_state); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value); |
} |
static void trinity_set_display_wm(struct radeon_device *rdev, |
u32 index, u32 wm) |
{ |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix); |
value &= ~DISPLAY_WM_MASK; |
value |= DISPLAY_WM(wm); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value); |
} |
static void trinity_set_vce_wm(struct radeon_device *rdev, |
u32 index, u32 wm) |
{ |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix); |
value &= ~VCE_WM_MASK; |
value |= VCE_WM(wm); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value); |
} |
static void trinity_set_at(struct radeon_device *rdev, |
u32 index, u32 at) |
{ |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix); |
value &= ~AT_MASK; |
value |= AT(at); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value); |
} |
static void trinity_program_power_level(struct radeon_device *rdev, |
struct trinity_pl *pl, u32 index) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
if (index >= SUMO_MAX_HARDWARE_POWERLEVELS) |
return; |
trinity_set_divider_value(rdev, index, pl->sclk); |
trinity_set_vid(rdev, index, pl->vddc_index); |
trinity_set_ss_dividers(rdev, index, pl->ss_divider_index); |
trinity_set_ds_dividers(rdev, index, pl->ds_divider_index); |
trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow); |
trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state); |
trinity_set_display_wm(rdev, index, pl->display_wm); |
trinity_set_vce_wm(rdev, index, pl->vce_wm); |
trinity_set_at(rdev, index, pi->at[index]); |
} |
static void trinity_power_level_enable_disable(struct radeon_device *rdev, |
u32 index, bool enable) |
{ |
u32 value; |
u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE; |
value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix); |
value &= ~STATE_VALID_MASK; |
if (enable) |
value |= STATE_VALID(1); |
WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value); |
} |
static bool trinity_dpm_enabled(struct radeon_device *rdev) |
{ |
if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1)) |
return true; |
else |
return false; |
} |
static void trinity_start_dpm(struct radeon_device *rdev) |
{ |
u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL); |
value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK); |
value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1); |
WREG32_SMC(SMU_SCLK_DPM_CNTL, value); |
WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN); |
WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN); |
trinity_dpm_config(rdev, true); |
} |
static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0) |
break; |
udelay(1); |
} |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0) |
break; |
udelay(1); |
} |
} |
static void trinity_stop_dpm(struct radeon_device *rdev) |
{ |
u32 sclk_dpm_cntl; |
WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN); |
sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL); |
sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK); |
WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl); |
trinity_dpm_config(rdev, false); |
} |
static void trinity_start_am(struct radeon_device *rdev) |
{ |
WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT)); |
} |
static void trinity_reset_am(struct radeon_device *rdev) |
{ |
WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT, |
~(RESET_SCLK_CNT | RESET_BUSY_CNT)); |
} |
static void trinity_wait_for_level_0(struct radeon_device *rdev) |
{ |
int i; |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0) |
break; |
udelay(1); |
} |
} |
static void trinity_enable_power_level_0(struct radeon_device *rdev) |
{ |
trinity_power_level_enable_disable(rdev, 0, true); |
} |
static void trinity_force_level_0(struct radeon_device *rdev) |
{ |
trinity_dpm_force_state(rdev, 0); |
} |
static void trinity_unforce_levels(struct radeon_device *rdev) |
{ |
trinity_dpm_no_forced_level(rdev); |
} |
static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct trinity_ps *new_ps = trinity_get_ps(new_rps); |
struct trinity_ps *old_ps = trinity_get_ps(old_rps); |
u32 i; |
u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels; |
for (i = 0; i < new_ps->num_levels; i++) { |
trinity_program_power_level(rdev, &new_ps->levels[i], i); |
trinity_power_level_enable_disable(rdev, i, true); |
} |
for (i = new_ps->num_levels; i < n_current_state_levels; i++) |
trinity_power_level_enable_disable(rdev, i, false); |
} |
static void trinity_program_bootup_state(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 i; |
trinity_program_power_level(rdev, &pi->boot_pl, 0); |
trinity_power_level_enable_disable(rdev, 0, true); |
for (i = 1; i < 8; i++) |
trinity_power_level_enable_disable(rdev, i, false); |
} |
static void trinity_setup_uvd_clock_table(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct trinity_ps *ps = trinity_get_ps(rps); |
u32 uvdstates = (ps->vclk_low_divider | |
ps->vclk_high_divider << 8 | |
ps->dclk_low_divider << 16 | |
ps->dclk_high_divider << 24); |
WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates); |
} |
static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev, |
u32 interval) |
{ |
u32 p, u; |
u32 tp = RREG32_SMC(PM_TP); |
u32 val; |
u32 xclk = radeon_get_xclk(rdev); |
r600_calculate_u_and_p(interval, xclk, 16, &p, &u); |
val = (p + tp - 1) / tp; |
WREG32_SMC(SMU_UVD_DPM_CNTL, val); |
} |
static bool trinity_uvd_clocks_zero(struct radeon_ps *rps) |
{ |
if ((rps->vclk == 0) && (rps->dclk == 0)) |
return true; |
else |
return false; |
} |
static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1, |
struct radeon_ps *rps2) |
{ |
struct trinity_ps *ps1 = trinity_get_ps(rps1); |
struct trinity_ps *ps2 = trinity_get_ps(rps2); |
if ((rps1->vclk == rps2->vclk) && |
(rps1->dclk == rps2->dclk) && |
(ps1->vclk_low_divider == ps2->vclk_low_divider) && |
(ps1->vclk_high_divider == ps2->vclk_high_divider) && |
(ps1->dclk_low_divider == ps2->dclk_low_divider) && |
(ps1->dclk_high_divider == ps2->dclk_high_divider)) |
return true; |
else |
return false; |
} |
static void trinity_setup_uvd_clocks(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
if (pi->enable_gfx_power_gating) { |
trinity_gfx_powergating_enable(rdev, false); |
} |
if (pi->uvd_dpm) { |
if (trinity_uvd_clocks_zero(new_rps) && |
!trinity_uvd_clocks_zero(old_rps)) { |
trinity_setup_uvd_dpm_interval(rdev, 0); |
} else if (!trinity_uvd_clocks_zero(new_rps)) { |
trinity_setup_uvd_clock_table(rdev, new_rps); |
if (trinity_uvd_clocks_zero(old_rps)) { |
u32 tmp = RREG32(CG_MISC_REG); |
tmp &= 0xfffffffd; |
WREG32(CG_MISC_REG, tmp); |
radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk); |
trinity_setup_uvd_dpm_interval(rdev, 3000); |
} |
} |
trinity_uvd_dpm_config(rdev); |
} else { |
if (trinity_uvd_clocks_zero(new_rps) || |
trinity_uvd_clocks_equal(new_rps, old_rps)) |
return; |
radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk); |
} |
if (pi->enable_gfx_power_gating) { |
trinity_gfx_powergating_enable(rdev, true); |
} |
} |
static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct trinity_ps *new_ps = trinity_get_ps(new_rps); |
struct trinity_ps *current_ps = trinity_get_ps(new_rps); |
if (new_ps->levels[new_ps->num_levels - 1].sclk >= |
current_ps->levels[current_ps->num_levels - 1].sclk) |
return; |
trinity_setup_uvd_clocks(rdev, new_rps, old_rps); |
} |
static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct trinity_ps *new_ps = trinity_get_ps(new_rps); |
struct trinity_ps *current_ps = trinity_get_ps(old_rps); |
if (new_ps->levels[new_ps->num_levels - 1].sclk < |
current_ps->levels[current_ps->num_levels - 1].sclk) |
return; |
trinity_setup_uvd_clocks(rdev, new_rps, old_rps); |
} |
static void trinity_program_ttt(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT); |
value &= ~(HT_MASK | LT_MASK); |
value |= HT((pi->thermal_auto_throttling + 49) * 8); |
value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8); |
WREG32_SMC(SMU_SCLK_DPM_TTT, value); |
} |
static void trinity_enable_att(struct radeon_device *rdev) |
{ |
u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL); |
value &= ~SCLK_TT_EN_MASK; |
value |= SCLK_TT_EN(1); |
WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value); |
} |
static void trinity_program_sclk_dpm(struct radeon_device *rdev) |
{ |
u32 p, u; |
u32 tp = RREG32_SMC(PM_TP); |
u32 ni; |
u32 xclk = radeon_get_xclk(rdev); |
u32 value; |
r600_calculate_u_and_p(400, xclk, 16, &p, &u); |
ni = (p + tp - 1) / tp; |
value = RREG32_SMC(PM_I_CNTL_1); |
value &= ~SCLK_DPM_MASK; |
value |= SCLK_DPM(ni); |
WREG32_SMC(PM_I_CNTL_1, value); |
} |
static int trinity_set_thermal_temperature_range(struct radeon_device *rdev, |
int min_temp, int max_temp) |
{ |
int low_temp = 0 * 1000; |
int high_temp = 255 * 1000; |
if (low_temp < min_temp) |
low_temp = min_temp; |
if (high_temp > max_temp) |
high_temp = max_temp; |
if (high_temp < low_temp) { |
DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); |
return -EINVAL; |
} |
WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK); |
WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK); |
rdev->pm.dpm.thermal.min_temp = low_temp; |
rdev->pm.dpm.thermal.max_temp = high_temp; |
return 0; |
} |
static void trinity_update_current_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct trinity_ps *new_ps = trinity_get_ps(rps); |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
pi->current_rps = *rps; |
pi->current_ps = *new_ps; |
pi->current_rps.ps_priv = &pi->current_ps; |
} |
static void trinity_update_requested_ps(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct trinity_ps *new_ps = trinity_get_ps(rps); |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
pi->requested_rps = *rps; |
pi->requested_ps = *new_ps; |
pi->requested_rps.ps_priv = &pi->requested_ps; |
} |
void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
if (pi->enable_bapm) { |
trinity_acquire_mutex(rdev); |
trinity_dpm_bapm_enable(rdev, enable); |
trinity_release_mutex(rdev); |
} |
} |
int trinity_dpm_enable(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
trinity_acquire_mutex(rdev); |
if (trinity_dpm_enabled(rdev)) { |
trinity_release_mutex(rdev); |
return -EINVAL; |
} |
trinity_program_bootup_state(rdev); |
sumo_program_vc(rdev, 0x00C00033); |
trinity_start_am(rdev); |
if (pi->enable_auto_thermal_throttling) { |
trinity_program_ttt(rdev); |
trinity_enable_att(rdev); |
} |
trinity_program_sclk_dpm(rdev); |
trinity_start_dpm(rdev); |
trinity_wait_for_dpm_enabled(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); |
if (ret) { |
trinity_release_mutex(rdev); |
return ret; |
} |
rdev->irq.dpm_thermal = true; |
radeon_irq_set(rdev); |
} |
trinity_release_mutex(rdev); |
return 0; |
} |
void trinity_dpm_disable(struct radeon_device *rdev) |
{ |
trinity_acquire_mutex(rdev); |
if (!trinity_dpm_enabled(rdev)) { |
trinity_release_mutex(rdev); |
return; |
} |
trinity_dpm_bapm_enable(rdev, false); |
trinity_disable_clock_power_gating(rdev); |
sumo_clear_vc(rdev); |
trinity_wait_for_level_0(rdev); |
trinity_stop_dpm(rdev); |
trinity_reset_am(rdev); |
trinity_release_mutex(rdev); |
if (rdev->irq.installed && |
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { |
rdev->irq.dpm_thermal = false; |
radeon_irq_set(rdev); |
} |
trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps); |
} |
static void trinity_get_min_sclk_divider(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
pi->min_sclk_did = |
(RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT; |
} |
static void trinity_setup_nbp_sim(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
struct trinity_ps *new_ps = trinity_get_ps(rps); |
u32 nbpsconfig; |
if (pi->sys_info.nb_dpm_enable) { |
nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG); |
nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK); |
nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) | |
Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) | |
DpmXNbPsLo(new_ps->DpmXNbPsLo) | |
DpmXNbPsHi(new_ps->DpmXNbPsHi)); |
WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig); |
} |
} |
int trinity_dpm_force_performance_level(struct radeon_device *rdev, |
enum radeon_dpm_forced_level level) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
struct radeon_ps *rps = &pi->current_rps; |
struct trinity_ps *ps = trinity_get_ps(rps); |
int i, ret; |
if (ps->num_levels <= 1) |
return 0; |
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { |
/* not supported by the hw */ |
return -EINVAL; |
} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { |
ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1); |
if (ret) |
return ret; |
} else { |
for (i = 0; i < ps->num_levels; i++) { |
ret = trinity_dpm_n_levels_disabled(rdev, 0); |
if (ret) |
return ret; |
} |
} |
rdev->pm.dpm.forced_level = level; |
return 0; |
} |
int trinity_dpm_pre_set_power_state(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; |
struct radeon_ps *new_ps = &requested_ps; |
trinity_update_requested_ps(rdev, new_ps); |
trinity_apply_state_adjust_rules(rdev, |
&pi->requested_rps, |
&pi->current_rps); |
return 0; |
} |
int trinity_dpm_set_power_state(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
struct radeon_ps *new_ps = &pi->requested_rps; |
struct radeon_ps *old_ps = &pi->current_rps; |
trinity_acquire_mutex(rdev); |
if (pi->enable_dpm) { |
if (pi->enable_bapm) |
trinity_dpm_bapm_enable(rdev, rdev->pm.dpm.ac_power); |
trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); |
trinity_enable_power_level_0(rdev); |
trinity_force_level_0(rdev); |
trinity_wait_for_level_0(rdev); |
trinity_setup_nbp_sim(rdev, new_ps); |
trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps); |
trinity_force_level_0(rdev); |
trinity_unforce_levels(rdev); |
trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
} |
trinity_release_mutex(rdev); |
return 0; |
} |
void trinity_dpm_post_set_power_state(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
struct radeon_ps *new_ps = &pi->requested_rps; |
trinity_update_current_ps(rdev, new_ps); |
} |
void trinity_dpm_setup_asic(struct radeon_device *rdev) |
{ |
trinity_acquire_mutex(rdev); |
sumo_program_sstp(rdev); |
sumo_take_smu_control(rdev, true); |
trinity_get_min_sclk_divider(rdev); |
trinity_release_mutex(rdev); |
} |
void trinity_dpm_reset_asic(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
trinity_acquire_mutex(rdev); |
if (pi->enable_dpm) { |
trinity_enable_power_level_0(rdev); |
trinity_force_level_0(rdev); |
trinity_wait_for_level_0(rdev); |
trinity_program_bootup_state(rdev); |
trinity_force_level_0(rdev); |
trinity_unforce_levels(rdev); |
} |
trinity_release_mutex(rdev); |
} |
static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev, |
u32 vid_2bit) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit); |
u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0; |
u32 step = (svi_mode == 0) ? 1250 : 625; |
u32 delta = vid_7bit * step + 50; |
if (delta > 155000) |
return 0; |
return (155000 - delta) / 100; |
} |
static void trinity_patch_boot_state(struct radeon_device *rdev, |
struct trinity_ps *ps) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
ps->num_levels = 1; |
ps->nbps_flags = 0; |
ps->bapm_flags = 0; |
ps->levels[0] = pi->boot_pl; |
} |
static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk) |
{ |
if (sclk < 20000) |
return 1; |
return 0; |
} |
static void trinity_construct_boot_state(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
pi->boot_pl.sclk = pi->sys_info.bootup_sclk; |
pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index; |
pi->boot_pl.ds_divider_index = 0; |
pi->boot_pl.ss_divider_index = 0; |
pi->boot_pl.allow_gnb_slow = 1; |
pi->boot_pl.force_nbp_state = 0; |
pi->boot_pl.display_wm = 0; |
pi->boot_pl.vce_wm = 0; |
pi->current_ps.num_levels = 1; |
pi->current_ps.levels[0] = pi->boot_pl; |
} |
static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev, |
u32 sclk, u32 min_sclk_in_sr) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 i; |
u32 temp; |
u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ? |
min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK; |
if (sclk < min) |
return 0; |
if (!pi->enable_sclk_ds) |
return 0; |
for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) { |
temp = sclk / sumo_get_sleep_divider_from_id(i); |
if (temp >= min || i == 0) |
break; |
} |
return (u8)i; |
} |
static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev, |
u32 lower_limit) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 i; |
for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) { |
if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit) |
return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency; |
} |
if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries) |
DRM_ERROR("engine clock out of range!"); |
return 0; |
} |
static void trinity_patch_thermal_state(struct radeon_device *rdev, |
struct trinity_ps *ps, |
struct trinity_ps *current_ps) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ |
u32 current_vddc; |
u32 current_sclk; |
u32 current_index = 0; |
if (current_ps) { |
current_vddc = current_ps->levels[current_index].vddc_index; |
current_sclk = current_ps->levels[current_index].sclk; |
} else { |
current_vddc = pi->boot_pl.vddc_index; |
current_sclk = pi->boot_pl.sclk; |
} |
ps->levels[0].vddc_index = current_vddc; |
if (ps->levels[0].sclk > current_sclk) |
ps->levels[0].sclk = current_sclk; |
ps->levels[0].ds_divider_index = |
trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr); |
ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index; |
ps->levels[0].allow_gnb_slow = 1; |
ps->levels[0].force_nbp_state = 0; |
ps->levels[0].display_wm = 0; |
ps->levels[0].vce_wm = |
trinity_calculate_vce_wm(rdev, ps->levels[0].sclk); |
} |
static u8 trinity_calculate_display_wm(struct radeon_device *rdev, |
struct trinity_ps *ps, u32 index) |
{ |
if (ps == NULL || ps->num_levels <= 1) |
return 0; |
else if (ps->num_levels == 2) { |
if (index == 0) |
return 0; |
else |
return 1; |
} else { |
if (index == 0) |
return 0; |
else if (ps->levels[index].sclk < 30000) |
return 0; |
else |
return 1; |
} |
} |
static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 i = 0; |
for (i = 0; i < 4; i++) { |
if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) && |
(rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk)) |
break; |
} |
if (i >= 4) { |
DRM_ERROR("UVD clock index not found!\n"); |
i = 3; |
} |
return i; |
} |
static void trinity_adjust_uvd_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
struct trinity_ps *ps = trinity_get_ps(rps); |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 high_index = 0; |
u32 low_index = 0; |
if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) { |
high_index = trinity_get_uvd_clock_index(rdev, rps); |
switch(high_index) { |
case 3: |
case 2: |
low_index = 1; |
break; |
case 1: |
case 0: |
default: |
low_index = 0; |
break; |
} |
ps->vclk_low_divider = |
pi->sys_info.uvd_clock_table_entries[high_index].vclk_did; |
ps->dclk_low_divider = |
pi->sys_info.uvd_clock_table_entries[high_index].dclk_did; |
ps->vclk_high_divider = |
pi->sys_info.uvd_clock_table_entries[low_index].vclk_did; |
ps->dclk_high_divider = |
pi->sys_info.uvd_clock_table_entries[low_index].dclk_did; |
} |
} |
static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, |
struct radeon_ps *new_rps, |
struct radeon_ps *old_rps) |
{ |
struct trinity_ps *ps = trinity_get_ps(new_rps); |
struct trinity_ps *current_ps = trinity_get_ps(old_rps); |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 min_voltage = 0; /* ??? */ |
u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */ |
u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ |
u32 i; |
bool force_high; |
u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count; |
if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) |
return trinity_patch_thermal_state(rdev, ps, current_ps); |
trinity_adjust_uvd_state(rdev, new_rps); |
for (i = 0; i < ps->num_levels; i++) { |
if (ps->levels[i].vddc_index < min_voltage) |
ps->levels[i].vddc_index = min_voltage; |
if (ps->levels[i].sclk < min_sclk) |
ps->levels[i].sclk = |
trinity_get_valid_engine_clock(rdev, min_sclk); |
ps->levels[i].ds_divider_index = |
sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr); |
ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index; |
ps->levels[i].allow_gnb_slow = 1; |
ps->levels[i].force_nbp_state = 0; |
ps->levels[i].display_wm = |
trinity_calculate_display_wm(rdev, ps, i); |
ps->levels[i].vce_wm = |
trinity_calculate_vce_wm(rdev, ps->levels[0].sclk); |
} |
if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) || |
((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) |
ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE; |
if (pi->sys_info.nb_dpm_enable) { |
ps->Dpm0PgNbPsLo = 0x1; |
ps->Dpm0PgNbPsHi = 0x0; |
ps->DpmXNbPsLo = 0x2; |
ps->DpmXNbPsHi = 0x1; |
if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) || |
((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) { |
force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) || |
((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) && |
(pi->sys_info.uma_channel_number == 1))); |
force_high = (num_active_displays >= 3) || force_high; |
ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3; |
ps->Dpm0PgNbPsHi = 0x1; |
ps->DpmXNbPsLo = force_high ? 0x2 : 0x3; |
ps->DpmXNbPsHi = 0x2; |
ps->levels[ps->num_levels - 1].allow_gnb_slow = 0; |
} |
} |
} |
static void trinity_cleanup_asic(struct radeon_device *rdev) |
{ |
sumo_take_smu_control(rdev, false); |
} |
#if 0 |
static void trinity_pre_display_configuration_change(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
if (pi->voltage_drop_in_dce) |
trinity_dce_enable_voltage_adjustment(rdev, false); |
} |
#endif |
static void trinity_add_dccac_value(struct radeon_device *rdev) |
{ |
u32 gpu_cac_avrg_cntl_window_size; |
u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count; |
u64 disp_clk = rdev->clock.default_dispclk / 100; |
u32 dc_cac_value; |
gpu_cac_avrg_cntl_window_size = |
(RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT; |
dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >> |
(32 - gpu_cac_avrg_cntl_window_size)); |
WREG32_SMC(DC_CAC_VALUE, dc_cac_value); |
} |
void trinity_dpm_display_configuration_changed(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
if (pi->voltage_drop_in_dce) |
trinity_dce_enable_voltage_adjustment(rdev, true); |
trinity_add_dccac_value(rdev); |
} |
union power_info { |
struct _ATOM_POWERPLAY_INFO info; |
struct _ATOM_POWERPLAY_INFO_V2 info_2; |
struct _ATOM_POWERPLAY_INFO_V3 info_3; |
struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; |
struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; |
}; |
union pplib_clock_info { |
struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; |
}; |
union pplib_power_state { |
struct _ATOM_PPLIB_STATE v1; |
struct _ATOM_PPLIB_STATE_V2 v2; |
}; |
static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, |
u8 table_rev) |
{ |
struct trinity_ps *ps = trinity_get_ps(rps); |
rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); |
rps->class = le16_to_cpu(non_clock_info->usClassification); |
rps->class2 = le16_to_cpu(non_clock_info->usClassification2); |
if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { |
rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); |
rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); |
} else { |
rps->vclk = 0; |
rps->dclk = 0; |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { |
rdev->pm.dpm.boot_ps = rps; |
trinity_patch_boot_state(rdev, ps); |
} |
if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) |
rdev->pm.dpm.uvd_ps = rps; |
} |
static void trinity_parse_pplib_clock_info(struct radeon_device *rdev, |
struct radeon_ps *rps, int index, |
union pplib_clock_info *clock_info) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
struct trinity_ps *ps = trinity_get_ps(rps); |
struct trinity_pl *pl = &ps->levels[index]; |
u32 sclk; |
sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); |
sclk |= clock_info->sumo.ucEngineClockHigh << 16; |
pl->sclk = sclk; |
pl->vddc_index = clock_info->sumo.vddcIndex; |
ps->num_levels = index + 1; |
if (pi->enable_sclk_ds) { |
pl->ds_divider_index = 5; |
pl->ss_divider_index = 5; |
} |
} |
static int trinity_parse_power_table(struct radeon_device *rdev) |
{ |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; |
union pplib_power_state *power_state; |
int i, j, k, non_clock_array_index, clock_array_index; |
union pplib_clock_info *clock_info; |
struct _StateArray *state_array; |
struct _ClockInfoArray *clock_info_array; |
struct _NonClockInfoArray *non_clock_info_array; |
union power_info *power_info; |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
u8 *power_state_offset; |
struct sumo_ps *ps; |
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); |
state_array = (struct _StateArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usStateArrayOffset)); |
clock_info_array = (struct _ClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); |
non_clock_info_array = (struct _NonClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); |
rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * |
state_array->ucNumEntries, GFP_KERNEL); |
if (!rdev->pm.dpm.ps) |
return -ENOMEM; |
power_state_offset = (u8 *)state_array->states; |
for (i = 0; i < state_array->ucNumEntries; i++) { |
u8 *idx; |
power_state = (union pplib_power_state *)power_state_offset; |
non_clock_array_index = power_state->v2.nonClockInfoIndex; |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
&non_clock_info_array->nonClockInfo[non_clock_array_index]; |
if (!rdev->pm.power_state[i].clock_info) |
return -EINVAL; |
ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL); |
if (ps == NULL) { |
kfree(rdev->pm.dpm.ps); |
return -ENOMEM; |
} |
rdev->pm.dpm.ps[i].ps_priv = ps; |
k = 0; |
idx = (u8 *)&power_state->v2.clockInfoIndex[0]; |
for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { |
clock_array_index = idx[j]; |
if (clock_array_index >= clock_info_array->ucNumEntries) |
continue; |
if (k >= SUMO_MAX_HARDWARE_POWERLEVELS) |
break; |
clock_info = (union pplib_clock_info *) |
((u8 *)&clock_info_array->clockInfo[0] + |
(clock_array_index * clock_info_array->ucEntrySize)); |
trinity_parse_pplib_clock_info(rdev, |
&rdev->pm.dpm.ps[i], k, |
clock_info); |
k++; |
} |
trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], |
non_clock_info, |
non_clock_info_array->ucEntrySize); |
power_state_offset += 2 + power_state->v2.ucNumDPMLevels; |
} |
rdev->pm.dpm.num_ps = state_array->ucNumEntries; |
return 0; |
} |
union igp_info { |
struct _ATOM_INTEGRATED_SYSTEM_INFO info; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; |
struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; |
}; |
static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
u32 divider; |
if (did >= 8 && did <= 0x3f) |
divider = did * 25; |
else if (did > 0x3f && did <= 0x5f) |
divider = (did - 64) * 50 + 1600; |
else if (did > 0x5f && did <= 0x7e) |
divider = (did - 96) * 100 + 3200; |
else if (did == 0x7f) |
divider = 128 * 100; |
else |
return 10000; |
return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider; |
} |
static int trinity_parse_sys_info_table(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
struct radeon_mode_info *mode_info = &rdev->mode_info; |
int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); |
union igp_info *igp_info; |
u8 frev, crev; |
u16 data_offset; |
int i; |
if (atom_parse_data_header(mode_info->atom_context, index, NULL, |
&frev, &crev, &data_offset)) { |
igp_info = (union igp_info *)(mode_info->atom_context->bios + |
data_offset); |
if (crev != 7) { |
DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); |
return -EINVAL; |
} |
pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock); |
pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock); |
pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock); |
pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq); |
pi->sys_info.bootup_nb_voltage_index = |
le16_to_cpu(igp_info->info_7.usBootUpNBVoltage); |
if (igp_info->info_7.ucHtcTmpLmt == 0) |
pi->sys_info.htc_tmp_lmt = 203; |
else |
pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt; |
if (igp_info->info_7.ucHtcHystLmt == 0) |
pi->sys_info.htc_hyst_lmt = 5; |
else |
pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt; |
if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { |
DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); |
} |
if (pi->enable_nbps_policy) |
pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable; |
else |
pi->sys_info.nb_dpm_enable = 0; |
for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) { |
pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]); |
pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]); |
} |
pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage); |
pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage); |
pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage); |
pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage); |
if (!pi->sys_info.nb_dpm_enable) { |
for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) { |
pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0]; |
pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0]; |
pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0]; |
} |
} |
pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber; |
sumo_construct_sclk_voltage_mapping_table(rdev, |
&pi->sys_info.sclk_voltage_mapping_table, |
igp_info->info_7.sAvail_SCLK); |
sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table, |
igp_info->info_7.sAvail_SCLK); |
pi->sys_info.uvd_clock_table_entries[0].vclk_did = |
igp_info->info_7.ucDPMState0VclkFid; |
pi->sys_info.uvd_clock_table_entries[1].vclk_did = |
igp_info->info_7.ucDPMState1VclkFid; |
pi->sys_info.uvd_clock_table_entries[2].vclk_did = |
igp_info->info_7.ucDPMState2VclkFid; |
pi->sys_info.uvd_clock_table_entries[3].vclk_did = |
igp_info->info_7.ucDPMState3VclkFid; |
pi->sys_info.uvd_clock_table_entries[0].dclk_did = |
igp_info->info_7.ucDPMState0DclkFid; |
pi->sys_info.uvd_clock_table_entries[1].dclk_did = |
igp_info->info_7.ucDPMState1DclkFid; |
pi->sys_info.uvd_clock_table_entries[2].dclk_did = |
igp_info->info_7.ucDPMState2DclkFid; |
pi->sys_info.uvd_clock_table_entries[3].dclk_did = |
igp_info->info_7.ucDPMState3DclkFid; |
for (i = 0; i < 4; i++) { |
pi->sys_info.uvd_clock_table_entries[i].vclk = |
trinity_convert_did_to_freq(rdev, |
pi->sys_info.uvd_clock_table_entries[i].vclk_did); |
pi->sys_info.uvd_clock_table_entries[i].dclk = |
trinity_convert_did_to_freq(rdev, |
pi->sys_info.uvd_clock_table_entries[i].dclk_did); |
} |
} |
return 0; |
} |
int trinity_dpm_init(struct radeon_device *rdev) |
{ |
struct trinity_power_info *pi; |
int ret, i; |
pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL); |
if (pi == NULL) |
return -ENOMEM; |
rdev->pm.dpm.priv = pi; |
for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) |
pi->at[i] = TRINITY_AT_DFLT; |
if (radeon_bapm == -1) { |
/* 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; |
} else if (radeon_bapm == 0) { |
pi->enable_bapm = false; |
} else { |
pi->enable_bapm = true; |
} |
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 = 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; /* ??? */ |
ret = trinity_parse_sys_info_table(rdev); |
if (ret) |
return ret; |
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; |
pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt; |
pi->enable_dpm = true; |
return 0; |
} |
void trinity_dpm_print_power_state(struct radeon_device *rdev, |
struct radeon_ps *rps) |
{ |
int i; |
struct trinity_ps *ps = trinity_get_ps(rps); |
r600_dpm_print_class_info(rps->class, rps->class2); |
r600_dpm_print_cap_info(rps->caps); |
printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
for (i = 0; i < ps->num_levels; i++) { |
struct trinity_pl *pl = &ps->levels[i]; |
printk("\t\tpower level %d sclk: %u vddc: %u\n", |
i, pl->sclk, |
trinity_convert_voltage_index_to_value(rdev, pl->vddc_index)); |
} |
r600_dpm_print_ps_status(rdev, rps); |
} |
void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, |
struct seq_file *m) |
{ |
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 = |
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >> |
CURRENT_STATE_SHIFT; |
if (current_index >= ps->num_levels) { |
seq_printf(m, "invalid dpm profile %d\n", current_index); |
} else { |
pl = &ps->levels[current_index]; |
seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); |
seq_printf(m, "power level %d sclk: %u vddc: %u\n", |
current_index, pl->sclk, |
trinity_convert_voltage_index_to_value(rdev, pl->vddc_index)); |
} |
} |
void trinity_dpm_fini(struct radeon_device *rdev) |
{ |
int i; |
trinity_cleanup_asic(rdev); /* ??? */ |
for (i = 0; i < rdev->pm.dpm.num_ps; i++) { |
kfree(rdev->pm.dpm.ps[i].ps_priv); |
} |
kfree(rdev->pm.dpm.ps); |
kfree(rdev->pm.dpm.priv); |
} |
u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps); |
if (low) |
return requested_state->levels[0].sclk; |
else |
return requested_state->levels[requested_state->num_levels - 1].sclk; |
} |
u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low) |
{ |
struct trinity_power_info *pi = trinity_get_pi(rdev); |
return pi->sys_info.bootup_uma_clk; |
} |
/drivers/video/drm/radeon/trinity_dpm.h |
---|
0,0 → 1,134 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#ifndef __TRINITY_DPM_H__ |
#define __TRINITY_DPM_H__ |
#include "sumo_dpm.h" |
#define TRINITY_SIZEOF_DPM_STATE_TABLE (SMU_SCLK_DPM_STATE_1_CNTL_0 - SMU_SCLK_DPM_STATE_0_CNTL_0) |
struct trinity_pl { |
u32 sclk; |
u8 vddc_index; |
u8 ds_divider_index; |
u8 ss_divider_index; |
u8 allow_gnb_slow; |
u8 force_nbp_state; |
u8 display_wm; |
u8 vce_wm; |
}; |
#define TRINITY_POWERSTATE_FLAGS_NBPS_FORCEHIGH (1 << 0) |
#define TRINITY_POWERSTATE_FLAGS_NBPS_LOCKTOHIGH (1 << 1) |
#define TRINITY_POWERSTATE_FLAGS_NBPS_LOCKTOLOW (1 << 2) |
#define TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE (1 << 0) |
struct trinity_ps { |
u32 num_levels; |
struct trinity_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS]; |
u32 nbps_flags; |
u32 bapm_flags; |
u8 Dpm0PgNbPsLo; |
u8 Dpm0PgNbPsHi; |
u8 DpmXNbPsLo; |
u8 DpmXNbPsHi; |
u32 vclk_low_divider; |
u32 vclk_high_divider; |
u32 dclk_low_divider; |
u32 dclk_high_divider; |
}; |
#define TRINITY_NUM_NBPSTATES 4 |
struct trinity_uvd_clock_table_entry |
{ |
u32 vclk; |
u32 dclk; |
u8 vclk_did; |
u8 dclk_did; |
u8 rsv[2]; |
}; |
struct trinity_sys_info { |
u32 bootup_uma_clk; |
u32 bootup_sclk; |
u32 min_sclk; |
u32 dentist_vco_freq; |
u32 nb_dpm_enable; |
u32 nbp_mclk[TRINITY_NUM_NBPSTATES]; |
u32 nbp_nclk[TRINITY_NUM_NBPSTATES]; |
u16 nbp_voltage_index[TRINITY_NUM_NBPSTATES]; |
u16 bootup_nb_voltage_index; |
u8 htc_tmp_lmt; |
u8 htc_hyst_lmt; |
struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table; |
struct sumo_vid_mapping_table vid_mapping_table; |
u32 uma_channel_number; |
struct trinity_uvd_clock_table_entry uvd_clock_table_entries[4]; |
}; |
struct trinity_power_info { |
u32 at[SUMO_MAX_HARDWARE_POWERLEVELS]; |
u32 dpm_interval; |
u32 thermal_auto_throttling; |
struct trinity_sys_info sys_info; |
struct trinity_pl boot_pl; |
u32 min_sclk_did; |
bool enable_nbps_policy; |
bool voltage_drop_in_dce; |
bool override_dynamic_mgpg; |
bool enable_gfx_clock_gating; |
bool enable_gfx_power_gating; |
bool enable_mg_clock_gating; |
bool enable_gfx_dynamic_mgpg; |
bool enable_auto_thermal_throttling; |
bool enable_dpm; |
bool enable_sclk_ds; |
bool enable_bapm; |
bool uvd_dpm; |
struct radeon_ps current_rps; |
struct trinity_ps current_ps; |
struct radeon_ps requested_rps; |
struct trinity_ps requested_ps; |
}; |
#define TRINITY_AT_DFLT 30 |
/* trinity_smc.c */ |
int trinity_dpm_bapm_enable(struct radeon_device *rdev, bool enable); |
int trinity_dpm_config(struct radeon_device *rdev, bool enable); |
int trinity_uvd_dpm_config(struct radeon_device *rdev); |
int trinity_dpm_force_state(struct radeon_device *rdev, u32 n); |
int trinity_dpm_n_levels_disabled(struct radeon_device *rdev, u32 n); |
int trinity_dpm_no_forced_level(struct radeon_device *rdev); |
int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev, |
bool enable); |
int trinity_gfx_dynamic_mgpg_config(struct radeon_device *rdev); |
void trinity_acquire_mutex(struct radeon_device *rdev); |
void trinity_release_mutex(struct radeon_device *rdev); |
#endif |
/drivers/video/drm/radeon/trinity_smc.c |
---|
0,0 → 1,127 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
#include "drmP.h" |
#include "radeon.h" |
#include "trinityd.h" |
#include "trinity_dpm.h" |
#include "ppsmc.h" |
static int trinity_notify_message_to_smu(struct radeon_device *rdev, u32 id) |
{ |
int i; |
u32 v = 0; |
WREG32(SMC_MESSAGE_0, id); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if (RREG32(SMC_RESP_0) != 0) |
break; |
udelay(1); |
} |
v = RREG32(SMC_RESP_0); |
if (v != 1) { |
if (v == 0xFF) { |
DRM_ERROR("SMC failed to handle the message!\n"); |
return -EINVAL; |
} else if (v == 0xFE) { |
DRM_ERROR("Unknown SMC message!\n"); |
return -EINVAL; |
} |
} |
return 0; |
} |
int trinity_dpm_bapm_enable(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_EnableBAPM); |
else |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DisableBAPM); |
} |
int trinity_dpm_config(struct radeon_device *rdev, bool enable) |
{ |
if (enable) |
WREG32_SMC(SMU_SCRATCH0, 1); |
else |
WREG32_SMC(SMU_SCRATCH0, 0); |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Config); |
} |
int trinity_dpm_force_state(struct radeon_device *rdev, u32 n) |
{ |
WREG32_SMC(SMU_SCRATCH0, n); |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_ForceState); |
} |
int trinity_dpm_n_levels_disabled(struct radeon_device *rdev, u32 n) |
{ |
WREG32_SMC(SMU_SCRATCH0, n); |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_N_LevelsDisabled); |
} |
int trinity_uvd_dpm_config(struct radeon_device *rdev) |
{ |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_UVD_DPM_Config); |
} |
int trinity_dpm_no_forced_level(struct radeon_device *rdev) |
{ |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel); |
} |
int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev, |
bool enable) |
{ |
if (enable) |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DCE_AllowVoltageAdjustment); |
else |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DCE_RemoveVoltageAdjustment); |
} |
int trinity_gfx_dynamic_mgpg_config(struct radeon_device *rdev) |
{ |
return trinity_notify_message_to_smu(rdev, PPSMC_MSG_PG_SIMD_Config); |
} |
void trinity_acquire_mutex(struct radeon_device *rdev) |
{ |
int i; |
WREG32(SMC_INT_REQ, 1); |
for (i = 0; i < rdev->usec_timeout; i++) { |
if ((RREG32(SMC_INT_REQ) & 0xffff) == 1) |
break; |
udelay(1); |
} |
} |
void trinity_release_mutex(struct radeon_device *rdev) |
{ |
WREG32(SMC_INT_REQ, 0); |
} |
/drivers/video/drm/radeon/trinityd.h |
---|
0,0 → 1,228 |
/* |
* Copyright 2012 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Alex Deucher |
*/ |
#ifndef _TRINITYD_H_ |
#define _TRINITYD_H_ |
/* pm registers */ |
/* cg */ |
#define CG_CGTT_LOCAL_0 0x0 |
#define CG_CGTT_LOCAL_1 0x1 |
/* smc */ |
#define SMU_SCLK_DPM_STATE_0_CNTL_0 0x1f000 |
# define STATE_VALID(x) ((x) << 0) |
# define STATE_VALID_MASK (0xff << 0) |
# define STATE_VALID_SHIFT 0 |
# define CLK_DIVIDER(x) ((x) << 8) |
# define CLK_DIVIDER_MASK (0xff << 8) |
# define CLK_DIVIDER_SHIFT 8 |
# define VID(x) ((x) << 16) |
# define VID_MASK (0xff << 16) |
# define VID_SHIFT 16 |
# define LVRT(x) ((x) << 24) |
# define LVRT_MASK (0xff << 24) |
# define LVRT_SHIFT 24 |
#define SMU_SCLK_DPM_STATE_0_CNTL_1 0x1f004 |
# define DS_DIV(x) ((x) << 0) |
# define DS_DIV_MASK (0xff << 0) |
# define DS_DIV_SHIFT 0 |
# define DS_SH_DIV(x) ((x) << 8) |
# define DS_SH_DIV_MASK (0xff << 8) |
# define DS_SH_DIV_SHIFT 8 |
# define DISPLAY_WM(x) ((x) << 16) |
# define DISPLAY_WM_MASK (0xff << 16) |
# define DISPLAY_WM_SHIFT 16 |
# define VCE_WM(x) ((x) << 24) |
# define VCE_WM_MASK (0xff << 24) |
# define VCE_WM_SHIFT 24 |
#define SMU_SCLK_DPM_STATE_0_CNTL_3 0x1f00c |
# define GNB_SLOW(x) ((x) << 0) |
# define GNB_SLOW_MASK (0xff << 0) |
# define GNB_SLOW_SHIFT 0 |
# define FORCE_NBPS1(x) ((x) << 8) |
# define FORCE_NBPS1_MASK (0xff << 8) |
# define FORCE_NBPS1_SHIFT 8 |
#define SMU_SCLK_DPM_STATE_0_AT 0x1f010 |
# define AT(x) ((x) << 0) |
# define AT_MASK (0xff << 0) |
# define AT_SHIFT 0 |
#define SMU_SCLK_DPM_STATE_0_PG_CNTL 0x1f014 |
# define PD_SCLK_DIVIDER(x) ((x) << 16) |
# define PD_SCLK_DIVIDER_MASK (0xff << 16) |
# define PD_SCLK_DIVIDER_SHIFT 16 |
#define SMU_SCLK_DPM_STATE_1_CNTL_0 0x1f020 |
#define SMU_SCLK_DPM_CNTL 0x1f100 |
# define SCLK_DPM_EN(x) ((x) << 0) |
# define SCLK_DPM_EN_MASK (0xff << 0) |
# define SCLK_DPM_EN_SHIFT 0 |
# define SCLK_DPM_BOOT_STATE(x) ((x) << 16) |
# define SCLK_DPM_BOOT_STATE_MASK (0xff << 16) |
# define SCLK_DPM_BOOT_STATE_SHIFT 16 |
# define VOLTAGE_CHG_EN(x) ((x) << 24) |
# define VOLTAGE_CHG_EN_MASK (0xff << 24) |
# define VOLTAGE_CHG_EN_SHIFT 24 |
#define SMU_SCLK_DPM_TT_CNTL 0x1f108 |
# define SCLK_TT_EN(x) ((x) << 0) |
# define SCLK_TT_EN_MASK (0xff << 0) |
# define SCLK_TT_EN_SHIFT 0 |
#define SMU_SCLK_DPM_TTT 0x1f10c |
# define LT(x) ((x) << 0) |
# define LT_MASK (0xffff << 0) |
# define LT_SHIFT 0 |
# define HT(x) ((x) << 16) |
# define HT_MASK (0xffff << 16) |
# define HT_SHIFT 16 |
#define SMU_UVD_DPM_STATES 0x1f1a0 |
#define SMU_UVD_DPM_CNTL 0x1f1a4 |
#define SMU_S_PG_CNTL 0x1f118 |
# define DS_PG_EN(x) ((x) << 16) |
# define DS_PG_EN_MASK (0xff << 16) |
# define DS_PG_EN_SHIFT 16 |
#define GFX_POWER_GATING_CNTL 0x1f38c |
# define PDS_DIV(x) ((x) << 0) |
# define PDS_DIV_MASK (0xff << 0) |
# define PDS_DIV_SHIFT 0 |
# define SSSD(x) ((x) << 8) |
# define SSSD_MASK (0xff << 8) |
# define SSSD_SHIFT 8 |
#define PM_CONFIG 0x1f428 |
# define SVI_Mode (1 << 29) |
#define PM_I_CNTL_1 0x1f464 |
# define SCLK_DPM(x) ((x) << 0) |
# define SCLK_DPM_MASK (0xff << 0) |
# define SCLK_DPM_SHIFT 0 |
# define DS_PG_CNTL(x) ((x) << 16) |
# define DS_PG_CNTL_MASK (0xff << 16) |
# define DS_PG_CNTL_SHIFT 16 |
#define PM_TP 0x1f468 |
#define NB_PSTATE_CONFIG 0x1f5f8 |
# define Dpm0PgNbPsLo(x) ((x) << 0) |
# define Dpm0PgNbPsLo_MASK (3 << 0) |
# define Dpm0PgNbPsLo_SHIFT 0 |
# define Dpm0PgNbPsHi(x) ((x) << 2) |
# define Dpm0PgNbPsHi_MASK (3 << 2) |
# define Dpm0PgNbPsHi_SHIFT 2 |
# define DpmXNbPsLo(x) ((x) << 4) |
# define DpmXNbPsLo_MASK (3 << 4) |
# define DpmXNbPsLo_SHIFT 4 |
# define DpmXNbPsHi(x) ((x) << 6) |
# define DpmXNbPsHi_MASK (3 << 6) |
# define DpmXNbPsHi_SHIFT 6 |
#define DC_CAC_VALUE 0x1f908 |
#define GPU_CAC_AVRG_CNTL 0x1f920 |
# define WINDOW_SIZE(x) ((x) << 0) |
# define WINDOW_SIZE_MASK (0xff << 0) |
# define WINDOW_SIZE_SHIFT 0 |
#define CC_SMU_MISC_FUSES 0xe0001004 |
# define MinSClkDid(x) ((x) << 2) |
# define MinSClkDid_MASK (0x7f << 2) |
# define MinSClkDid_SHIFT 2 |
#define CC_SMU_TST_EFUSE1_MISC 0xe000101c |
# define RB_BACKEND_DISABLE(x) ((x) << 16) |
# define RB_BACKEND_DISABLE_MASK (3 << 16) |
# define RB_BACKEND_DISABLE_SHIFT 16 |
#define SMU_SCRATCH_A 0xe0003024 |
#define SMU_SCRATCH0 0xe0003040 |
/* mmio */ |
#define SMC_INT_REQ 0x220 |
#define SMC_MESSAGE_0 0x22c |
#define SMC_RESP_0 0x230 |
#define GENERAL_PWRMGT 0x670 |
# define GLOBAL_PWRMGT_EN (1 << 0) |
#define SCLK_PWRMGT_CNTL 0x678 |
# define DYN_PWR_DOWN_EN (1 << 2) |
# define RESET_BUSY_CNT (1 << 4) |
# define RESET_SCLK_CNT (1 << 5) |
# define DYN_GFX_CLK_OFF_EN (1 << 7) |
# define GFX_CLK_FORCE_ON (1 << 8) |
# define DYNAMIC_PM_EN (1 << 21) |
#define TARGET_AND_CURRENT_PROFILE_INDEX 0x684 |
# define TARGET_STATE(x) ((x) << 0) |
# define TARGET_STATE_MASK (0xf << 0) |
# define TARGET_STATE_SHIFT 0 |
# define CURRENT_STATE(x) ((x) << 4) |
# define CURRENT_STATE_MASK (0xf << 4) |
# define CURRENT_STATE_SHIFT 4 |
#define CG_GIPOTS 0x6d8 |
# define CG_GIPOT(x) ((x) << 16) |
# define CG_GIPOT_MASK (0xffff << 16) |
# define CG_GIPOT_SHIFT 16 |
#define CG_PG_CTRL 0x6e0 |
# define SP(x) ((x) << 0) |
# define SP_MASK (0xffff << 0) |
# define SP_SHIFT 0 |
# define SU(x) ((x) << 16) |
# define SU_MASK (0xffff << 16) |
# define SU_SHIFT 16 |
#define CG_MISC_REG 0x708 |
#define CG_THERMAL_INT_CTRL 0x738 |
# define DIG_THERM_INTH(x) ((x) << 0) |
# define DIG_THERM_INTH_MASK (0xff << 0) |
# define DIG_THERM_INTH_SHIFT 0 |
# define DIG_THERM_INTL(x) ((x) << 8) |
# define DIG_THERM_INTL_MASK (0xff << 8) |
# define DIG_THERM_INTL_SHIFT 8 |
# define THERM_INTH_MASK (1 << 24) |
# define THERM_INTL_MASK (1 << 25) |
#define CG_CG_VOLTAGE_CNTL 0x770 |
# define EN (1 << 9) |
#define HW_REV 0x5564 |
# define ATI_REV_ID_MASK (0xf << 28) |
# define ATI_REV_ID_SHIFT 28 |
/* 0 = A0, 1 = A1, 2 = B0, 3 = C0, etc. */ |
#define CGTS_SM_CTRL_REG 0x9150 |
#define GB_ADDR_CONFIG 0x98f8 |
#endif |
/drivers/video/drm/radeon/utils.c |
---|
0,0 → 1,452 |
#include <ddk.h> |
#include <linux/mm.h> |
#include <linux/err.h> |
#include <drm/drmP.h> |
#include <linux/hdmi.h> |
int x86_clflush_size; |
unsigned int tsc_khz; |
struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags) |
{ |
struct file *filep; |
int count; |
filep = malloc(sizeof(*filep)); |
if(unlikely(filep == NULL)) |
return ERR_PTR(-ENOMEM); |
count = size / PAGE_SIZE; |
filep->pages = kzalloc(sizeof(struct page *) * count, 0); |
if(unlikely(filep->pages == NULL)) |
{ |
kfree(filep); |
return ERR_PTR(-ENOMEM); |
}; |
filep->count = count; |
filep->allocated = 0; |
filep->vma = NULL; |
// printf("%s file %p pages %p count %d\n", |
// __FUNCTION__,filep, filep->pages, count); |
return filep; |
} |
static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) |
{ |
while (bytes) { |
if (*start != value) |
return (void *)start; |
start++; |
bytes--; |
} |
return NULL; |
} |
/** |
* memchr_inv - Find an unmatching character in an area of memory. |
* @start: The memory area |
* @c: Find a character other than c |
* @bytes: The size of the area. |
* |
* returns the address of the first character other than @c, or %NULL |
* if the whole buffer contains just @c. |
*/ |
void *memchr_inv(const void *start, int c, size_t bytes) |
{ |
u8 value = c; |
u64 value64; |
unsigned int words, prefix; |
if (bytes <= 16) |
return check_bytes8(start, value, bytes); |
value64 = value; |
#if defined(ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64 |
value64 *= 0x0101010101010101; |
#elif defined(ARCH_HAS_FAST_MULTIPLIER) |
value64 *= 0x01010101; |
value64 |= value64 << 32; |
#else |
value64 |= value64 << 8; |
value64 |= value64 << 16; |
value64 |= value64 << 32; |
#endif |
prefix = (unsigned long)start % 8; |
if (prefix) { |
u8 *r; |
prefix = 8 - prefix; |
r = check_bytes8(start, value, prefix); |
if (r) |
return r; |
start += prefix; |
bytes -= prefix; |
} |
words = bytes / 8; |
while (words) { |
if (*(u64 *)start != value64) |
return check_bytes8(start, value, 8); |
start += 8; |
words--; |
} |
return check_bytes8(start, value, bytes % 8); |
} |
#define _U 0x01 /* upper */ |
#define _L 0x02 /* lower */ |
#define _D 0x04 /* digit */ |
#define _C 0x08 /* cntrl */ |
#define _P 0x10 /* punct */ |
#define _S 0x20 /* white space (space/lf/tab) */ |
#define _X 0x40 /* hex digit */ |
#define _SP 0x80 /* hard space (0x20) */ |
extern const unsigned char _ctype[]; |
#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) |
#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) |
#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) |
#define iscntrl(c) ((__ismask(c)&(_C)) != 0) |
#define isdigit(c) ((__ismask(c)&(_D)) != 0) |
#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) |
#define islower(c) ((__ismask(c)&(_L)) != 0) |
#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) |
#define ispunct(c) ((__ismask(c)&(_P)) != 0) |
/* Note: isspace() must return false for %NUL-terminator */ |
#define isspace(c) ((__ismask(c)&(_S)) != 0) |
#define isupper(c) ((__ismask(c)&(_U)) != 0) |
#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) |
#define isascii(c) (((unsigned char)(c))<=0x7f) |
#define toascii(c) (((unsigned char)(c))&0x7f) |
static inline unsigned char __tolower(unsigned char c) |
{ |
if (isupper(c)) |
c -= 'A'-'a'; |
return c; |
} |
static inline unsigned char __toupper(unsigned char c) |
{ |
if (islower(c)) |
c -= 'a'-'A'; |
return c; |
} |
#define tolower(c) __tolower(c) |
#define toupper(c) __toupper(c) |
/* |
* Fast implementation of tolower() for internal usage. Do not use in your |
* code. |
*/ |
static inline char _tolower(const char c) |
{ |
return c | 0x20; |
} |
//const char hex_asc[] = "0123456789abcdef"; |
/** |
* hex_to_bin - convert a hex digit to its real value |
* @ch: ascii character represents hex digit |
* |
* hex_to_bin() converts one hex digit to its actual value or -1 in case of bad |
* input. |
*/ |
int hex_to_bin(char ch) |
{ |
if ((ch >= '0') && (ch <= '9')) |
return ch - '0'; |
ch = tolower(ch); |
if ((ch >= 'a') && (ch <= 'f')) |
return ch - 'a' + 10; |
return -1; |
} |
EXPORT_SYMBOL(hex_to_bin); |
/** |
* hex2bin - convert an ascii hexadecimal string to its binary representation |
* @dst: binary result |
* @src: ascii hexadecimal string |
* @count: result length |
* |
* Return 0 on success, -1 in case of bad input. |
*/ |
int hex2bin(u8 *dst, const char *src, size_t count) |
{ |
while (count--) { |
int hi = hex_to_bin(*src++); |
int lo = hex_to_bin(*src++); |
if ((hi < 0) || (lo < 0)) |
return -1; |
*dst++ = (hi << 4) | lo; |
} |
return 0; |
} |
EXPORT_SYMBOL(hex2bin); |
/** |
* hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory |
* @buf: data blob to dump |
* @len: number of bytes in the @buf |
* @rowsize: number of bytes to print per line; must be 16 or 32 |
* @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) |
* @linebuf: where to put the converted data |
* @linebuflen: total size of @linebuf, including space for terminating NUL |
* @ascii: include ASCII after the hex output |
* |
* hex_dump_to_buffer() works on one "line" of output at a time, i.e., |
* 16 or 32 bytes of input data converted to hex + ASCII output. |
* |
* Given a buffer of u8 data, hex_dump_to_buffer() converts the input data |
* to a hex + ASCII dump at the supplied memory location. |
* The converted output is always NUL-terminated. |
* |
* E.g.: |
* hex_dump_to_buffer(frame->data, frame->len, 16, 1, |
* linebuf, sizeof(linebuf), true); |
* |
* example output buffer: |
* 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO |
*/ |
void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, |
int groupsize, char *linebuf, size_t linebuflen, |
bool ascii) |
{ |
const u8 *ptr = buf; |
u8 ch; |
int j, lx = 0; |
int ascii_column; |
if (rowsize != 16 && rowsize != 32) |
rowsize = 16; |
if (!len) |
goto nil; |
if (len > rowsize) /* limit to one line at a time */ |
len = rowsize; |
if ((len % groupsize) != 0) /* no mixed size output */ |
groupsize = 1; |
switch (groupsize) { |
case 8: { |
const u64 *ptr8 = buf; |
int ngroups = len / groupsize; |
for (j = 0; j < ngroups; j++) |
lx += scnprintf(linebuf + lx, linebuflen - lx, |
"%s%16.16llx", j ? " " : "", |
(unsigned long long)*(ptr8 + j)); |
ascii_column = 17 * ngroups + 2; |
break; |
} |
case 4: { |
const u32 *ptr4 = buf; |
int ngroups = len / groupsize; |
for (j = 0; j < ngroups; j++) |
lx += scnprintf(linebuf + lx, linebuflen - lx, |
"%s%8.8x", j ? " " : "", *(ptr4 + j)); |
ascii_column = 9 * ngroups + 2; |
break; |
} |
case 2: { |
const u16 *ptr2 = buf; |
int ngroups = len / groupsize; |
for (j = 0; j < ngroups; j++) |
lx += scnprintf(linebuf + lx, linebuflen - lx, |
"%s%4.4x", j ? " " : "", *(ptr2 + j)); |
ascii_column = 5 * ngroups + 2; |
break; |
} |
default: |
for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) { |
ch = ptr[j]; |
linebuf[lx++] = hex_asc_hi(ch); |
linebuf[lx++] = hex_asc_lo(ch); |
linebuf[lx++] = ' '; |
} |
if (j) |
lx--; |
ascii_column = 3 * rowsize + 2; |
break; |
} |
if (!ascii) |
goto nil; |
while (lx < (linebuflen - 1) && lx < (ascii_column - 1)) |
linebuf[lx++] = ' '; |
for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) { |
ch = ptr[j]; |
linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; |
} |
nil: |
linebuf[lx++] = '\0'; |
} |
/** |
* print_hex_dump - print a text hex dump to syslog for a binary blob of data |
* @level: kernel log level (e.g. KERN_DEBUG) |
* @prefix_str: string to prefix each line with; |
* caller supplies trailing spaces for alignment if desired |
* @prefix_type: controls whether prefix of an offset, address, or none |
* is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) |
* @rowsize: number of bytes to print per line; must be 16 or 32 |
* @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) |
* @buf: data blob to dump |
* @len: number of bytes in the @buf |
* @ascii: include ASCII after the hex output |
* |
* Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump |
* to the kernel log at the specified kernel log level, with an optional |
* leading prefix. |
* |
* print_hex_dump() works on one "line" of output at a time, i.e., |
* 16 or 32 bytes of input data converted to hex + ASCII output. |
* print_hex_dump() iterates over the entire input @buf, breaking it into |
* "line size" chunks to format and print. |
* |
* E.g.: |
* print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS, |
* 16, 1, frame->data, frame->len, true); |
* |
* Example output using %DUMP_PREFIX_OFFSET and 1-byte mode: |
* 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO |
* Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: |
* ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. |
*/ |
void print_hex_dump(const char *level, const char *prefix_str, int prefix_type, |
int rowsize, int groupsize, |
const void *buf, size_t len, bool ascii) |
{ |
const u8 *ptr = buf; |
int i, linelen, remaining = len; |
unsigned char linebuf[32 * 3 + 2 + 32 + 1]; |
if (rowsize != 16 && rowsize != 32) |
rowsize = 16; |
for (i = 0; i < len; i += rowsize) { |
linelen = min(remaining, rowsize); |
remaining -= rowsize; |
hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, |
linebuf, sizeof(linebuf), ascii); |
switch (prefix_type) { |
case DUMP_PREFIX_ADDRESS: |
printk("%s%s%p: %s\n", |
level, prefix_str, ptr + i, linebuf); |
break; |
case DUMP_PREFIX_OFFSET: |
printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf); |
break; |
default: |
printk("%s%s%s\n", level, prefix_str, linebuf); |
break; |
} |
} |
} |
void print_hex_dump_bytes(const char *prefix_str, int prefix_type, |
const void *buf, size_t len) |
{ |
print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1, |
buf, len, true); |
} |
static inline void __cpuid(unsigned int *eax, unsigned int *ebx, |
unsigned int *ecx, unsigned int *edx) |
{ |
/* ecx is often an input as well as an output. */ |
asm volatile("cpuid" |
: "=a" (*eax), |
"=b" (*ebx), |
"=c" (*ecx), |
"=d" (*edx) |
: "0" (*eax), "2" (*ecx) |
: "memory"); |
} |
static inline void cpuid(unsigned int op, |
unsigned int *eax, unsigned int *ebx, |
unsigned int *ecx, unsigned int *edx) |
{ |
*eax = op; |
*ecx = 0; |
__cpuid(eax, ebx, ecx, edx); |
} |
void cpu_detect() |
{ |
u32 junk, tfms, cap0, misc; |
cpuid(0x00000001, &tfms, &misc, &junk, &cap0); |
if (cap0 & (1<<19)) |
{ |
x86_clflush_size = ((misc >> 8) & 0xff) * 8; |
} |
tsc_khz = GetCpuFreq()/1000; |
} |
void *kmemdup(const void *src, size_t len, gfp_t gfp) |
{ |
void *p; |
p = kmalloc(len, gfp); |
if (p) |
memcpy(p, src, len); |
return p; |
} |
unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) |
{ |
const unsigned long *p = addr; |
unsigned long result = 0; |
unsigned long tmp; |
while (size & ~(BITS_PER_LONG-1)) { |
if (~(tmp = *(p++))) |
goto found; |
result += BITS_PER_LONG; |
size -= BITS_PER_LONG; |
} |
if (!size) |
return result; |
tmp = (*p) | (~0UL << size); |
if (tmp == ~0UL) /* Are any bits zero? */ |
return result + size; /* Nope. */ |
found: |
return result + ffz(tmp); |
} |
/drivers/video/drm/radeon/uvd_v1_0.c |
---|
0,0 → 1,444 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Christian König <christian.koenig@amd.com> |
*/ |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "radeon_asic.h" |
#include "r600d.h" |
/** |
* uvd_v1_0_get_rptr - get read pointer |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring pointer |
* |
* Returns the current hardware read pointer |
*/ |
uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
return RREG32(UVD_RBC_RB_RPTR); |
} |
/** |
* uvd_v1_0_get_wptr - get write pointer |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring pointer |
* |
* Returns the current hardware write pointer |
*/ |
uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
return RREG32(UVD_RBC_RB_WPTR); |
} |
/** |
* uvd_v1_0_set_wptr - set write pointer |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring pointer |
* |
* Commits the write pointer to the hardware |
*/ |
void uvd_v1_0_set_wptr(struct radeon_device *rdev, |
struct radeon_ring *ring) |
{ |
WREG32(UVD_RBC_RB_WPTR, ring->wptr); |
} |
/** |
* uvd_v1_0_init - start and test UVD block |
* |
* @rdev: radeon_device pointer |
* |
* Initialize the hardware, boot up the VCPU and do some testing |
*/ |
int uvd_v1_0_init(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
uint32_t tmp; |
int r; |
/* raise clocks while booting up the VCPU */ |
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) |
goto done; |
ring->ready = true; |
r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring); |
if (r) { |
ring->ready = false; |
goto done; |
} |
r = radeon_ring_lock(rdev, ring, 10); |
if (r) { |
DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r); |
goto done; |
} |
tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0); |
radeon_ring_write(ring, tmp); |
radeon_ring_write(ring, 0xFFFFF); |
tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0); |
radeon_ring_write(ring, tmp); |
radeon_ring_write(ring, 0xFFFFF); |
tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0); |
radeon_ring_write(ring, tmp); |
radeon_ring_write(ring, 0xFFFFF); |
/* Clear timeout status bits */ |
radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0)); |
radeon_ring_write(ring, 0x8); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0)); |
radeon_ring_write(ring, 3); |
radeon_ring_unlock_commit(rdev, ring, false); |
done: |
/* lower clocks again */ |
radeon_set_uvd_clocks(rdev, 0, 0); |
if (!r) |
DRM_INFO("UVD initialized successfully.\n"); |
return r; |
} |
/** |
* uvd_v1_0_fini - stop the hardware block |
* |
* @rdev: radeon_device pointer |
* |
* Stop the UVD block, mark ring as not ready any more |
*/ |
void uvd_v1_0_fini(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
uvd_v1_0_stop(rdev); |
ring->ready = false; |
} |
/** |
* uvd_v1_0_start - start UVD block |
* |
* @rdev: radeon_device pointer |
* |
* Setup and start the UVD block |
*/ |
int uvd_v1_0_start(struct radeon_device *rdev) |
{ |
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; |
uint32_t rb_bufsz; |
int i, j, r; |
/* disable byte swapping */ |
u32 lmi_swap_cntl = 0; |
u32 mp_swap_cntl = 0; |
/* disable clock gating */ |
WREG32(UVD_CGC_GATE, 0); |
/* disable interupt */ |
WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1)); |
/* Stall UMC and register bus before resetting VCPU */ |
WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); |
WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); |
mdelay(1); |
/* put LMI, VCPU, RBC etc... into reset */ |
WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET | |
LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET | |
CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET); |
mdelay(5); |
/* take UVD block out of reset */ |
WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD); |
mdelay(5); |
/* initialize UVD memory controller */ |
WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) | |
(1 << 21) | (1 << 9) | (1 << 20)); |
#ifdef __BIG_ENDIAN |
/* swap (8 in 32) RB and IB */ |
lmi_swap_cntl = 0xa; |
mp_swap_cntl = 0; |
#endif |
WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl); |
WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl); |
WREG32(UVD_MPC_SET_MUXA0, 0x40c2040); |
WREG32(UVD_MPC_SET_MUXA1, 0x0); |
WREG32(UVD_MPC_SET_MUXB0, 0x40c2040); |
WREG32(UVD_MPC_SET_MUXB1, 0x0); |
WREG32(UVD_MPC_SET_ALU, 0); |
WREG32(UVD_MPC_SET_MUX, 0x88); |
/* take all subblocks out of reset, except VCPU */ |
WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); |
mdelay(5); |
/* enable VCPU clock */ |
WREG32(UVD_VCPU_CNTL, 1 << 9); |
/* enable UMC */ |
WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); |
/* boot up the VCPU */ |
WREG32(UVD_SOFT_RESET, 0); |
mdelay(10); |
WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); |
for (i = 0; i < 10; ++i) { |
uint32_t status; |
for (j = 0; j < 100; ++j) { |
status = RREG32(UVD_STATUS); |
if (status & 2) |
break; |
mdelay(10); |
} |
r = 0; |
if (status & 2) |
break; |
DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n"); |
WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET); |
mdelay(10); |
WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET); |
mdelay(10); |
r = -1; |
} |
if (r) { |
DRM_ERROR("UVD not responding, giving up!!!\n"); |
return r; |
} |
/* enable interupt */ |
WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1)); |
/* force RBC into idle state */ |
WREG32(UVD_RBC_RB_CNTL, 0x11010101); |
/* Set the write pointer delay */ |
WREG32(UVD_RBC_RB_WPTR_CNTL, 0); |
/* programm the 4GB memory segment for rptr and ring buffer */ |
WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) | |
(0x7 << 16) | (0x1 << 31)); |
/* Initialize the ring buffer's read and write pointers */ |
WREG32(UVD_RBC_RB_RPTR, 0x0); |
ring->wptr = RREG32(UVD_RBC_RB_RPTR); |
WREG32(UVD_RBC_RB_WPTR, ring->wptr); |
/* set the ring address */ |
WREG32(UVD_RBC_RB_BASE, ring->gpu_addr); |
/* Set ring buffer size */ |
rb_bufsz = order_base_2(ring->ring_size); |
rb_bufsz = (0x1 << 8) | rb_bufsz; |
WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f); |
return 0; |
} |
/** |
* uvd_v1_0_stop - stop UVD block |
* |
* @rdev: radeon_device pointer |
* |
* stop the UVD block |
*/ |
void uvd_v1_0_stop(struct radeon_device *rdev) |
{ |
/* force RBC into idle state */ |
WREG32(UVD_RBC_RB_CNTL, 0x11010101); |
/* Stall UMC and register bus before resetting VCPU */ |
WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); |
WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); |
mdelay(1); |
/* put VCPU into reset */ |
WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); |
mdelay(5); |
/* disable VCPU clock */ |
WREG32(UVD_VCPU_CNTL, 0x0); |
/* Unstall UMC and register bus */ |
WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); |
WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); |
} |
/** |
* uvd_v1_0_ring_test - register write test |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring pointer |
* |
* Test if we can successfully write to the context register |
*/ |
int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
uint32_t tmp = 0; |
unsigned i; |
int r; |
WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD); |
r = radeon_ring_lock(rdev, ring, 3); |
if (r) { |
DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", |
ring->idx, r); |
return r; |
} |
radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); |
radeon_ring_write(ring, 0xDEADBEEF); |
radeon_ring_unlock_commit(rdev, ring, false); |
for (i = 0; i < rdev->usec_timeout; i++) { |
tmp = RREG32(UVD_CONTEXT_ID); |
if (tmp == 0xDEADBEEF) |
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 (0x%08X)\n", |
ring->idx, tmp); |
r = -EINVAL; |
} |
return r; |
} |
/** |
* uvd_v1_0_semaphore_emit - emit semaphore command |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring pointer |
* @semaphore: semaphore to emit commands for |
* @emit_wait: true if we should emit a wait command |
* |
* Emit a semaphore command (either wait or signal) to the UVD ring. |
*/ |
bool uvd_v1_0_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, PACKET0(UVD_SEMA_ADDR_LOW, 0)); |
radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); |
radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); |
radeon_ring_write(ring, emit_wait ? 1 : 0); |
return true; |
} |
/** |
* uvd_v1_0_ib_execute - execute indirect buffer |
* |
* @rdev: radeon_device pointer |
* @ib: indirect buffer to execute |
* |
* Write ring commands to execute the indirect buffer |
*/ |
void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) |
{ |
struct radeon_ring *ring = &rdev->ring[ib->ring]; |
radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0)); |
radeon_ring_write(ring, ib->gpu_addr); |
radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0)); |
radeon_ring_write(ring, ib->length_dw); |
} |
/** |
* uvd_v1_0_ib_test - test ib execution |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring pointer |
* |
* Test if we can successfully execute an IB |
*/ |
int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
{ |
struct radeon_fence *fence = NULL; |
int r; |
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; |
} |
r = radeon_uvd_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_uvd_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); |
goto error; |
} |
DRM_INFO("ib test on ring %d succeeded\n", ring->idx); |
error: |
radeon_fence_unref(&fence); |
radeon_set_uvd_clocks(rdev, 0, 0); |
return r; |
} |
/drivers/video/drm/radeon/uvd_v2_2.c |
---|
0,0 → 1,165 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Christian König <christian.koenig@amd.com> |
*/ |
#include <linux/firmware.h> |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "radeon_asic.h" |
#include "rv770d.h" |
/** |
* uvd_v2_2_fence_emit - emit an fence & trap command |
* |
* @rdev: radeon_device pointer |
* @fence: fence to emit |
* |
* Write a fence and a trap command to the ring. |
*/ |
void uvd_v2_2_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, 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, 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)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); |
radeon_ring_write(ring, 0); |
radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); |
radeon_ring_write(ring, 2); |
} |
/** |
* uvd_v2_2_resume - memory controller programming |
* |
* @rdev: radeon_device pointer |
* |
* Let the UVD memory controller know it's offsets |
*/ |
int uvd_v2_2_resume(struct radeon_device *rdev) |
{ |
uint64_t addr; |
uint32_t chip_id, size; |
int r; |
r = radeon_uvd_resume(rdev); |
if (r) |
return r; |
/* programm the VCPU memory controller bits 0-27 */ |
addr = rdev->uvd.gpu_addr >> 3; |
size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; |
WREG32(UVD_VCPU_CACHE_OFFSET0, addr); |
WREG32(UVD_VCPU_CACHE_SIZE0, size); |
addr += size; |
size = RADEON_UVD_STACK_SIZE >> 3; |
WREG32(UVD_VCPU_CACHE_OFFSET1, addr); |
WREG32(UVD_VCPU_CACHE_SIZE1, size); |
addr += size; |
size = RADEON_UVD_HEAP_SIZE >> 3; |
WREG32(UVD_VCPU_CACHE_OFFSET2, addr); |
WREG32(UVD_VCPU_CACHE_SIZE2, size); |
/* bits 28-31 */ |
addr = (rdev->uvd.gpu_addr >> 28) & 0xF; |
WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0)); |
/* bits 32-39 */ |
addr = (rdev->uvd.gpu_addr >> 32) & 0xFF; |
WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31)); |
/* tell firmware which hardware it is running on */ |
switch (rdev->family) { |
default: |
return -EINVAL; |
case CHIP_RV710: |
chip_id = 0x01000005; |
break; |
case CHIP_RV730: |
chip_id = 0x01000006; |
break; |
case CHIP_RV740: |
chip_id = 0x01000007; |
break; |
case CHIP_CYPRESS: |
case CHIP_HEMLOCK: |
chip_id = 0x01000008; |
break; |
case CHIP_JUNIPER: |
chip_id = 0x01000009; |
break; |
case CHIP_REDWOOD: |
chip_id = 0x0100000a; |
break; |
case CHIP_CEDAR: |
chip_id = 0x0100000b; |
break; |
case CHIP_SUMO: |
case CHIP_SUMO2: |
chip_id = 0x0100000c; |
break; |
case CHIP_PALM: |
chip_id = 0x0100000e; |
break; |
case CHIP_CAYMAN: |
chip_id = 0x0100000f; |
break; |
case CHIP_BARTS: |
chip_id = 0x01000010; |
break; |
case CHIP_TURKS: |
chip_id = 0x01000011; |
break; |
case CHIP_CAICOS: |
chip_id = 0x01000012; |
break; |
case CHIP_TAHITI: |
chip_id = 0x01000014; |
break; |
case CHIP_VERDE: |
chip_id = 0x01000015; |
break; |
case CHIP_PITCAIRN: |
case CHIP_OLAND: |
chip_id = 0x01000016; |
break; |
case CHIP_ARUBA: |
chip_id = 0x01000017; |
break; |
} |
WREG32(UVD_VCPU_CHIP_ID, chip_id); |
return 0; |
} |
/drivers/video/drm/radeon/uvd_v3_1.c |
---|
0,0 → 1,57 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: Christian König <christian.koenig@amd.com> |
*/ |
#include <drm/drmP.h> |
#include "radeon.h" |
#include "radeon_asic.h" |
#include "nid.h" |
/** |
* uvd_v3_1_semaphore_emit - emit semaphore command |
* |
* @rdev: radeon_device pointer |
* @ring: radeon_ring pointer |
* @semaphore: semaphore to emit commands for |
* @emit_wait: true if we should emit a wait command |
* |
* Emit a semaphore command (either wait or signal) to the UVD ring. |
*/ |
bool uvd_v3_1_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, PACKET0(UVD_SEMA_ADDR_LOW, 0)); |
radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); |
radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); |
radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); |
radeon_ring_write(ring, 0x80 | (emit_wait ? 1 : 0)); |
return true; |
} |
/drivers/video/drm/radeon/uvd_v4_2.c |
---|
0,0 → 1,68 |
/* |
* Copyright 2013 Advanced Micro Devices, Inc. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
* OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: 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" |
/** |
* uvd_v4_2_resume - memory controller programming |
* |
* @rdev: radeon_device pointer |
* |
* Let the UVD memory controller know it's offsets |
*/ |
int uvd_v4_2_resume(struct radeon_device *rdev) |
{ |
uint64_t addr; |
uint32_t size; |
/* programm the VCPU memory controller bits 0-27 */ |
addr = rdev->uvd.gpu_addr >> 3; |
size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; |
WREG32(UVD_VCPU_CACHE_OFFSET0, addr); |
WREG32(UVD_VCPU_CACHE_SIZE0, size); |
addr += size; |
size = RADEON_UVD_STACK_SIZE >> 3; |
WREG32(UVD_VCPU_CACHE_OFFSET1, addr); |
WREG32(UVD_VCPU_CACHE_SIZE1, size); |
addr += size; |
size = RADEON_UVD_HEAP_SIZE >> 3; |
WREG32(UVD_VCPU_CACHE_OFFSET2, addr); |
WREG32(UVD_VCPU_CACHE_SIZE2, size); |
/* bits 28-31 */ |
addr = (rdev->uvd.gpu_addr >> 28) & 0xF; |
WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0)); |
/* bits 32-39 */ |
addr = (rdev->uvd.gpu_addr >> 32) & 0xFF; |
WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31)); |
return 0; |
} |
/drivers/video/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; |
} |
/drivers/video/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; |
} |
/drivers/video/drm/ttm/ttm_bo.c |
---|
39,92 → 39,35 |
#include <linux/mm.h> |
#include <linux/module.h> |
#define pr_err(fmt, ...) \ |
printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
#define TTM_ASSERT_LOCKED(param) |
#define TTM_DEBUG(fmt, arg...) |
#define TTM_BO_HASH_ORDER 13 |
#define pr_err(fmt, ...) \ |
printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) |
static inline int ttm_mem_type_from_flags(uint32_t flags, uint32_t *mem_type) |
{ |
int i; |
mutex_lock(&man->io_reserve_mutex); |
for (i = 0; i <= TTM_PL_PRIV5; i++) |
if (flags & (1 << i)) { |
*mem_type = i; |
return 0; |
} |
void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) |
{ |
if (likely(man->io_reserve_fastpath)) |
return; |
mutex_unlock(&man->io_reserve_mutex); |
return -EINVAL; |
} |
#if 0 |
static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type) |
{ |
struct ttm_mem_type_manager *man = &bdev->man[mem_type]; |
pr_err(" has_type: %d\n", man->has_type); |
pr_err(" use_type: %d\n", man->use_type); |
pr_err(" flags: 0x%08X\n", man->flags); |
pr_err(" gpu_offset: 0x%08lX\n", man->gpu_offset); |
pr_err(" size: %llu\n", man->size); |
pr_err(" available_caching: 0x%08X\n", man->available_caching); |
pr_err(" default_caching: 0x%08X\n", man->default_caching); |
if (mem_type != TTM_PL_SYSTEM) |
(*man->func->debug)(man, TTM_PFX); |
} |
static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, |
struct ttm_placement *placement) |
{ |
int i, ret, mem_type; |
pr_err("No space for %p (%lu pages, %luK, %luM)\n", |
bo, bo->mem.num_pages, bo->mem.size >> 10, |
bo->mem.size >> 20); |
for (i = 0; i < placement->num_placement; i++) { |
ret = ttm_mem_type_from_flags(placement->placement[i], |
&mem_type); |
if (ret) |
return; |
pr_err(" placement[%d]=0x%08X (%d)\n", |
i, placement->placement[i], mem_type); |
ttm_mem_type_debug(bo->bdev, mem_type); |
} |
} |
static ssize_t ttm_bo_global_show(struct kobject *kobj, |
struct attribute *attr, |
char *buffer) |
{ |
struct ttm_bo_global *glob = |
container_of(kobj, struct ttm_bo_global, kobj); |
return snprintf(buffer, PAGE_SIZE, "%lu\n", |
(unsigned long) atomic_read(&glob->bo_count)); |
} |
static struct attribute *ttm_bo_global_attrs[] = { |
&ttm_bo_count, |
NULL |
}; |
static const struct sysfs_ops ttm_bo_global_ops = { |
.show = &ttm_bo_global_show |
}; |
static struct kobj_type ttm_bo_glob_kobj_type = { |
.release = &ttm_bo_global_kobj_release, |
.sysfs_ops = &ttm_bo_global_ops, |
.default_attrs = ttm_bo_global_attrs |
}; |
#endif |
static inline uint32_t ttm_bo_type_flags(unsigned type) |
{ |
return 1 << (type); |
148,12 → 91,14 |
if (bo->ttm) |
ttm_tt_destroy(bo->ttm); |
atomic_dec(&bo->glob->bo_count); |
if (bo->resv == &bo->ttm_resv) |
reservation_object_fini(&bo->ttm_resv); |
mutex_destroy(&bo->wu_mutex); |
if (bo->destroy) |
bo->destroy(bo); |
else { |
kfree(bo); |
} |
ttm_mem_global_free(bdev->glob->mem_glob, acc_size); |
} |
void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) |
161,7 → 106,7 |
struct ttm_bo_device *bdev = bo->bdev; |
struct ttm_mem_type_manager *man; |
// BUG_ON(!ttm_bo_is_reserved(bo)); |
lockdep_assert_held(&bo->resv->lock.base); |
if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { |
268,7 → 213,6 |
return ret; |
} |
#if 0 |
static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, |
struct ttm_mem_reg *mem, |
bool evict, bool interruptible, |
348,9 → 292,11 |
moved: |
if (bo->evicted) { |
if (bdev->driver->invalidate_caches) { |
ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement); |
if (ret) |
pr_err("Can not flush read caches\n"); |
} |
bo->evicted = false; |
} |
407,7 → 353,7 |
int ret; |
spin_lock(&glob->lru_lock); |
ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); |
ret = __ttm_bo_reserve(bo, false, true, false, NULL); |
spin_lock(&bdev->fence_lock); |
(void) ttm_bo_wait(bo, false, false, true); |
438,7 → 384,7 |
ttm_bo_add_to_lru(bo); |
} |
ww_mutex_unlock(&bo->resv->lock); |
__ttm_bo_unreserve(bo); |
} |
kref_get(&bo->list_kref); |
449,8 → 395,8 |
driver->sync_obj_flush(sync_obj); |
driver->sync_obj_unref(&sync_obj); |
} |
schedule_delayed_work(&bdev->wq, |
((HZ / 100) < 1) ? 1 : HZ / 100); |
// schedule_delayed_work(&bdev->wq, |
// ((HZ / 100) < 1) ? 1 : HZ / 100); |
} |
/** |
489,7 → 435,7 |
sync_obj = driver->sync_obj_ref(bo->sync_obj); |
spin_unlock(&bdev->fence_lock); |
ww_mutex_unlock(&bo->resv->lock); |
__ttm_bo_unreserve(bo); |
spin_unlock(&glob->lru_lock); |
ret = driver->sync_obj_wait(sync_obj, false, interruptible); |
509,7 → 455,7 |
return ret; |
spin_lock(&glob->lru_lock); |
ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); |
ret = __ttm_bo_reserve(bo, false, true, false, NULL); |
/* |
* We raced, and lost, someone else holds the reservation now, |
527,7 → 473,7 |
spin_unlock(&bdev->fence_lock); |
if (ret || unlikely(list_empty(&bo->ddestroy))) { |
ww_mutex_unlock(&bo->resv->lock); |
__ttm_bo_unreserve(bo); |
spin_unlock(&glob->lru_lock); |
return ret; |
} |
572,11 → 518,11 |
kref_get(&nentry->list_kref); |
} |
ret = ttm_bo_reserve_nolru(entry, false, true, false, 0); |
ret = __ttm_bo_reserve(entry, false, true, false, NULL); |
if (remove_all && ret) { |
spin_unlock(&glob->lru_lock); |
ret = ttm_bo_reserve_nolru(entry, false, false, |
false, 0); |
ret = __ttm_bo_reserve(entry, false, false, |
false, NULL); |
spin_lock(&glob->lru_lock); |
} |
615,7 → 561,6 |
((HZ / 100) < 1) ? 1 : HZ / 100); |
} |
} |
#endif |
static void ttm_bo_release(struct kref *kref) |
{ |
626,10 → 571,10 |
drm_vma_offset_remove(&bdev->vma_manager, &bo->vma_node); |
ttm_mem_io_lock(man, false); |
// ttm_mem_io_free_vm(bo); |
ttm_mem_io_free_vm(bo); |
ttm_mem_io_unlock(man); |
// ttm_bo_cleanup_refs_or_queue(bo); |
// kref_put(&bo->list_kref, ttm_bo_release_list); |
ttm_bo_cleanup_refs_or_queue(bo); |
kref_put(&bo->list_kref, ttm_bo_release_list); |
} |
void ttm_bo_unref(struct ttm_buffer_object **p_bo) |
641,121 → 586,6 |
} |
EXPORT_SYMBOL(ttm_bo_unref); |
#if 0 |
int ttm_bo_lock_delayed_workqueue(struct ttm_bo_device *bdev) |
{ |
return cancel_delayed_work_sync(&bdev->wq); |
} |
EXPORT_SYMBOL(ttm_bo_lock_delayed_workqueue); |
void ttm_bo_unlock_delayed_workqueue(struct ttm_bo_device *bdev, int resched) |
{ |
if (resched) |
schedule_delayed_work(&bdev->wq, |
((HZ / 100) < 1) ? 1 : HZ / 100); |
} |
EXPORT_SYMBOL(ttm_bo_unlock_delayed_workqueue); |
static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, |
bool no_wait_gpu) |
{ |
struct ttm_bo_device *bdev = bo->bdev; |
struct ttm_mem_reg evict_mem; |
struct ttm_placement placement; |
int ret = 0; |
spin_lock(&bdev->fence_lock); |
ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); |
spin_unlock(&bdev->fence_lock); |
if (unlikely(ret != 0)) { |
if (ret != -ERESTARTSYS) { |
pr_err("Failed to expire sync object before buffer eviction\n"); |
} |
goto out; |
} |
// BUG_ON(!ttm_bo_is_reserved(bo)); |
evict_mem = bo->mem; |
evict_mem.mm_node = NULL; |
evict_mem.bus.io_reserved_vm = false; |
evict_mem.bus.io_reserved_count = 0; |
placement.fpfn = 0; |
placement.lpfn = 0; |
placement.num_placement = 0; |
placement.num_busy_placement = 0; |
bdev->driver->evict_flags(bo, &placement); |
ret = ttm_bo_mem_space(bo, &placement, &evict_mem, interruptible, |
no_wait_gpu); |
if (ret) { |
if (ret != -ERESTARTSYS) { |
pr_err("Failed to find memory space for buffer 0x%p eviction\n", |
bo); |
ttm_bo_mem_space_debug(bo, &placement); |
} |
goto out; |
} |
ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, interruptible, |
no_wait_gpu); |
if (ret) { |
if (ret != -ERESTARTSYS) |
pr_err("Buffer eviction failed\n"); |
ttm_bo_mem_put(bo, &evict_mem); |
goto out; |
} |
bo->evicted = true; |
out: |
return ret; |
} |
static int ttm_mem_evict_first(struct ttm_bo_device *bdev, |
uint32_t mem_type, |
bool interruptible, |
bool no_wait_gpu) |
{ |
struct ttm_bo_global *glob = bdev->glob; |
struct ttm_mem_type_manager *man = &bdev->man[mem_type]; |
struct ttm_buffer_object *bo; |
int ret = -EBUSY, put_count; |
spin_lock(&glob->lru_lock); |
list_for_each_entry(bo, &man->lru, lru) { |
ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); |
if (!ret) |
break; |
} |
if (ret) { |
spin_unlock(&glob->lru_lock); |
return ret; |
} |
kref_get(&bo->list_kref); |
if (!list_empty(&bo->ddestroy)) { |
ret = ttm_bo_cleanup_refs_and_unlock(bo, interruptible, |
no_wait_gpu); |
kref_put(&bo->list_kref, ttm_bo_release_list); |
return ret; |
} |
put_count = ttm_bo_del_from_lru(bo); |
spin_unlock(&glob->lru_lock); |
BUG_ON(ret != 0); |
ttm_bo_list_ref_sub(bo, put_count, true); |
ret = ttm_bo_evict(bo, interruptible, no_wait_gpu); |
ttm_bo_unreserve(bo); |
kref_put(&bo->list_kref, ttm_bo_release_list); |
return ret; |
} |
void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) |
{ |
struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type]; |
781,15 → 611,15 |
int ret; |
do { |
ret = (*man->func->get_node)(man, bo, placement, mem); |
ret = (*man->func->get_node)(man, bo, placement, 0, mem); |
if (unlikely(ret != 0)) |
return ret; |
if (mem->mm_node) |
break; |
ret = ttm_mem_evict_first(bdev, mem_type, |
interruptible, no_wait_gpu); |
if (unlikely(ret != 0)) |
return ret; |
// ret = ttm_mem_evict_first(bdev, mem_type, |
// interruptible, no_wait_gpu); |
// if (unlikely(ret != 0)) |
// return ret; |
} while (1); |
if (mem->mm_node == NULL) |
return -ENOMEM; |
894,7 → 724,8 |
if (man->has_type && man->use_type) { |
type_found = true; |
ret = (*man->func->get_node)(man, bo, placement, mem); |
ret = (*man->func->get_node)(man, bo, placement, |
cur_flags, mem); |
if (unlikely(ret)) |
return ret; |
} |
934,7 → 765,6 |
ttm_flag_masked(&cur_flags, placement->busy_placement[i], |
~TTM_PL_MASK_MEMTYPE); |
if (mem_type == TTM_PL_SYSTEM) { |
mem->mem_type = mem_type; |
mem->placement = cur_flags; |
965,7 → 795,7 |
struct ttm_mem_reg mem; |
struct ttm_bo_device *bdev = bo->bdev; |
// BUG_ON(!ttm_bo_is_reserved(bo)); |
lockdep_assert_held(&bo->resv->lock.base); |
/* |
* FIXME: It's possible to pipeline buffer moves. |
996,7 → 826,6 |
ttm_bo_mem_put(bo, &mem); |
return ret; |
} |
#endif |
static bool ttm_bo_mem_compat(struct ttm_placement *placement, |
struct ttm_mem_reg *mem, |
1034,7 → 863,7 |
int ret; |
uint32_t new_flags; |
// BUG_ON(!ttm_bo_is_reserved(bo)); |
lockdep_assert_held(&bo->resv->lock.base); |
/* Check that range is valid */ |
if (placement->lpfn || placement->fpfn) |
if (placement->fpfn > placement->lpfn || |
1044,8 → 873,8 |
* Check whether we need to move buffer. |
*/ |
if (!ttm_bo_mem_compat(placement, &bo->mem, &new_flags)) { |
// ret = ttm_bo_move_buffer(bo, placement, interruptible, |
// no_wait_gpu); |
ret = ttm_bo_move_buffer(bo, placement, interruptible, |
no_wait_gpu); |
if (ret) |
return ret; |
} else { |
1091,19 → 920,8 |
{ |
int ret = 0; |
unsigned long num_pages; |
struct ttm_mem_global *mem_glob = bdev->glob->mem_glob; |
bool locked; |
// ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false); |
if (ret) { |
pr_err("Out of kernel memory\n"); |
if (destroy) |
(*destroy)(bo); |
else |
kfree(bo); |
return -ENOMEM; |
} |
num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; |
if (num_pages == 0) { |
pr_err("Illegal buffer object size\n"); |
1111,7 → 929,6 |
(*destroy)(bo); |
else |
kfree(bo); |
// ttm_mem_global_free(mem_glob, acc_size); |
return -EINVAL; |
} |
bo->destroy = destroy; |
1141,7 → 958,7 |
bo->acc_size = acc_size; |
bo->sg = sg; |
bo->resv = &bo->ttm_resv; |
// reservation_object_init(bo->resv); |
reservation_object_init(bo->resv); |
atomic_inc(&bo->glob->bo_count); |
drm_vma_node_reset(&bo->vma_node); |
1151,19 → 968,23 |
* For ttm_bo_type_device buffers, allocate |
* address space from the device. |
*/ |
// if (likely(!ret) && |
// (bo->type == ttm_bo_type_device || |
// bo->type == ttm_bo_type_sg)) |
// ret = ttm_bo_setup_vm(bo); |
if (likely(!ret) && |
(bo->type == ttm_bo_type_device || |
bo->type == ttm_bo_type_sg)) |
ret = drm_vma_offset_add(&bdev->vma_manager, &bo->vma_node, |
bo->mem.num_pages); |
// if (likely(!ret)) |
// ret = ttm_bo_validate(bo, placement, interruptible, false); |
locked = ww_mutex_trylock(&bo->resv->lock); |
WARN_ON(!locked); |
// ttm_bo_unreserve(bo); |
if (likely(!ret)) |
ret = ttm_bo_validate(bo, placement, interruptible, false); |
// if (unlikely(ret)) |
// ttm_bo_unref(&bo); |
ttm_bo_unreserve(bo); |
if (unlikely(ret)) |
ttm_bo_unref(&bo); |
return ret; |
} |
EXPORT_SYMBOL(ttm_bo_init); |
1197,53 → 1018,6 |
} |
EXPORT_SYMBOL(ttm_bo_dma_acc_size); |
int ttm_bo_create(struct ttm_bo_device *bdev, |
unsigned long size, |
enum ttm_bo_type type, |
struct ttm_placement *placement, |
uint32_t page_alignment, |
bool interruptible, |
struct file *persistent_swap_storage, |
struct ttm_buffer_object **p_bo) |
{ |
struct ttm_buffer_object *bo; |
size_t acc_size; |
int ret; |
bo = kzalloc(sizeof(*bo), GFP_KERNEL); |
if (unlikely(bo == NULL)) |
return -ENOMEM; |
acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct ttm_buffer_object)); |
ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment, |
interruptible, persistent_swap_storage, acc_size, |
NULL, NULL); |
if (likely(ret == 0)) |
*p_bo = bo; |
return ret; |
} |
EXPORT_SYMBOL(ttm_bo_create); |
int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type, |
unsigned long p_size) |
{ |
1250,8 → 1024,6 |
int ret = -EINVAL; |
struct ttm_mem_type_manager *man; |
ENTER(); |
BUG_ON(type >= TTM_NUM_MEM_TYPES); |
man = &bdev->man[type]; |
BUG_ON(man->has_type); |
1277,12 → 1049,9 |
INIT_LIST_HEAD(&man->lru); |
LEAVE(); |
return 0; |
} |
EXPORT_SYMBOL(ttm_bo_init_mm); |
void ttm_bo_global_release(struct drm_global_reference *ref) |
{ |
struct ttm_bo_global *glob = ref->object; |
1297,12 → 1066,10 |
struct ttm_bo_global *glob = ref->object; |
int ret; |
ENTER(); |
mutex_init(&glob->device_list_mutex); |
spin_lock_init(&glob->lru_lock); |
glob->mem_glob = bo_ref->mem_glob; |
glob->dummy_read_page = AllocPage(); |
glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32); |
if (unlikely(glob->dummy_read_page == NULL)) { |
ret = -ENOMEM; |
1314,8 → 1081,6 |
atomic_set(&glob->bo_count, 0); |
LEAVE(); |
return 0; |
out_no_drp: |
1324,17 → 1089,15 |
} |
EXPORT_SYMBOL(ttm_bo_global_init); |
int ttm_bo_device_init(struct ttm_bo_device *bdev, |
struct ttm_bo_global *glob, |
struct ttm_bo_driver *driver, |
struct address_space *mapping, |
uint64_t file_page_offset, |
bool need_dma32) |
{ |
int ret = -EINVAL; |
ENTER(); |
bdev->driver = driver; |
memset(bdev->man, 0, sizeof(bdev->man)); |
1349,9 → 1112,9 |
drm_vma_offset_manager_init(&bdev->vma_manager, file_page_offset, |
0x10000000); |
// INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue); |
INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue); |
INIT_LIST_HEAD(&bdev->ddestroy); |
bdev->dev_mapping = NULL; |
bdev->dev_mapping = mapping; |
bdev->glob = glob; |
bdev->need_dma32 = need_dma32; |
bdev->val_seq = 0; |
1360,8 → 1123,6 |
list_add_tail(&bdev->device_list, &glob->device_list); |
mutex_unlock(&glob->device_list_mutex); |
LEAVE(); |
return 0; |
out_no_sys: |
return ret; |
1389,6 → 1150,28 |
return true; |
} |
void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo) |
{ |
struct ttm_bo_device *bdev = bo->bdev; |
drm_vma_node_unmap(&bo->vma_node, bdev->dev_mapping); |
ttm_mem_io_free_vm(bo); |
} |
void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) |
{ |
struct ttm_bo_device *bdev = bo->bdev; |
struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; |
ttm_mem_io_lock(man, false); |
ttm_bo_unmap_virtual_locked(bo); |
ttm_mem_io_unlock(man); |
} |
EXPORT_SYMBOL(ttm_bo_unmap_virtual); |
int ttm_bo_wait(struct ttm_buffer_object *bo, |
bool lazy, bool interruptible, bool no_wait) |
{ |
1400,25 → 1183,47 |
if (likely(bo->sync_obj == NULL)) |
return 0; |
return 0; |
while (bo->sync_obj) { |
if (driver->sync_obj_signaled(bo->sync_obj)) { |
void *tmp_obj = bo->sync_obj; |
bo->sync_obj = NULL; |
clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); |
spin_unlock(&bdev->fence_lock); |
driver->sync_obj_unref(&tmp_obj); |
spin_lock(&bdev->fence_lock); |
continue; |
} |
EXPORT_SYMBOL(ttm_bo_wait); |
int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait) |
{ |
struct ttm_bo_device *bdev = bo->bdev; |
int ret = 0; |
if (no_wait) |
return -EBUSY; |
/* |
* Using ttm_bo_reserve makes sure the lru lists are updated. |
*/ |
sync_obj = driver->sync_obj_ref(bo->sync_obj); |
spin_unlock(&bdev->fence_lock); |
ret = driver->sync_obj_wait(sync_obj, |
lazy, interruptible); |
if (unlikely(ret != 0)) { |
driver->sync_obj_unref(&sync_obj); |
spin_lock(&bdev->fence_lock); |
return ret; |
} |
EXPORT_SYMBOL(ttm_bo_synccpu_write_grab); |
spin_lock(&bdev->fence_lock); |
if (likely(bo->sync_obj == sync_obj)) { |
void *tmp_obj = bo->sync_obj; |
bo->sync_obj = NULL; |
clear_bit(TTM_BO_PRIV_FLAG_MOVING, |
&bo->priv_flags); |
spin_unlock(&bdev->fence_lock); |
driver->sync_obj_unref(&sync_obj); |
driver->sync_obj_unref(&tmp_obj); |
spin_lock(&bdev->fence_lock); |
} else { |
spin_unlock(&bdev->fence_lock); |
driver->sync_obj_unref(&sync_obj); |
spin_lock(&bdev->fence_lock); |
} |
} |
return 0; |
} |
EXPORT_SYMBOL(ttm_bo_wait); |
void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo) |
{ |
atomic_dec(&bo->cpu_writers); |
} |
EXPORT_SYMBOL(ttm_bo_synccpu_write_release); |
/drivers/video/drm/ttm/ttm_bo_manager.c |
---|
50,11 → 50,13 |
static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, |
struct ttm_buffer_object *bo, |
struct ttm_placement *placement, |
uint32_t flags, |
struct ttm_mem_reg *mem) |
{ |
struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; |
struct drm_mm *mm = &rman->mm; |
struct drm_mm_node *node = NULL; |
enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT; |
unsigned long lpfn; |
int ret; |
66,11 → 68,15 |
if (!node) |
return -ENOMEM; |
if (flags & TTM_PL_FLAG_TOPDOWN) |
aflags = DRM_MM_CREATE_TOP; |
spin_lock(&rman->lock); |
ret = drm_mm_insert_node_in_range(mm, node, mem->num_pages, |
mem->page_alignment, |
ret = drm_mm_insert_node_in_range_generic(mm, node, mem->num_pages, |
mem->page_alignment, 0, |
placement->fpfn, lpfn, |
DRM_MM_SEARCH_BEST); |
DRM_MM_SEARCH_BEST, |
aflags); |
spin_unlock(&rman->lock); |
if (unlikely(ret)) { |
/drivers/video/drm/ttm/ttm_bo_util.c |
---|
27,17 → 27,25 |
/* |
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> |
*/ |
#define iowrite32(v, addr) writel((v), (addr)) |
#define ioread32(addr) readl(addr) |
#include <drm/ttm/ttm_bo_driver.h> |
#include <drm/ttm/ttm_placement.h> |
#include <drm/drm_vma_manager.h> |
#include <linux/io.h> |
#include <linux/highmem.h> |
//#include <linux/io.h> |
//#include <linux/highmem.h> |
#include <linux/wait.h> |
#include <linux/slab.h> |
#include <linux/vmalloc.h> |
//#include <linux/vmalloc.h> |
#include <linux/module.h> |
#define __pgprot(x) ((pgprot_t) { (x) } ) |
#define PAGE_KERNEL __pgprot(3) |
void *vmap(struct page **pages, unsigned int count, |
unsigned long flags, pgprot_t prot); |
void ttm_bo_free_old_node(struct ttm_buffer_object *bo) |
{ |
ttm_bo_mem_put(bo, &bo->mem); |
156,6 → 164,7 |
} |
EXPORT_SYMBOL(ttm_mem_io_free); |
#if 0 |
int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) |
{ |
struct ttm_mem_reg *mem = &bo->mem; |
175,6 → 184,7 |
} |
return 0; |
} |
#endif |
void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) |
{ |
207,7 → 217,7 |
if (mem->placement & TTM_PL_FLAG_WC) |
addr = ioremap_wc(mem->bus.base + mem->bus.offset, mem->bus.size); |
else |
addr = ioremap_nocache(mem->bus.base + mem->bus.offset, mem->bus.size); |
addr = ioremap(mem->bus.base + mem->bus.offset, mem->bus.size); |
if (!addr) { |
(void) ttm_mem_io_lock(man, false); |
ttm_mem_io_free(bdev, mem); |
258,27 → 268,14 |
src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); |
#ifdef CONFIG_X86 |
dst = kmap_atomic_prot(d, prot); |
#else |
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) |
dst = vmap(&d, 1, 0, prot); |
else |
dst = kmap(d); |
#endif |
dst = (void*)MapIoMem((addr_t)d, 4096, PG_SW); |
if (!dst) |
return -ENOMEM; |
memcpy_fromio(dst, src, PAGE_SIZE); |
memcpy(dst, src, PAGE_SIZE); |
#ifdef CONFIG_X86 |
kunmap_atomic(dst); |
#else |
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) |
vunmap(dst); |
else |
kunmap(d); |
#endif |
FreeKernelSpace(dst); |
return 0; |
} |
294,27 → 291,15 |
return -ENOMEM; |
dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); |
#ifdef CONFIG_X86 |
src = kmap_atomic_prot(s, prot); |
#else |
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) |
src = vmap(&s, 1, 0, prot); |
else |
src = kmap(s); |
#endif |
src = (void*)MapIoMem((addr_t)s, 4096, PG_SW); |
if (!src) |
return -ENOMEM; |
memcpy_toio(dst, src, PAGE_SIZE); |
memcpy(dst, src, PAGE_SIZE); |
#ifdef CONFIG_X86 |
kunmap_atomic(src); |
#else |
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) |
vunmap(src); |
else |
kunmap(s); |
#endif |
FreeKernelSpace(src); |
return 0; |
} |
352,8 → 337,12 |
/* |
* Don't move nonexistent data. Clear destination instead. |
*/ |
if (old_iomap == NULL && ttm == NULL) |
if (old_iomap == NULL && |
(ttm == NULL || (ttm->state == tt_unpopulated && |
!(ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)))) { |
memset(new_iomap, 0, new_mem->num_pages*PAGE_SIZE); |
goto out2; |
} |
/* |
* TTM might be null for moves within the same region. |
483,29 → 472,6 |
pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp) |
{ |
#if defined(__i386__) || defined(__x86_64__) |
if (caching_flags & TTM_PL_FLAG_WC) |
tmp = pgprot_writecombine(tmp); |
else if (boot_cpu_data.x86 > 3) |
tmp = pgprot_noncached(tmp); |
#elif defined(__powerpc__) |
if (!(caching_flags & TTM_PL_FLAG_CACHED)) { |
pgprot_val(tmp) |= _PAGE_NO_CACHE; |
if (caching_flags & TTM_PL_FLAG_UNCACHED) |
pgprot_val(tmp) |= _PAGE_GUARDED; |
} |
#endif |
#if defined(__ia64__) |
if (caching_flags & TTM_PL_FLAG_WC) |
tmp = pgprot_writecombine(tmp); |
else |
tmp = pgprot_noncached(tmp); |
#endif |
#if defined(__sparc__) || defined(__mips__) |
if (!(caching_flags & TTM_PL_FLAG_CACHED)) |
tmp = pgprot_noncached(tmp); |
#endif |
return tmp; |
} |
EXPORT_SYMBOL(ttm_io_prot); |
526,7 → 492,7 |
map->virtual = ioremap_wc(bo->mem.bus.base + bo->mem.bus.offset + offset, |
size); |
else |
map->virtual = ioremap_nocache(bo->mem.bus.base + bo->mem.bus.offset + offset, |
map->virtual = ioremap(bo->mem.bus.base + bo->mem.bus.offset + offset, |
size); |
} |
return (!map->virtual) ? -ENOMEM : 0; |
557,7 → 523,7 |
map->bo_kmap_type = ttm_bo_map_kmap; |
map->page = ttm->pages[start_page]; |
map->virtual = kmap(map->page); |
map->virtual = (void*)MapIoMem(page_to_phys(map->page), 4096, PG_SW); |
} else { |
/* |
* We need to use vmap to get the desired page protection |
621,10 → 587,8 |
iounmap(map->virtual); |
break; |
case ttm_bo_map_vmap: |
vunmap(map->virtual); |
break; |
case ttm_bo_map_kmap: |
kunmap(map->page); |
FreeKernelSpace(map->virtual); |
break; |
case ttm_bo_map_premapped: |
break; |
713,3 → 677,25 |
return 0; |
} |
EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); |
void *vmap(struct page **pages, unsigned int count, |
unsigned long flags, pgprot_t prot) |
{ |
void *vaddr; |
char *tmp; |
int i; |
vaddr = AllocKernelSpace(count << 12); |
if(vaddr == NULL) |
return NULL; |
for(i = 0, tmp = vaddr; i < count; i++) |
{ |
MapPage(tmp, page_to_phys(pages[i]), PG_SW); |
tmp+= 4096; |
}; |
return vaddr; |
}; |
/drivers/video/drm/ttm/ttm_execbuf_util.c |
---|
24,7 → 24,6 |
* USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
**************************************************************************/ |
struct ww_acquire_ctx{}; |
#include <drm/ttm/ttm_execbuf_util.h> |
#include <drm/ttm/ttm_bo_driver.h> |
33,8 → 32,9 |
#include <linux/sched.h> |
#include <linux/module.h> |
static void ttm_eu_backoff_reservation_locked(struct list_head *list, |
struct ww_acquire_ctx *ticket) |
DEFINE_WW_CLASS(reservation_ww_class); |
static void ttm_eu_backoff_reservation_locked(struct list_head *list) |
{ |
struct ttm_validate_buffer *entry; |
48,7 → 48,7 |
ttm_bo_add_to_lru(bo); |
entry->removed = false; |
} |
// ww_mutex_unlock(&bo->resv->lock); |
__ttm_bo_unreserve(bo); |
} |
} |
94,8 → 94,9 |
entry = list_first_entry(list, struct ttm_validate_buffer, head); |
glob = entry->bo->glob; |
spin_lock(&glob->lru_lock); |
ttm_eu_backoff_reservation_locked(list, ticket); |
// ww_acquire_fini(ticket); |
ttm_eu_backoff_reservation_locked(list); |
if (ticket) |
ww_acquire_fini(ticket); |
spin_unlock(&glob->lru_lock); |
} |
EXPORT_SYMBOL(ttm_eu_backoff_reservation); |
131,7 → 132,8 |
entry = list_first_entry(list, struct ttm_validate_buffer, head); |
glob = entry->bo->glob; |
// ww_acquire_init(ticket, &reservation_ww_class); |
if (ticket) |
ww_acquire_init(ticket, &reservation_ww_class); |
retry: |
list_for_each_entry(entry, list, head) { |
struct ttm_buffer_object *bo = entry->bo; |
140,20 → 142,21 |
if (entry->reserved) |
continue; |
ret = __ttm_bo_reserve(bo, true, (ticket == NULL), true, |
ticket); |
ret = ttm_bo_reserve_nolru(bo, true, false, true, ticket); |
if (ret == -EDEADLK) { |
/* uh oh, we lost out, drop every reservation and try |
* to only reserve this buffer, then start over if |
* this succeeds. |
*/ |
BUG_ON(ticket == NULL); |
spin_lock(&glob->lru_lock); |
ttm_eu_backoff_reservation_locked(list, ticket); |
ttm_eu_backoff_reservation_locked(list); |
spin_unlock(&glob->lru_lock); |
ttm_eu_list_ref_sub(list); |
// ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, |
// ticket); |
ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, |
ticket); |
if (unlikely(ret != 0)) { |
if (ret == -EINTR) |
ret = -ERESTARTSYS; |
176,7 → 179,8 |
} |
} |
// ww_acquire_done(ticket); |
if (ticket) |
ww_acquire_done(ticket); |
spin_lock(&glob->lru_lock); |
ttm_eu_del_from_lru_locked(list); |
spin_unlock(&glob->lru_lock); |
185,12 → 189,14 |
err: |
spin_lock(&glob->lru_lock); |
ttm_eu_backoff_reservation_locked(list, ticket); |
ttm_eu_backoff_reservation_locked(list); |
spin_unlock(&glob->lru_lock); |
ttm_eu_list_ref_sub(list); |
err_fini: |
// ww_acquire_done(ticket); |
// ww_acquire_fini(ticket); |
if (ticket) { |
ww_acquire_done(ticket); |
ww_acquire_fini(ticket); |
} |
return ret; |
} |
EXPORT_SYMBOL(ttm_eu_reserve_buffers); |
220,12 → 226,13 |
entry->old_sync_obj = bo->sync_obj; |
bo->sync_obj = driver->sync_obj_ref(sync_obj); |
ttm_bo_add_to_lru(bo); |
// ww_mutex_unlock(&bo->resv->lock); |
__ttm_bo_unreserve(bo); |
entry->reserved = false; |
} |
spin_unlock(&bdev->fence_lock); |
spin_unlock(&glob->lru_lock); |
// ww_acquire_fini(ticket); |
if (ticket) |
ww_acquire_fini(ticket); |
list_for_each_entry(entry, list, head) { |
if (entry->old_sync_obj) |
/drivers/video/drm/ttm/ttm_lock.c |
---|
0,0 → 1,286 |
/************************************************************************** |
* |
* Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA |
* 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 above copyright notice and this permission notice (including the |
* next paragraph) 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 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. |
* |
**************************************************************************/ |
/* |
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> |
*/ |
#include <linux/mutex.h> |
#include <drm/ttm/ttm_lock.h> |
#include <drm/ttm/ttm_module.h> |
//#include <linux/atomic.h> |
#include <linux/errno.h> |
#include <linux/wait.h> |
#include <linux/sched.h> |
#include <linux/module.h> |
#define TTM_WRITE_LOCK_PENDING (1 << 0) |
#define TTM_VT_LOCK_PENDING (1 << 1) |
#define TTM_SUSPEND_LOCK_PENDING (1 << 2) |
#define TTM_VT_LOCK (1 << 3) |
#define TTM_SUSPEND_LOCK (1 << 4) |
void ttm_lock_init(struct ttm_lock *lock) |
{ |
spin_lock_init(&lock->lock); |
init_waitqueue_head(&lock->queue); |
lock->rw = 0; |
lock->flags = 0; |
} |
EXPORT_SYMBOL(ttm_lock_init); |
void ttm_read_unlock(struct ttm_lock *lock) |
{ |
spin_lock(&lock->lock); |
if (--lock->rw == 0) |
wake_up_all(&lock->queue); |
spin_unlock(&lock->lock); |
} |
EXPORT_SYMBOL(ttm_read_unlock); |
static bool __ttm_read_lock(struct ttm_lock *lock) |
{ |
bool locked = false; |
spin_lock(&lock->lock); |
if (lock->rw >= 0 && lock->flags == 0) { |
++lock->rw; |
locked = true; |
} |
spin_unlock(&lock->lock); |
return locked; |
} |
int ttm_read_lock(struct ttm_lock *lock, bool interruptible) |
{ |
int ret = 0; |
if (interruptible) |
ret = wait_event_interruptible(lock->queue, |
__ttm_read_lock(lock)); |
else |
wait_event(lock->queue, __ttm_read_lock(lock)); |
return ret; |
} |
EXPORT_SYMBOL(ttm_read_lock); |
static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked) |
{ |
bool block = true; |
*locked = false; |
spin_lock(&lock->lock); |
if (lock->rw >= 0 && lock->flags == 0) { |
++lock->rw; |
block = false; |
*locked = true; |
} else if (lock->flags == 0) { |
block = false; |
} |
spin_unlock(&lock->lock); |
return !block; |
} |
int ttm_read_trylock(struct ttm_lock *lock, bool interruptible) |
{ |
int ret = 0; |
bool locked; |
if (interruptible) |
ret = wait_event_interruptible |
(lock->queue, __ttm_read_trylock(lock, &locked)); |
else |
wait_event(lock->queue, __ttm_read_trylock(lock, &locked)); |
if (unlikely(ret != 0)) { |
BUG_ON(locked); |
return ret; |
} |
return (locked) ? 0 : -EBUSY; |
} |
void ttm_write_unlock(struct ttm_lock *lock) |
{ |
spin_lock(&lock->lock); |
lock->rw = 0; |
wake_up_all(&lock->queue); |
spin_unlock(&lock->lock); |
} |
EXPORT_SYMBOL(ttm_write_unlock); |
static bool __ttm_write_lock(struct ttm_lock *lock) |
{ |
bool locked = false; |
spin_lock(&lock->lock); |
if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) { |
lock->rw = -1; |
lock->flags &= ~TTM_WRITE_LOCK_PENDING; |
locked = true; |
} else { |
lock->flags |= TTM_WRITE_LOCK_PENDING; |
} |
spin_unlock(&lock->lock); |
return locked; |
} |
int ttm_write_lock(struct ttm_lock *lock, bool interruptible) |
{ |
int ret = 0; |
if (interruptible) { |
ret = wait_event_interruptible(lock->queue, |
__ttm_write_lock(lock)); |
if (unlikely(ret != 0)) { |
spin_lock(&lock->lock); |
lock->flags &= ~TTM_WRITE_LOCK_PENDING; |
wake_up_all(&lock->queue); |
spin_unlock(&lock->lock); |
} |
} else |
wait_event(lock->queue, __ttm_read_lock(lock)); |
return ret; |
} |
EXPORT_SYMBOL(ttm_write_lock); |
static int __ttm_vt_unlock(struct ttm_lock *lock) |
{ |
int ret = 0; |
spin_lock(&lock->lock); |
if (unlikely(!(lock->flags & TTM_VT_LOCK))) |
ret = -EINVAL; |
lock->flags &= ~TTM_VT_LOCK; |
wake_up_all(&lock->queue); |
spin_unlock(&lock->lock); |
return ret; |
} |
static void ttm_vt_lock_remove(struct ttm_base_object **p_base) |
{ |
struct ttm_base_object *base = *p_base; |
struct ttm_lock *lock = container_of(base, struct ttm_lock, base); |
int ret; |
*p_base = NULL; |
ret = __ttm_vt_unlock(lock); |
BUG_ON(ret != 0); |
} |
static bool __ttm_vt_lock(struct ttm_lock *lock) |
{ |
bool locked = false; |
spin_lock(&lock->lock); |
if (lock->rw == 0) { |
lock->flags &= ~TTM_VT_LOCK_PENDING; |
lock->flags |= TTM_VT_LOCK; |
locked = true; |
} else { |
lock->flags |= TTM_VT_LOCK_PENDING; |
} |
spin_unlock(&lock->lock); |
return locked; |
} |
int ttm_vt_lock(struct ttm_lock *lock, |
bool interruptible, |
struct ttm_object_file *tfile) |
{ |
int ret = 0; |
if (interruptible) { |
ret = wait_event_interruptible(lock->queue, |
__ttm_vt_lock(lock)); |
if (unlikely(ret != 0)) { |
spin_lock(&lock->lock); |
lock->flags &= ~TTM_VT_LOCK_PENDING; |
wake_up_all(&lock->queue); |
spin_unlock(&lock->lock); |
return ret; |
} |
} else |
wait_event(lock->queue, __ttm_vt_lock(lock)); |
/* |
* Add a base-object, the destructor of which will |
* make sure the lock is released if the client dies |
* while holding it. |
*/ |
ret = ttm_base_object_init(tfile, &lock->base, false, |
ttm_lock_type, &ttm_vt_lock_remove, NULL); |
if (ret) |
(void)__ttm_vt_unlock(lock); |
else |
lock->vt_holder = tfile; |
return ret; |
} |
EXPORT_SYMBOL(ttm_vt_lock); |
int ttm_vt_unlock(struct ttm_lock *lock) |
{ |
return ttm_ref_object_base_unref(lock->vt_holder, |
lock->base.hash.key, TTM_REF_USAGE); |
} |
EXPORT_SYMBOL(ttm_vt_unlock); |
void ttm_suspend_unlock(struct ttm_lock *lock) |
{ |
spin_lock(&lock->lock); |
lock->flags &= ~TTM_SUSPEND_LOCK; |
wake_up_all(&lock->queue); |
spin_unlock(&lock->lock); |
} |
EXPORT_SYMBOL(ttm_suspend_unlock); |
static bool __ttm_suspend_lock(struct ttm_lock *lock) |
{ |
bool locked = false; |
spin_lock(&lock->lock); |
if (lock->rw == 0) { |
lock->flags &= ~TTM_SUSPEND_LOCK_PENDING; |
lock->flags |= TTM_SUSPEND_LOCK; |
locked = true; |
} else { |
lock->flags |= TTM_SUSPEND_LOCK_PENDING; |
} |
spin_unlock(&lock->lock); |
return locked; |
} |
void ttm_suspend_lock(struct ttm_lock *lock) |
{ |
wait_event(lock->queue, __ttm_suspend_lock(lock)); |
} |
EXPORT_SYMBOL(ttm_suspend_lock); |
/drivers/video/drm/ttm/ttm_memory.c |
---|
37,534 → 37,40 |
#include <linux/module.h> |
#include <linux/slab.h> |
struct sysinfo { |
u32_t totalram; /* Total usable main memory size */ |
u32_t freeram; /* Available memory size */ |
u32_t sharedram; /* Amount of shared memory */ |
u32_t bufferram; /* Memory used by buffers */ |
u32_t totalswap; /* Total swap space size */ |
u32_t freeswap; /* swap space still available */ |
u32_t totalhigh; /* Total high memory size */ |
u32_t freehigh; /* Available high memory size */ |
u32_t mem_unit; /* Memory unit size in bytes */ |
}; |
#define TTM_MEMORY_ALLOC_RETRIES 4 |
struct ttm_mem_zone { |
struct kobject kobj; |
struct ttm_mem_global *glob; |
const char *name; |
uint64_t zone_mem; |
uint64_t emer_mem; |
uint64_t max_mem; |
uint64_t swap_limit; |
uint64_t used_mem; |
}; |
#if 0 |
static struct attribute ttm_mem_sys = { |
.name = "zone_memory", |
.mode = S_IRUGO |
}; |
static struct attribute ttm_mem_emer = { |
.name = "emergency_memory", |
.mode = S_IRUGO | S_IWUSR |
}; |
static struct attribute ttm_mem_max = { |
.name = "available_memory", |
.mode = S_IRUGO | S_IWUSR |
}; |
static struct attribute ttm_mem_swap = { |
.name = "swap_limit", |
.mode = S_IRUGO | S_IWUSR |
}; |
static struct attribute ttm_mem_used = { |
.name = "used_memory", |
.mode = S_IRUGO |
}; |
#endif |
static void ttm_mem_zone_kobj_release(struct kobject *kobj) |
int ttm_mem_global_init(struct ttm_mem_global *glob) |
{ |
struct ttm_mem_zone *zone = |
container_of(kobj, struct ttm_mem_zone, kobj); |
pr_info("Zone %7s: Used memory at exit: %llu kiB\n", |
zone->name, (unsigned long long)zone->used_mem >> 10); |
kfree(zone); |
} |
#if 0 |
static ssize_t ttm_mem_zone_show(struct kobject *kobj, |
struct attribute *attr, |
char *buffer) |
{ |
struct ttm_mem_zone *zone = |
container_of(kobj, struct ttm_mem_zone, kobj); |
uint64_t val = 0; |
spin_lock(&zone->glob->lock); |
if (attr == &ttm_mem_sys) |
val = zone->zone_mem; |
else if (attr == &ttm_mem_emer) |
val = zone->emer_mem; |
else if (attr == &ttm_mem_max) |
val = zone->max_mem; |
else if (attr == &ttm_mem_swap) |
val = zone->swap_limit; |
else if (attr == &ttm_mem_used) |
val = zone->used_mem; |
spin_unlock(&zone->glob->lock); |
return snprintf(buffer, PAGE_SIZE, "%llu\n", |
(unsigned long long) val >> 10); |
} |
static void ttm_check_swapping(struct ttm_mem_global *glob); |
static ssize_t ttm_mem_zone_store(struct kobject *kobj, |
struct attribute *attr, |
const char *buffer, |
size_t size) |
{ |
struct ttm_mem_zone *zone = |
container_of(kobj, struct ttm_mem_zone, kobj); |
int chars; |
unsigned long val; |
uint64_t val64; |
chars = sscanf(buffer, "%lu", &val); |
if (chars == 0) |
return size; |
val64 = val; |
val64 <<= 10; |
spin_lock(&zone->glob->lock); |
if (val64 > zone->zone_mem) |
val64 = zone->zone_mem; |
if (attr == &ttm_mem_emer) { |
zone->emer_mem = val64; |
if (zone->max_mem > val64) |
zone->max_mem = val64; |
} else if (attr == &ttm_mem_max) { |
zone->max_mem = val64; |
if (zone->emer_mem < val64) |
zone->emer_mem = val64; |
} else if (attr == &ttm_mem_swap) |
zone->swap_limit = val64; |
spin_unlock(&zone->glob->lock); |
ttm_check_swapping(zone->glob); |
return size; |
} |
#endif |
//static struct attribute *ttm_mem_zone_attrs[] = { |
// &ttm_mem_sys, |
// &ttm_mem_emer, |
// &ttm_mem_max, |
// &ttm_mem_swap, |
// &ttm_mem_used, |
// NULL |
//}; |
//static const struct sysfs_ops ttm_mem_zone_ops = { |
// .show = &ttm_mem_zone_show, |
// .store = &ttm_mem_zone_store |
//}; |
static struct kobj_type ttm_mem_zone_kobj_type = { |
.release = &ttm_mem_zone_kobj_release, |
// .sysfs_ops = &ttm_mem_zone_ops, |
// .default_attrs = ttm_mem_zone_attrs, |
}; |
static void ttm_mem_global_kobj_release(struct kobject *kobj) |
{ |
struct ttm_mem_global *glob = |
container_of(kobj, struct ttm_mem_global, kobj); |
kfree(glob); |
} |
static struct kobj_type ttm_mem_glob_kobj_type = { |
.release = &ttm_mem_global_kobj_release, |
}; |
#if 0 |
static bool ttm_zones_above_swap_target(struct ttm_mem_global *glob, |
bool from_wq, uint64_t extra) |
{ |
unsigned int i; |
struct ttm_mem_zone *zone; |
uint64_t target; |
for (i = 0; i < glob->num_zones; ++i) { |
zone = glob->zones[i]; |
if (from_wq) |
target = zone->swap_limit; |
else if (capable(CAP_SYS_ADMIN)) |
target = zone->emer_mem; |
else |
target = zone->max_mem; |
target = (extra > target) ? 0ULL : target; |
if (zone->used_mem > target) |
return true; |
} |
return false; |
} |
/** |
* At this point we only support a single shrink callback. |
* Extend this if needed, perhaps using a linked list of callbacks. |
* Note that this function is reentrant: |
* many threads may try to swap out at any given time. |
*/ |
static void ttm_shrink(struct ttm_mem_global *glob, bool from_wq, |
uint64_t extra) |
{ |
int ret; |
struct ttm_mem_shrink *shrink; |
int i; |
spin_lock(&glob->lock); |
if (glob->shrink == NULL) |
goto out; |
spin_lock_init(&glob->lock); |
while (ttm_zones_above_swap_target(glob, from_wq, extra)) { |
shrink = glob->shrink; |
spin_unlock(&glob->lock); |
ret = shrink->do_shrink(shrink); |
spin_lock(&glob->lock); |
if (unlikely(ret != 0)) |
goto out; |
} |
out: |
spin_unlock(&glob->lock); |
} |
ttm_page_alloc_init(glob, 4*1024); |
static void ttm_shrink_work(struct work_struct *work) |
{ |
struct ttm_mem_global *glob = |
container_of(work, struct ttm_mem_global, work); |
ttm_shrink(glob, true, 0ULL); |
} |
#endif |
static int ttm_mem_init_kernel_zone(struct ttm_mem_global *glob, |
const struct sysinfo *si) |
{ |
struct ttm_mem_zone *zone = kzalloc(sizeof(*zone), GFP_KERNEL); |
uint64_t mem; |
int ret; |
if (unlikely(!zone)) |
return -ENOMEM; |
// mem = si->totalram - si->totalhigh; |
// mem *= si->mem_unit; |
zone->name = "kernel"; |
zone->zone_mem = mem; |
zone->max_mem = mem >> 1; |
zone->emer_mem = (mem >> 1) + (mem >> 2); |
zone->swap_limit = zone->max_mem - (mem >> 3); |
zone->used_mem = 0; |
zone->glob = glob; |
glob->zone_kernel = zone; |
ret = kobject_init_and_add( |
&zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); |
if (unlikely(ret != 0)) { |
kobject_put(&zone->kobj); |
return ret; |
} |
glob->zones[glob->num_zones++] = zone; |
return 0; |
} |
#if 0 |
#ifdef CONFIG_HIGHMEM |
static int ttm_mem_init_highmem_zone(struct ttm_mem_global *glob, |
const struct sysinfo *si) |
{ |
struct ttm_mem_zone *zone; |
uint64_t mem; |
int ret; |
if (si->totalhigh == 0) |
return 0; |
zone = kzalloc(sizeof(*zone), GFP_KERNEL); |
if (unlikely(!zone)) |
return -ENOMEM; |
mem = si->totalram; |
mem *= si->mem_unit; |
zone->name = "highmem"; |
zone->zone_mem = mem; |
zone->max_mem = mem >> 1; |
zone->emer_mem = (mem >> 1) + (mem >> 2); |
zone->swap_limit = zone->max_mem - (mem >> 3); |
zone->used_mem = 0; |
zone->glob = glob; |
glob->zone_highmem = zone; |
ret = kobject_init_and_add( |
&zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); |
if (unlikely(ret != 0)) { |
kobject_put(&zone->kobj); |
out_no_zone: |
ttm_mem_global_release(glob); |
return ret; |
} |
glob->zones[glob->num_zones++] = zone; |
return 0; |
} |
#else |
static int ttm_mem_init_dma32_zone(struct ttm_mem_global *glob, |
const struct sysinfo *si) |
{ |
struct ttm_mem_zone *zone = kzalloc(sizeof(*zone), GFP_KERNEL); |
uint64_t mem; |
int ret; |
EXPORT_SYMBOL(ttm_mem_global_init); |
if (unlikely(!zone)) |
return -ENOMEM; |
mem = si->totalram; |
mem *= si->mem_unit; |
/** |
* No special dma32 zone needed. |
*/ |
if (mem <= ((uint64_t) 1ULL << 32)) { |
kfree(zone); |
return 0; |
} |
/* |
* Limit max dma32 memory to 4GB for now |
* until we can figure out how big this |
* zone really is. |
*/ |
mem = ((uint64_t) 1ULL << 32); |
zone->name = "dma32"; |
zone->zone_mem = mem; |
zone->max_mem = mem >> 1; |
zone->emer_mem = (mem >> 1) + (mem >> 2); |
zone->swap_limit = zone->max_mem - (mem >> 3); |
zone->used_mem = 0; |
zone->glob = glob; |
glob->zone_dma32 = zone; |
ret = kobject_init_and_add( |
&zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); |
if (unlikely(ret != 0)) { |
kobject_put(&zone->kobj); |
return ret; |
} |
glob->zones[glob->num_zones++] = zone; |
return 0; |
} |
#endif |
void ttm_mem_global_release(struct ttm_mem_global *glob) |
{ |
unsigned int i; |
struct ttm_mem_zone *zone; |
/* let the page allocator first stop the shrink work. */ |
ttm_page_alloc_fini(); |
ttm_dma_page_alloc_fini(); |
// ttm_page_alloc_fini(); |
// ttm_dma_page_alloc_fini(); |
flush_workqueue(glob->swap_queue); |
destroy_workqueue(glob->swap_queue); |
glob->swap_queue = NULL; |
for (i = 0; i < glob->num_zones; ++i) { |
zone = glob->zones[i]; |
kobject_del(&zone->kobj); |
kobject_put(&zone->kobj); |
} |
kobject_del(&glob->kobj); |
kobject_put(&glob->kobj); |
} |
EXPORT_SYMBOL(ttm_mem_global_release); |
static void ttm_check_swapping(struct ttm_mem_global *glob) |
{ |
bool needs_swapping = false; |
unsigned int i; |
struct ttm_mem_zone *zone; |
spin_lock(&glob->lock); |
for (i = 0; i < glob->num_zones; ++i) { |
zone = glob->zones[i]; |
if (zone->used_mem > zone->swap_limit) { |
needs_swapping = true; |
break; |
} |
} |
spin_unlock(&glob->lock); |
if (unlikely(needs_swapping)) |
(void)queue_work(glob->swap_queue, &glob->work); |
} |
static void ttm_mem_global_free_zone(struct ttm_mem_global *glob, |
struct ttm_mem_zone *single_zone, |
uint64_t amount) |
{ |
unsigned int i; |
struct ttm_mem_zone *zone; |
spin_lock(&glob->lock); |
for (i = 0; i < glob->num_zones; ++i) { |
zone = glob->zones[i]; |
if (single_zone && zone != single_zone) |
continue; |
zone->used_mem -= amount; |
} |
spin_unlock(&glob->lock); |
} |
void ttm_mem_global_free(struct ttm_mem_global *glob, |
uint64_t amount) |
{ |
return ttm_mem_global_free_zone(glob, NULL, amount); |
} |
EXPORT_SYMBOL(ttm_mem_global_free); |
static int ttm_mem_global_reserve(struct ttm_mem_global *glob, |
struct ttm_mem_zone *single_zone, |
uint64_t amount, bool reserve) |
{ |
uint64_t limit; |
int ret = -ENOMEM; |
unsigned int i; |
struct ttm_mem_zone *zone; |
spin_lock(&glob->lock); |
for (i = 0; i < glob->num_zones; ++i) { |
zone = glob->zones[i]; |
if (single_zone && zone != single_zone) |
continue; |
limit = zone->emer_mem; |
if (zone->used_mem > limit) |
goto out_unlock; |
} |
if (reserve) { |
for (i = 0; i < glob->num_zones; ++i) { |
zone = glob->zones[i]; |
if (single_zone && zone != single_zone) |
continue; |
zone->used_mem += amount; |
} |
} |
ret = 0; |
out_unlock: |
spin_unlock(&glob->lock); |
ttm_check_swapping(glob); |
return ret; |
} |
static int ttm_mem_global_alloc_zone(struct ttm_mem_global *glob, |
struct ttm_mem_zone *single_zone, |
uint64_t memory, |
bool no_wait, bool interruptible) |
{ |
int count = TTM_MEMORY_ALLOC_RETRIES; |
while (unlikely(ttm_mem_global_reserve(glob, |
single_zone, |
memory, true) |
!= 0)) { |
if (no_wait) |
return -ENOMEM; |
if (unlikely(count-- == 0)) |
return -ENOMEM; |
ttm_shrink(glob, false, memory + (memory >> 2) + 16); |
} |
return 0; |
} |
int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory, |
bool no_wait, bool interruptible) |
{ |
/** |
* Normal allocations of kernel memory are registered in |
* all zones. |
*/ |
return ttm_mem_global_alloc_zone(glob, NULL, memory, no_wait, |
interruptible); |
} |
EXPORT_SYMBOL(ttm_mem_global_alloc); |
int ttm_mem_global_alloc_page(struct ttm_mem_global *glob, |
struct page *page, |
bool no_wait, bool interruptible) |
{ |
struct ttm_mem_zone *zone = NULL; |
/** |
* Page allocations may be registed in a single zone |
* only if highmem or !dma32. |
*/ |
#ifdef CONFIG_HIGHMEM |
if (PageHighMem(page) && glob->zone_highmem != NULL) |
zone = glob->zone_highmem; |
#else |
if (glob->zone_dma32 && page_to_pfn(page) > 0x00100000UL) |
zone = glob->zone_kernel; |
#endif |
return ttm_mem_global_alloc_zone(glob, zone, PAGE_SIZE, no_wait, |
interruptible); |
} |
void ttm_mem_global_free_page(struct ttm_mem_global *glob, struct page *page) |
{ |
struct ttm_mem_zone *zone = NULL; |
#ifdef CONFIG_HIGHMEM |
if (PageHighMem(page) && glob->zone_highmem != NULL) |
zone = glob->zone_highmem; |
#else |
if (glob->zone_dma32 && page_to_pfn(page) > 0x00100000UL) |
zone = glob->zone_kernel; |
#endif |
ttm_mem_global_free_zone(glob, zone, PAGE_SIZE); |
} |
#endif |
void ttm_mem_global_free_page(struct ttm_mem_global *glob, struct page *page) |
{ |
} |
size_t ttm_round_pot(size_t size) |
{ |
if ((size & (size - 1)) == 0) |
582,24 → 88,3 |
return 0; |
} |
EXPORT_SYMBOL(ttm_round_pot); |
void ttm_mem_global_free(struct ttm_mem_global *glob, |
uint64_t amount) |
{ |
return 0; |
} |
int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory, |
bool no_wait, bool interruptible) |
{ |
return 0; |
} |
EXPORT_SYMBOL(ttm_mem_global_alloc); |
int ttm_mem_global_init(struct ttm_mem_global *glob) |
{ |
return 0; |
} |
EXPORT_SYMBOL(ttm_mem_global_init); |
/drivers/video/drm/ttm/ttm_page_alloc.c |
---|
41,7 → 41,7 |
#include <linux/mm.h> |
#include <linux/seq_file.h> /* for seq_printf */ |
#include <linux/slab.h> |
#include <linux/dma-mapping.h> |
//#include <linux/dma-mapping.h> |
//#include <linux/atomic.h> |
58,12 → 58,6 |
/* times are in msecs */ |
#define PAGE_FREE_INTERVAL 1000 |
#define pr_err(fmt, ...) \ |
printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
#if 0 |
/** |
* struct ttm_page_pool - Pool to reuse recently allocated uc/wc pages. |
* |
115,7 → 109,6 |
**/ |
struct ttm_pool_manager { |
struct kobject kobj; |
struct shrinker mm_shrink; |
struct ttm_pool_opts options; |
union { |
129,134 → 122,10 |
}; |
}; |
static struct attribute ttm_page_pool_max = { |
.name = "pool_max_size", |
.mode = S_IRUGO | S_IWUSR |
}; |
static struct attribute ttm_page_pool_small = { |
.name = "pool_small_allocation", |
.mode = S_IRUGO | S_IWUSR |
}; |
static struct attribute ttm_page_pool_alloc_size = { |
.name = "pool_allocation_size", |
.mode = S_IRUGO | S_IWUSR |
}; |
static struct attribute *ttm_pool_attrs[] = { |
&ttm_page_pool_max, |
&ttm_page_pool_small, |
&ttm_page_pool_alloc_size, |
NULL |
}; |
static void ttm_pool_kobj_release(struct kobject *kobj) |
{ |
struct ttm_pool_manager *m = |
container_of(kobj, struct ttm_pool_manager, kobj); |
kfree(m); |
} |
static ssize_t ttm_pool_store(struct kobject *kobj, |
struct attribute *attr, const char *buffer, size_t size) |
{ |
struct ttm_pool_manager *m = |
container_of(kobj, struct ttm_pool_manager, kobj); |
int chars; |
unsigned val; |
chars = sscanf(buffer, "%u", &val); |
if (chars == 0) |
return size; |
/* Convert kb to number of pages */ |
val = val / (PAGE_SIZE >> 10); |
if (attr == &ttm_page_pool_max) |
m->options.max_size = val; |
else if (attr == &ttm_page_pool_small) |
m->options.small = val; |
else if (attr == &ttm_page_pool_alloc_size) { |
if (val > NUM_PAGES_TO_ALLOC*8) { |
pr_err("Setting allocation size to %lu is not allowed. Recommended size is %lu\n", |
NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7), |
NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); |
return size; |
} else if (val > NUM_PAGES_TO_ALLOC) { |
pr_warn("Setting allocation size to larger than %lu is not recommended\n", |
NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); |
} |
m->options.alloc_size = val; |
} |
return size; |
} |
static ssize_t ttm_pool_show(struct kobject *kobj, |
struct attribute *attr, char *buffer) |
{ |
struct ttm_pool_manager *m = |
container_of(kobj, struct ttm_pool_manager, kobj); |
unsigned val = 0; |
if (attr == &ttm_page_pool_max) |
val = m->options.max_size; |
else if (attr == &ttm_page_pool_small) |
val = m->options.small; |
else if (attr == &ttm_page_pool_alloc_size) |
val = m->options.alloc_size; |
val = val * (PAGE_SIZE >> 10); |
return snprintf(buffer, PAGE_SIZE, "%u\n", val); |
} |
static const struct sysfs_ops ttm_pool_sysfs_ops = { |
.show = &ttm_pool_show, |
.store = &ttm_pool_store, |
}; |
static struct kobj_type ttm_pool_kobj_type = { |
.release = &ttm_pool_kobj_release, |
.sysfs_ops = &ttm_pool_sysfs_ops, |
.default_attrs = ttm_pool_attrs, |
}; |
static struct ttm_pool_manager *_manager; |
#ifndef CONFIG_X86 |
static int set_pages_array_wb(struct page **pages, int addrinarray) |
{ |
#ifdef TTM_HAS_AGP |
int i; |
for (i = 0; i < addrinarray; i++) |
unmap_page_from_agp(pages[i]); |
#endif |
return 0; |
} |
static int set_pages_array_wc(struct page **pages, int addrinarray) |
{ |
#ifdef TTM_HAS_AGP |
int i; |
for (i = 0; i < addrinarray; i++) |
map_page_into_agp(pages[i]); |
#endif |
return 0; |
} |
static int set_pages_array_uc(struct page **pages, int addrinarray) |
{ |
#ifdef TTM_HAS_AGP |
int i; |
for (i = 0; i < addrinarray; i++) |
map_page_into_agp(pages[i]); |
#endif |
return 0; |
} |
#endif |
/** |
* Select the right pool or requested caching state and ttm flags. */ |
static struct ttm_page_pool *ttm_get_pool(int flags, |
282,8 → 151,6 |
static void ttm_pages_put(struct page *pages[], unsigned npages) |
{ |
unsigned i; |
if (set_pages_array_wb(pages, npages)) |
pr_err("Failed to set %d pages to wb!\n", npages); |
for (i = 0; i < npages; ++i) |
__free_page(pages[i]); |
} |
295,407 → 162,21 |
pool->nfrees += freed_pages; |
} |
/** |
* Free pages from pool. |
* |
* To prevent hogging the ttm_swap process we only free NUM_PAGES_TO_ALLOC |
* number of pages in one go. |
* |
* @pool: to free the pages from |
* @free_all: If set to true will free all pages in pool |
**/ |
static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free) |
{ |
unsigned long irq_flags; |
struct page *p; |
struct page **pages_to_free; |
unsigned freed_pages = 0, |
npages_to_free = nr_free; |
if (NUM_PAGES_TO_ALLOC < nr_free) |
npages_to_free = NUM_PAGES_TO_ALLOC; |
pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), |
GFP_KERNEL); |
if (!pages_to_free) { |
pr_err("Failed to allocate memory for pool free operation\n"); |
return 0; |
} |
restart: |
spin_lock_irqsave(&pool->lock, irq_flags); |
list_for_each_entry_reverse(p, &pool->list, lru) { |
if (freed_pages >= npages_to_free) |
break; |
pages_to_free[freed_pages++] = p; |
/* We can only remove NUM_PAGES_TO_ALLOC at a time. */ |
if (freed_pages >= NUM_PAGES_TO_ALLOC) { |
/* remove range of pages from the pool */ |
__list_del(p->lru.prev, &pool->list); |
ttm_pool_update_free_locked(pool, freed_pages); |
/** |
* Because changing page caching is costly |
* we unlock the pool to prevent stalling. |
*/ |
spin_unlock_irqrestore(&pool->lock, irq_flags); |
ttm_pages_put(pages_to_free, freed_pages); |
if (likely(nr_free != FREE_ALL_PAGES)) |
nr_free -= freed_pages; |
if (NUM_PAGES_TO_ALLOC >= nr_free) |
npages_to_free = nr_free; |
else |
npages_to_free = NUM_PAGES_TO_ALLOC; |
freed_pages = 0; |
/* free all so restart the processing */ |
if (nr_free) |
goto restart; |
/* Not allowed to fall through or break because |
* following context is inside spinlock while we are |
* outside here. |
*/ |
goto out; |
} |
} |
/* remove range of pages from the pool */ |
if (freed_pages) { |
__list_del(&p->lru, &pool->list); |
ttm_pool_update_free_locked(pool, freed_pages); |
nr_free -= freed_pages; |
} |
spin_unlock_irqrestore(&pool->lock, irq_flags); |
if (freed_pages) |
ttm_pages_put(pages_to_free, freed_pages); |
out: |
kfree(pages_to_free); |
return nr_free; |
} |
/** |
* Callback for mm to request pool to reduce number of page held. |
* |
* XXX: (dchinner) Deadlock warning! |
* |
* ttm_page_pool_free() does memory allocation using GFP_KERNEL. that means |
* this can deadlock when called a sc->gfp_mask that is not equal to |
* GFP_KERNEL. |
* |
* This code is crying out for a shrinker per pool.... |
*/ |
static unsigned long |
ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) |
{ |
static atomic_t start_pool = ATOMIC_INIT(0); |
unsigned i; |
unsigned pool_offset = atomic_add_return(1, &start_pool); |
struct ttm_page_pool *pool; |
int shrink_pages = sc->nr_to_scan; |
unsigned long freed = 0; |
pool_offset = pool_offset % NUM_POOLS; |
/* select start pool in round robin fashion */ |
for (i = 0; i < NUM_POOLS; ++i) { |
unsigned nr_free = shrink_pages; |
if (shrink_pages == 0) |
break; |
pool = &_manager->pools[(i + pool_offset)%NUM_POOLS]; |
shrink_pages = ttm_page_pool_free(pool, nr_free); |
freed += nr_free - shrink_pages; |
} |
return freed; |
} |
static unsigned long |
ttm_pool_shrink_count(struct shrinker *shrink, struct shrink_control *sc) |
{ |
unsigned i; |
unsigned long count = 0; |
for (i = 0; i < NUM_POOLS; ++i) |
count += _manager->pools[i].npages; |
return count; |
} |
static void ttm_pool_mm_shrink_init(struct ttm_pool_manager *manager) |
{ |
manager->mm_shrink.count_objects = ttm_pool_shrink_count; |
manager->mm_shrink.scan_objects = ttm_pool_shrink_scan; |
manager->mm_shrink.seeks = 1; |
register_shrinker(&manager->mm_shrink); |
} |
static void ttm_pool_mm_shrink_fini(struct ttm_pool_manager *manager) |
{ |
unregister_shrinker(&manager->mm_shrink); |
} |
static int ttm_set_pages_caching(struct page **pages, |
enum ttm_caching_state cstate, unsigned cpages) |
{ |
int r = 0; |
/* Set page caching */ |
switch (cstate) { |
case tt_uncached: |
r = set_pages_array_uc(pages, cpages); |
if (r) |
pr_err("Failed to set %d pages to uc!\n", cpages); |
break; |
case tt_wc: |
r = set_pages_array_wc(pages, cpages); |
if (r) |
pr_err("Failed to set %d pages to wc!\n", cpages); |
break; |
default: |
break; |
} |
return r; |
} |
/** |
* Free pages the pages that failed to change the caching state. If there is |
* any pages that have changed their caching state already put them to the |
* pool. |
*/ |
static void ttm_handle_caching_state_failure(struct list_head *pages, |
int ttm_flags, enum ttm_caching_state cstate, |
struct page **failed_pages, unsigned cpages) |
{ |
unsigned i; |
/* Failed pages have to be freed */ |
for (i = 0; i < cpages; ++i) { |
list_del(&failed_pages[i]->lru); |
__free_page(failed_pages[i]); |
} |
} |
/** |
* Allocate new pages with correct caching. |
* |
* This function is reentrant if caller updates count depending on number of |
* pages returned in pages array. |
*/ |
static int ttm_alloc_new_pages(struct list_head *pages, gfp_t gfp_flags, |
int ttm_flags, enum ttm_caching_state cstate, unsigned count) |
{ |
struct page **caching_array; |
struct page *p; |
int r = 0; |
unsigned i, cpages; |
unsigned max_cpages = min(count, |
(unsigned)(PAGE_SIZE/sizeof(struct page *))); |
/* allocate array for page caching change */ |
caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL); |
if (!caching_array) { |
pr_err("Unable to allocate table for new pages\n"); |
return -ENOMEM; |
} |
for (i = 0, cpages = 0; i < count; ++i) { |
p = alloc_page(gfp_flags); |
if (!p) { |
pr_err("Unable to get page %u\n", i); |
/* store already allocated pages in the pool after |
* setting the caching state */ |
if (cpages) { |
r = ttm_set_pages_caching(caching_array, |
cstate, cpages); |
if (r) |
ttm_handle_caching_state_failure(pages, |
ttm_flags, cstate, |
caching_array, cpages); |
} |
r = -ENOMEM; |
goto out; |
} |
#ifdef CONFIG_HIGHMEM |
/* gfp flags of highmem page should never be dma32 so we |
* we should be fine in such case |
*/ |
if (!PageHighMem(p)) |
#endif |
{ |
caching_array[cpages++] = p; |
if (cpages == max_cpages) { |
r = ttm_set_pages_caching(caching_array, |
cstate, cpages); |
if (r) { |
ttm_handle_caching_state_failure(pages, |
ttm_flags, cstate, |
caching_array, cpages); |
goto out; |
} |
cpages = 0; |
} |
} |
list_add(&p->lru, pages); |
} |
if (cpages) { |
r = ttm_set_pages_caching(caching_array, cstate, cpages); |
if (r) |
ttm_handle_caching_state_failure(pages, |
ttm_flags, cstate, |
caching_array, cpages); |
} |
out: |
kfree(caching_array); |
return r; |
} |
/** |
* Fill the given pool if there aren't enough pages and the requested number of |
* pages is small. |
*/ |
static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool, |
int ttm_flags, enum ttm_caching_state cstate, unsigned count, |
unsigned long *irq_flags) |
{ |
struct page *p; |
int r; |
unsigned cpages = 0; |
/** |
* Only allow one pool fill operation at a time. |
* If pool doesn't have enough pages for the allocation new pages are |
* allocated from outside of pool. |
*/ |
if (pool->fill_lock) |
return; |
pool->fill_lock = true; |
/* If allocation request is small and there are not enough |
* pages in a pool we fill the pool up first. */ |
if (count < _manager->options.small |
&& count > pool->npages) { |
struct list_head new_pages; |
unsigned alloc_size = _manager->options.alloc_size; |
/** |
* Can't change page caching if in irqsave context. We have to |
* drop the pool->lock. |
*/ |
spin_unlock_irqrestore(&pool->lock, *irq_flags); |
INIT_LIST_HEAD(&new_pages); |
r = ttm_alloc_new_pages(&new_pages, pool->gfp_flags, ttm_flags, |
cstate, alloc_size); |
spin_lock_irqsave(&pool->lock, *irq_flags); |
if (!r) { |
list_splice(&new_pages, &pool->list); |
++pool->nrefills; |
pool->npages += alloc_size; |
} else { |
pr_err("Failed to fill pool (%p)\n", pool); |
/* If we have any pages left put them to the pool. */ |
list_for_each_entry(p, &pool->list, lru) { |
++cpages; |
} |
list_splice(&new_pages, &pool->list); |
pool->npages += cpages; |
} |
} |
pool->fill_lock = false; |
} |
/** |
* Cut 'count' number of pages from the pool and put them on the return list. |
* |
* @return count of pages still required to fulfill the request. |
*/ |
static unsigned ttm_page_pool_get_pages(struct ttm_page_pool *pool, |
struct list_head *pages, |
int ttm_flags, |
enum ttm_caching_state cstate, |
unsigned count) |
{ |
unsigned long irq_flags; |
struct list_head *p; |
unsigned i; |
spin_lock_irqsave(&pool->lock, irq_flags); |
ttm_page_pool_fill_locked(pool, ttm_flags, cstate, count, &irq_flags); |
if (count >= pool->npages) { |
/* take all pages from the pool */ |
list_splice_init(&pool->list, pages); |
count -= pool->npages; |
pool->npages = 0; |
goto out; |
} |
/* find the last pages to include for requested number of pages. Split |
* pool to begin and halve it to reduce search space. */ |
if (count <= pool->npages/2) { |
i = 0; |
list_for_each(p, &pool->list) { |
if (++i == count) |
break; |
} |
} else { |
i = pool->npages + 1; |
list_for_each_prev(p, &pool->list) { |
if (--i == count) |
break; |
} |
} |
/* Cut 'count' number of pages from the pool */ |
list_cut_position(pages, &pool->list, p); |
pool->npages -= count; |
count = 0; |
out: |
spin_unlock_irqrestore(&pool->lock, irq_flags); |
return count; |
} |
#endif |
/* Put all pages in pages list to correct pool to wait for reuse */ |
static void ttm_put_pages(struct page **pages, unsigned npages, int flags, |
enum ttm_caching_state cstate) |
{ |
unsigned long irq_flags; |
// struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); |
struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); |
unsigned i; |
for (i = 0; i < npages; i++) { |
if (pages[i]) { |
// if (page_count(pages[i]) != 1) |
// pr_err("Erroneous page count. Leaking pages.\n"); |
FreePage(pages[i]); |
pages[i] = NULL; |
} |
} |
return; |
#if 0 |
if (pool == NULL) { |
if (1) { |
/* No pool for this memory type so free the pages */ |
for (i = 0; i < npages; i++) { |
if (pages[i]) { |
if (page_count(pages[i]) != 1) |
pr_err("Erroneous page count. Leaking pages.\n"); |
__free_page(pages[i]); |
pages[i] = NULL; |
} |
703,32 → 184,8 |
return; |
} |
spin_lock_irqsave(&pool->lock, irq_flags); |
for (i = 0; i < npages; i++) { |
if (pages[i]) { |
if (page_count(pages[i]) != 1) |
pr_err("Erroneous page count. Leaking pages.\n"); |
list_add_tail(&pages[i]->lru, &pool->list); |
pages[i] = NULL; |
pool->npages++; |
} |
} |
/* Check that we don't go over the pool limit */ |
npages = 0; |
if (pool->npages > _manager->options.max_size) { |
npages = pool->npages - _manager->options.max_size; |
/* free at least NUM_PAGES_TO_ALLOC number of pages |
* to reduce calls to set_memory_wb */ |
if (npages < NUM_PAGES_TO_ALLOC) |
npages = NUM_PAGES_TO_ALLOC; |
} |
spin_unlock_irqrestore(&pool->lock, irq_flags); |
if (npages) |
ttm_page_pool_free(pool, npages); |
#endif |
} |
/* |
* On success pages list will hold count number of correctly |
* cached pages. |
736,44 → 193,21 |
static int ttm_get_pages(struct page **pages, unsigned npages, int flags, |
enum ttm_caching_state cstate) |
{ |
// struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); |
struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); |
struct list_head plist; |
struct page *p = NULL; |
// gfp_t gfp_flags = GFP_USER; |
gfp_t gfp_flags = 0; |
unsigned count; |
int r; |
for (r = 0; r < npages; ++r) { |
p = AllocPage(); |
if (!p) { |
pr_err("Unable to allocate page\n"); |
return -ENOMEM; |
} |
pages[r] = p; |
} |
return 0; |
#if 0 |
/* set zero flag for page allocation if required */ |
if (flags & TTM_PAGE_FLAG_ZERO_ALLOC) |
gfp_flags |= __GFP_ZERO; |
/* No pool for cached pages */ |
if (pool == NULL) { |
if (flags & TTM_PAGE_FLAG_DMA32) |
gfp_flags |= GFP_DMA32; |
else |
gfp_flags |= GFP_HIGHUSER; |
if (1) { |
for (r = 0; r < npages; ++r) { |
p = alloc_page(gfp_flags); |
if (!p) { |
pr_err("Unable to allocate page\n"); |
return -ENOMEM; |
} |
782,52 → 216,12 |
return 0; |
} |
/* combine zero flag to pool flags */ |
gfp_flags |= pool->gfp_flags; |
/* First we take pages from the pool */ |
INIT_LIST_HEAD(&plist); |
npages = ttm_page_pool_get_pages(pool, &plist, flags, cstate, npages); |
count = 0; |
list_for_each_entry(p, &plist, lru) { |
pages[count++] = p; |
} |
/* clear the pages coming from the pool if requested */ |
if (flags & TTM_PAGE_FLAG_ZERO_ALLOC) { |
list_for_each_entry(p, &plist, lru) { |
if (PageHighMem(p)) |
clear_highpage(p); |
else |
clear_page(page_address(p)); |
} |
} |
/* If pool didn't have enough pages allocate new one. */ |
if (npages > 0) { |
/* ttm_alloc_new_pages doesn't reference pool so we can run |
* multiple requests in parallel. |
**/ |
INIT_LIST_HEAD(&plist); |
r = ttm_alloc_new_pages(&plist, gfp_flags, flags, cstate, npages); |
list_for_each_entry(p, &plist, lru) { |
pages[count++] = p; |
} |
if (r) { |
/* If there is any pages in the list put them back to |
* the pool. */ |
pr_err("Failed to allocate extra pages for large request\n"); |
ttm_put_pages(pages, count, flags, cstate); |
return r; |
} |
} |
#endif |
return 0; |
} |
#if 0 |
static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, int flags, |
static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, gfp_t flags, |
char *name) |
{ |
spin_lock_init(&pool->lock); |
844,34 → 238,12 |
WARN_ON(_manager); |
pr_info("Initializing pool allocator\n"); |
_manager = kzalloc(sizeof(*_manager), GFP_KERNEL); |
ttm_page_pool_init_locked(&_manager->wc_pool, GFP_HIGHUSER, "wc"); |
ttm_page_pool_init_locked(&_manager->uc_pool, GFP_HIGHUSER, "uc"); |
ttm_page_pool_init_locked(&_manager->wc_pool_dma32, |
GFP_USER | GFP_DMA32, "wc dma"); |
ttm_page_pool_init_locked(&_manager->uc_pool_dma32, |
GFP_USER | GFP_DMA32, "uc dma"); |
_manager->options.max_size = max_pages; |
_manager->options.small = SMALL_ALLOCATION; |
_manager->options.alloc_size = NUM_PAGES_TO_ALLOC; |
ret = kobject_init_and_add(&_manager->kobj, &ttm_pool_kobj_type, |
&glob->kobj, "pool"); |
if (unlikely(ret != 0)) { |
kobject_put(&_manager->kobj); |
_manager = NULL; |
return ret; |
} |
ttm_pool_mm_shrink_init(_manager); |
return 0; |
} |
879,18 → 251,9 |
{ |
int i; |
pr_info("Finalizing pool allocator\n"); |
ttm_pool_mm_shrink_fini(_manager); |
for (i = 0; i < NUM_POOLS; ++i) |
ttm_page_pool_free(&_manager->pools[i], FREE_ALL_PAGES); |
kobject_put(&_manager->kobj); |
_manager = NULL; |
} |
#endif |
int ttm_pool_populate(struct ttm_tt *ttm) |
{ |
struct ttm_mem_global *mem_glob = ttm->glob->mem_glob; |
908,9 → 271,7 |
ttm_pool_unpopulate(ttm); |
return -ENOMEM; |
} |
} |
ttm->state = tt_unbound; |
return 0; |
} |
922,8 → 283,6 |
for (i = 0; i < ttm->num_pages; ++i) { |
if (ttm->pages[i]) { |
ttm_mem_global_free_page(ttm->glob->mem_glob, |
ttm->pages[i]); |
ttm_put_pages(&ttm->pages[i], 1, |
ttm->page_flags, |
ttm->caching_state); |
/drivers/video/drm/ttm/ttm_tt.c |
---|
57,9 → 57,12 |
static void ttm_dma_tt_alloc_page_directory(struct ttm_dma_tt *ttm) |
{ |
ttm->ttm.pages = drm_calloc_large(ttm->ttm.num_pages, sizeof(void*)); |
ttm->dma_address = drm_calloc_large(ttm->ttm.num_pages, |
sizeof(*ttm->dma_address)); |
ttm->ttm.pages = drm_calloc_large(ttm->ttm.num_pages, |
sizeof(*ttm->ttm.pages) + |
sizeof(*ttm->dma_address) + |
sizeof(*ttm->cpu_address)); |
ttm->cpu_address = (void *) (ttm->ttm.pages + ttm->ttm.num_pages); |
ttm->dma_address = (void *) (ttm->cpu_address + ttm->ttm.num_pages); |
} |
#ifdef CONFIG_X86 |
118,8 → 121,8 |
return 0; |
} |
// if (ttm->caching_state == tt_cached) |
// drm_clflush_pages(ttm->pages, ttm->num_pages); |
if (ttm->caching_state == tt_cached) |
drm_clflush_pages(ttm->pages, ttm->num_pages); |
for (i = 0; i < ttm->num_pages; ++i) { |
cur_page = ttm->pages[i]; |
172,8 → 175,8 |
ttm_tt_unbind(ttm); |
} |
// if (ttm->state == tt_unbound) |
// ttm_tt_unpopulate(ttm); |
if (ttm->state == tt_unbound) |
ttm_tt_unpopulate(ttm); |
// if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP) && |
// ttm->swap_storage) |
230,7 → 233,7 |
INIT_LIST_HEAD(&ttm_dma->pages_list); |
ttm_dma_tt_alloc_page_directory(ttm_dma); |
if (!ttm->pages || !ttm_dma->dma_address) { |
if (!ttm->pages) { |
ttm_tt_destroy(ttm); |
printf("Failed allocating page table\n"); |
return -ENOMEM; |
245,7 → 248,7 |
drm_free_large(ttm->pages); |
ttm->pages = NULL; |
drm_free_large(ttm_dma->dma_address); |
ttm_dma->cpu_address = NULL; |
ttm_dma->dma_address = NULL; |
} |
EXPORT_SYMBOL(ttm_dma_tt_fini); |
261,8 → 264,6 |
} |
} |
#if 0 |
int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) |
{ |
int ret = 0; |
286,9 → 287,8 |
return 0; |
} |
EXPORT_SYMBOL(ttm_tt_bind); |
#endif |
/* |
#if 0 |
int ttm_tt_swapin(struct ttm_tt *ttm) |
{ |
struct address_space *swap_space; |
380,7 → 380,20 |
return ret; |
} |
#endif |
*/ |
static void ttm_tt_clear_mapping(struct ttm_tt *ttm) |
{ |
pgoff_t i; |
struct page **page = ttm->pages; |
} |
void ttm_tt_unpopulate(struct ttm_tt *ttm) |
{ |
if (ttm->state == tt_unpopulated) |
return; |
ttm_tt_clear_mapping(ttm); |
ttm->bdev->driver->ttm_tt_unpopulate(ttm); |
} |
/drivers/video/drm/vmwgfx/Makefile |
---|
1,4 → 1,5 |
CC = gcc |
LD = ld |
AS = as |
13,7 → 14,7 |
INCLUDES = -I$(DRV_INCLUDES) -I$(DRV_INCLUDES)/drm \ |
-I$(DRV_INCLUDES)/linux -I$(DRV_INCLUDES)/linux/uapi |
CFLAGS = -c -O2 $(INCLUDES) -march=i686 -fomit-frame-pointer -fno-builtin-printf |
CFLAGS = -c -Os $(INCLUDES) -fomit-frame-pointer -fno-builtin-printf |
CFLAGS+= -mno-ms-bitfields |
LIBPATH:= $(DRV_TOPDIR)/ddk |
93,7 → 94,6 |
$(NAME).dll: $(NAME_OBJS) $(LIBPATH)/libcore.a $(LIBPATH)/libddk.a vmw.lds Makefile |
$(LD) -L$(LIBPATH) $(LDFLAGS) -T vmw.lds -o $@ $(NAME_OBJS) $(LIBS) |
kpack $@ |
%.o : %.c $(HFILES) Makefile |
/drivers/video/drm/vmwgfx/Makefile.lto |
---|
6,19 → 6,18 |
DEFINES = -D__KERNEL__ -DCONFIG_X86_32 |
DRV_TOPDIR = $(CURDIR)/../../.. |
DDK_TOPDIR = /d/kos/kolibri/drivers/ddk |
DRV_INCLUDES = /d/kos/kolibri/drivers/include |
DRM_TOPDIR = $(CURDIR)/.. |
DRV_INCLUDES = $(DRV_TOPDIR)/include |
INCLUDES = -I$(DRV_INCLUDES) -I$(DRV_INCLUDES)/drm \ |
-I$(DRV_INCLUDES)/linux |
-I$(DRV_INCLUDES)/linux -I$(DRV_INCLUDES)/linux/uapi |
CFLAGS_OPT = -Os -march=i686 -msse2 -fomit-frame-pointer -fno-builtin-printf -mno-stack-arg-probe |
CFLAGS_OPT = -Os -fomit-frame-pointer -fno-builtin-printf -mno-stack-arg-probe |
CFLAGS_OPT+= -mpreferred-stack-boundary=2 -mincoming-stack-boundary=2 -mno-ms-bitfields -flto |
CFLAGS = -c $(INCLUDES) $(DEFINES) $(CFLAGS_OPT) |
LIBPATH:= $(DRV_TOPDIR)/ddk |
LIBPATH:= ../../../ddk |
LIBS:= -lddk -lcore -lgcc |
52,8 → 51,10 |
vmwgfx_irq.c \ |
vmwgfx_kms.c \ |
vmwgfx_marker.c \ |
vmwgfx_mob.c \ |
vmwgfx_resource.c \ |
vmwgfx_scrn.c \ |
vmwgfx_shader.c \ |
vmwgfx_surface.c \ |
vmwgfx_ttm_glue.c \ |
../hdmi.c \ |
61,6 → 62,7 |
../ttm/ttm_bo.c \ |
../ttm/ttm_bo_manager.c \ |
../ttm/ttm_execbuf_util.c \ |
../ttm/ttm_lock.c \ |
../ttm/ttm_memory.c \ |
../ttm/ttm_object.c \ |
../ttm/ttm_page_alloc.c \ |
90,7 → 92,7 |
all: $(NAME).dll |
$(NAME).dll: $(NAME_OBJS) $(SRC_DEP) $(HFILES) vmw.lds Makefile |
$(CC) $(CFLAGS_OPT) -fwhole-program -nostdlib -Wl,-L$(LIBPATH),$(LDFLAGS),-T,vmw.lds -o $@ $(NAME_OBJS) libddk.a libcore.a libgcc.a |
$(CC) $(CFLAGS_OPT) -fwhole-program -nostdlib -Wl,-L$(LIBPATH),$(LDFLAGS),-T,vmw.lds -o $@ $(NAME_OBJS) $(LIBS) |
kpack $@ |
101,6 → 103,5 |
as -o $@ $< |
clean: |
-rm -f */*.o |
/drivers/video/drm/vmwgfx/main.c |
---|
31,22 → 31,14 |
int vmw_init(void); |
int kms_init(struct drm_device *dev); |
void vmw_driver_thread(); |
void kms_update(); |
void cpu_detect(); |
void parse_cmdline(char *cmdline, char *log); |
int _stdcall display_handler(ioctl_t *io); |
int srv_blit_bitmap(u32 hbitmap, int dst_x, int dst_y, |
int src_x, int src_y, u32 w, u32 h); |
int blit_textured(u32 hbitmap, int dst_x, int dst_y, |
int src_x, int src_y, u32 w, u32 h); |
int blit_tex(u32 hbitmap, int dst_x, int dst_y, |
int src_x, int src_y, u32 w, u32 h); |
void get_pci_info(struct pci_device *dev); |
int gem_getparam(struct drm_device *dev, void *data); |
64,23 → 56,6 |
int kms_modeset = 1; |
void vmw_driver_thread() |
{ |
dbgprintf("%s\n",__FUNCTION__); |
// run_workqueue(dev_priv->wq); |
while(driver_wq_state) |
{ |
kms_update(); |
delay(1); |
}; |
__asm__ __volatile__ ( |
"int $0x40" |
::"a"(-1)); |
} |
u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline) |
{ |
203,9 → 178,9 |
break; |
case SRV_ENUM_MODES: |
dbgprintf("SRV_ENUM_MODES inp %x inp_size %x out_size %x\n", |
inp, io->inp_size, io->out_size ); |
check_output(4); |
// dbgprintf("SRV_ENUM_MODES inp %x inp_size %x out_size %x\n", |
// inp, io->inp_size, io->out_size ); |
// check_output(4); |
// check_input(*outp * sizeof(videomode_t)); |
if( kms_modeset) |
retval = get_videomodes((videomode_t*)inp, outp); |
212,9 → 187,9 |
break; |
case SRV_SET_MODE: |
dbgprintf("SRV_SET_MODE inp %x inp_size %x\n", |
inp, io->inp_size); |
check_input(sizeof(videomode_t)); |
// dbgprintf("SRV_SET_MODE inp %x inp_size %x\n", |
// inp, io->inp_size); |
// check_input(sizeof(videomode_t)); |
if( kms_modeset ) |
retval = set_user_mode((videomode_t*)inp); |
break; |
830,6 → 805,7 |
uint32_t hot_y; |
struct list_head list; |
void *priv; |
}cursor_t; |
#define CURSOR_WIDTH 64 |
865,9 → 841,8 |
u32 check_m_pixel; |
}; |
display_t *os_display; |
static display_t *os_display; |
static int count_connector_modes(struct drm_connector* connector) |
{ |
struct drm_display_mode *mode; |
889,6 → 864,8 |
struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
du->cursor_x = x; |
du->cursor_y = y; |
vmw_cursor_update_position(dev_priv, true, x,y); |
}; |
895,6 → 872,7 |
static cursor_t* __stdcall select_cursor_kms(cursor_t *cursor) |
{ |
struct vmw_private *dev_priv = vmw_priv(os_display->ddev); |
struct vmw_display_unit *du = vmw_crtc_to_du(os_display->crtc); |
cursor_t *old; |
old = os_display->cursor; |
902,30 → 880,38 |
vmw_cursor_update_image(dev_priv, cursor->data, |
64, 64, cursor->hot_x, cursor->hot_y); |
vmw_cursor_update_position(dev_priv, true, |
du->cursor_x, du->cursor_y); |
return old; |
}; |
// vmw_cursor_update_position(dev_priv, true, |
// du->cursor_x + du->hotspot_x, |
// du->cursor_y + du->hotspot_y); |
void vmw_driver_thread() |
{ |
DRM_DEBUG_KMS("%s\n",__FUNCTION__); |
return old; |
select_cursor_kms(os_display->cursor); |
while(driver_wq_state) |
{ |
kms_update(); |
delay(2); |
}; |
__asm__ __volatile__ ( |
"int $0x40" |
::"a"(-1)); |
} |
int kms_init(struct drm_device *dev) |
{ |
struct drm_connector *connector; |
struct drm_connector_helper_funcs *connector_funcs; |
struct drm_encoder *encoder; |
struct drm_crtc *crtc = NULL; |
struct drm_framebuffer *fb; |
struct vmw_display_unit *du; |
cursor_t *cursor; |
int mode_count; |
u32_t ifl; |
int err; |
ENTER(); |
crtc = list_entry(dev->mode_config.crtc_list.next, typeof(*crtc), head); |
encoder = list_entry(dev->mode_config.encoder_list.next, typeof(*encoder), head); |
connector = list_entry(dev->mode_config.connector_list.next, typeof(*connector), head); |
944,24 → 930,20 |
mode_count++; |
}; |
printf("%s %d\n",__FUNCTION__, mode_count); |
DRM_DEBUG_KMS("CONNECTOR %x ID:%d status:%d ENCODER %x CRTC %x ID:%d\n", |
connector, connector->base.id, |
connector->status, connector->encoder, |
crtc, crtc->base.id ); |
DRM_DEBUG_KMS("[Select CRTC:%d]\n", crtc->base.id); |
os_display = GetDisplay(); |
ifl = safe_cli(); |
{ |
os_display->ddev = dev; |
os_display->connector = connector; |
os_display->crtc = crtc; |
os_display->supported_modes = mode_count; |
ifl = safe_cli(); |
{ |
os_display->restore_cursor(0,0); |
os_display->select_cursor = select_cursor_kms; |
os_display->show_cursor = NULL; |
968,16 → 950,14 |
os_display->move_cursor = move_cursor_kms; |
os_display->restore_cursor = restore_cursor; |
os_display->disable_mouse = disable_mouse; |
select_cursor_kms(os_display->cursor); |
}; |
safe_sti(ifl); |
#ifdef __HWA__ |
err = init_bitmaps(); |
#endif |
du = vmw_crtc_to_du(os_display->crtc); |
du->cursor_x = os_display->width/2; |
du->cursor_y = os_display->height/2; |
select_cursor_kms(os_display->cursor); |
LEAVE(); |
return 0; |
}; |
986,6 → 966,7 |
{ |
struct vmw_private *dev_priv = vmw_priv(main_device); |
size_t fifo_size; |
u32_t ifl; |
int i; |
struct { |
1004,8 → 985,8 |
cmd->header = cpu_to_le32(SVGA_CMD_UPDATE); |
cmd->body.x = 0; |
cmd->body.y = 0; |
cmd->body.width = os_display->width; //cpu_to_le32(clips->x2 - clips->x1); |
cmd->body.height = os_display->height; //cpu_to_le32(clips->y2 - clips->y1); |
cmd->body.width = os_display->width; |
cmd->body.height = os_display->height; |
vmw_fifo_commit(dev_priv, fifo_size); |
} |
1012,10 → 993,9 |
int get_videomodes(videomode_t *mode, int *count) |
{ |
struct drm_display_mode *drmmode; |
int err = -1; |
dbgprintf("mode %x count %d\n", mode, *count); |
if( *count == 0 ) |
{ |
*count = os_display->supported_modes; |
1023,7 → 1003,6 |
} |
else if( mode != NULL ) |
{ |
struct drm_display_mode *drmmode; |
int i = 0; |
if( *count > os_display->supported_modes) |
1036,15 → 1015,17 |
mode->width = drm_mode_width(drmmode); |
mode->height = drm_mode_height(drmmode); |
mode->bpp = 32; |
mode->freq = drm_mode_vrefresh(drmmode); |
mode->freq = drmmode->vrefresh; |
i++; |
mode++; |
} |
else break; |
}; |
*count = i; |
err = 0; |
}; |
return err; |
}; |
/drivers/video/drm/vmwgfx/svga3d_reg.h |
---|
261,12 → 261,7 |
/* Planar video formats. */ |
SVGA3D_YV12 = 121, |
/* Shader constant formats. */ |
SVGA3D_SURFACE_SHADERCONST_FLOAT = 122, |
SVGA3D_SURFACE_SHADERCONST_INT = 123, |
SVGA3D_SURFACE_SHADERCONST_BOOL = 124, |
SVGA3D_FORMAT_MAX = 125, |
SVGA3D_FORMAT_MAX = 122, |
} SVGA3dSurfaceFormat; |
typedef uint32 SVGA3dColor; /* a, r, g, b */ |
1223,10 → 1218,20 |
#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL 1129 |
#define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE 1130 |
#define SVGA_3D_CMD_GB_SCREEN_DMA 1131 |
#define SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH 1132 |
#define SVGA_3D_CMD_GB_MOB_FENCE 1133 |
#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 1134 |
#define SVGA_3D_CMD_DEFINE_GB_MOB64 1135 |
#define SVGA_3D_CMD_REDEFINE_GB_MOB64 1136 |
#define SVGA_3D_CMD_NOP_ERROR 1137 |
#define SVGA_3D_CMD_RESERVED1 1138 |
#define SVGA_3D_CMD_RESERVED2 1139 |
#define SVGA_3D_CMD_RESERVED3 1140 |
#define SVGA_3D_CMD_RESERVED4 1141 |
#define SVGA_3D_CMD_RESERVED5 1142 |
#define SVGA_3D_CMD_MAX 1142 |
#define SVGA_3D_CMD_FUTURE_MAX 3000 |
1973,8 → 1978,7 |
uint32 sizeInBytes; |
uint32 validSizeInBytes; |
SVGAMobFormat ptDepth; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdSetOTableBase; /* SVGA_3D_CMD_SET_OTABLE_BASE */ |
typedef |
1984,15 → 1988,13 |
uint32 sizeInBytes; |
uint32 validSizeInBytes; |
SVGAMobFormat ptDepth; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdSetOTableBase64; /* SVGA_3D_CMD_SET_OTABLE_BASE64 */ |
typedef |
struct { |
SVGAOTableType type; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdReadbackOTable; /* SVGA_3D_CMD_READBACK_OTABLE */ |
/* |
2005,8 → 2007,7 |
SVGAMobFormat ptDepth; |
PPN base; |
uint32 sizeInBytes; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */ |
2017,8 → 2018,7 |
typedef |
struct SVGA3dCmdDestroyGBMob { |
SVGAMobId mobid; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdDestroyGBMob; /* SVGA_3D_CMD_DESTROY_GB_MOB */ |
/* |
2031,8 → 2031,7 |
SVGAMobFormat ptDepth; |
PPN base; |
uint32 sizeInBytes; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdRedefineGBMob; /* SVGA_3D_CMD_REDEFINE_GB_MOB */ |
/* |
2045,8 → 2044,7 |
SVGAMobFormat ptDepth; |
PPN64 base; |
uint32 sizeInBytes; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdDefineGBMob64; /* SVGA_3D_CMD_DEFINE_GB_MOB64 */ |
/* |
2059,8 → 2057,7 |
SVGAMobFormat ptDepth; |
PPN64 base; |
uint32 sizeInBytes; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */ |
/* |
2070,8 → 2067,7 |
typedef |
struct SVGA3dCmdUpdateGBMobMapping { |
SVGAMobId mobid; |
} |
__attribute__((__packed__)) |
} __packed |
SVGA3dCmdUpdateGBMobMapping; /* SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING */ |
/* |
2087,7 → 2083,8 |
uint32 multisampleCount; |
SVGA3dTextureFilter autogenFilter; |
SVGA3dSize size; |
} SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */ |
} __packed |
SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */ |
/* |
* Destroy a guest-backed surface. |
2096,7 → 2093,8 |
typedef |
struct SVGA3dCmdDestroyGBSurface { |
uint32 sid; |
} SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */ |
} __packed |
SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */ |
/* |
* Bind a guest-backed surface to an object. |
2106,7 → 2104,8 |
struct SVGA3dCmdBindGBSurface { |
uint32 sid; |
SVGAMobId mobid; |
} SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */ |
} __packed |
SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */ |
/* |
* Conditionally bind a mob to a guest backed surface if testMobid |
2123,7 → 2122,7 |
SVGAMobId testMobid; |
SVGAMobId mobid; |
uint32 flags; |
} |
} __packed |
SVGA3dCmdCondBindGBSurface; /* SVGA_3D_CMD_COND_BIND_GB_SURFACE */ |
/* |
2135,7 → 2134,8 |
struct SVGA3dCmdUpdateGBImage { |
SVGA3dSurfaceImageId image; |
SVGA3dBox box; |
} SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */ |
} __packed |
SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */ |
/* |
* Update an entire guest-backed surface. |
2145,7 → 2145,8 |
typedef |
struct SVGA3dCmdUpdateGBSurface { |
uint32 sid; |
} SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */ |
} __packed |
SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */ |
/* |
* Readback an image in a guest-backed surface. |
2155,7 → 2156,8 |
typedef |
struct SVGA3dCmdReadbackGBImage { |
SVGA3dSurfaceImageId image; |
} SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/ |
} __packed |
SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/ |
/* |
* Readback an entire guest-backed surface. |
2165,7 → 2167,8 |
typedef |
struct SVGA3dCmdReadbackGBSurface { |
uint32 sid; |
} SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */ |
} __packed |
SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */ |
/* |
* Readback a sub rect of an image in a guest-backed surface. After |
2179,7 → 2182,7 |
SVGA3dSurfaceImageId image; |
SVGA3dBox box; |
uint32 invertBox; |
} |
} __packed |
SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */ |
/* |
2190,7 → 2193,8 |
typedef |
struct SVGA3dCmdInvalidateGBImage { |
SVGA3dSurfaceImageId image; |
} SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */ |
} __packed |
SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */ |
/* |
* Invalidate an entire guest-backed surface. |
2200,7 → 2204,8 |
typedef |
struct SVGA3dCmdInvalidateGBSurface { |
uint32 sid; |
} SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */ |
} __packed |
SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */ |
/* |
* Invalidate a sub rect of an image in a guest-backed surface. After |
2214,7 → 2219,7 |
SVGA3dSurfaceImageId image; |
SVGA3dBox box; |
uint32 invertBox; |
} |
} __packed |
SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */ |
/* |
2224,7 → 2229,8 |
typedef |
struct SVGA3dCmdDefineGBContext { |
uint32 cid; |
} SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */ |
} __packed |
SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */ |
/* |
* Destroy a guest-backed context. |
2233,7 → 2239,8 |
typedef |
struct SVGA3dCmdDestroyGBContext { |
uint32 cid; |
} SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */ |
} __packed |
SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */ |
/* |
* Bind a guest-backed context. |
2252,7 → 2259,8 |
uint32 cid; |
SVGAMobId mobid; |
uint32 validContents; |
} SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */ |
} __packed |
SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */ |
/* |
* Readback a guest-backed context. |
2262,7 → 2270,8 |
typedef |
struct SVGA3dCmdReadbackGBContext { |
uint32 cid; |
} SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */ |
} __packed |
SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */ |
/* |
* Invalidate a guest-backed context. |
2270,7 → 2279,8 |
typedef |
struct SVGA3dCmdInvalidateGBContext { |
uint32 cid; |
} SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */ |
} __packed |
SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */ |
/* |
* Define a guest-backed shader. |
2281,7 → 2291,8 |
uint32 shid; |
SVGA3dShaderType type; |
uint32 sizeInBytes; |
} SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */ |
} __packed |
SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */ |
/* |
* Bind a guest-backed shader. |
2291,7 → 2302,8 |
uint32 shid; |
SVGAMobId mobid; |
uint32 offsetInBytes; |
} SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */ |
} __packed |
SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */ |
/* |
* Destroy a guest-backed shader. |
2299,7 → 2311,8 |
typedef struct SVGA3dCmdDestroyGBShader { |
uint32 shid; |
} SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */ |
} __packed |
SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */ |
typedef |
struct { |
2314,7 → 2327,8 |
* Note that FLOAT and INT constants are 4-dwords in length, while |
* BOOL constants are 1-dword in length. |
*/ |
} SVGA3dCmdSetGBShaderConstInline; |
} __packed |
SVGA3dCmdSetGBShaderConstInline; |
/* SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE */ |
typedef |
2321,7 → 2335,8 |
struct { |
uint32 cid; |
SVGA3dQueryType type; |
} SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */ |
} __packed |
SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */ |
typedef |
struct { |
2329,7 → 2344,8 |
SVGA3dQueryType type; |
SVGAMobId mobid; |
uint32 offset; |
} SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */ |
} __packed |
SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */ |
/* |
2346,7 → 2362,8 |
SVGA3dQueryType type; |
SVGAMobId mobid; |
uint32 offset; |
} SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */ |
} __packed |
SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */ |
typedef |
struct { |
2353,7 → 2370,7 |
SVGAMobId mobid; |
uint32 fbOffset; |
uint32 initalized; |
} |
} __packed |
SVGA3dCmdEnableGart; /* SVGA_3D_CMD_ENABLE_GART */ |
typedef |
2360,7 → 2377,7 |
struct { |
SVGAMobId mobid; |
uint32 gartOffset; |
} |
} __packed |
SVGA3dCmdMapMobIntoGart; /* SVGA_3D_CMD_MAP_MOB_INTO_GART */ |
2368,7 → 2385,7 |
struct { |
uint32 gartOffset; |
uint32 numPages; |
} |
} __packed |
SVGA3dCmdUnmapGartRange; /* SVGA_3D_CMD_UNMAP_GART_RANGE */ |
2385,13 → 2402,13 |
int32 xRoot; |
int32 yRoot; |
uint32 flags; |
} |
} __packed |
SVGA3dCmdDefineGBScreenTarget; /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */ |
typedef |
struct { |
uint32 stid; |
} |
} __packed |
SVGA3dCmdDestroyGBScreenTarget; /* SVGA_3D_CMD_DESTROY_GB_SCREENTARGET */ |
typedef |
2398,7 → 2415,7 |
struct { |
uint32 stid; |
SVGA3dSurfaceImageId image; |
} |
} __packed |
SVGA3dCmdBindGBScreenTarget; /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */ |
typedef |
2405,7 → 2422,7 |
struct { |
uint32 stid; |
SVGA3dBox box; |
} |
} __packed |
SVGA3dCmdUpdateGBScreenTarget; /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */ |
/* |
2583,4 → 2600,28 |
float f; |
} SVGA3dDevCapResult; |
typedef enum { |
SVGA3DCAPS_RECORD_UNKNOWN = 0, |
SVGA3DCAPS_RECORD_DEVCAPS_MIN = 0x100, |
SVGA3DCAPS_RECORD_DEVCAPS = 0x100, |
SVGA3DCAPS_RECORD_DEVCAPS_MAX = 0x1ff, |
} SVGA3dCapsRecordType; |
typedef |
struct SVGA3dCapsRecordHeader { |
uint32 length; |
SVGA3dCapsRecordType type; |
} |
SVGA3dCapsRecordHeader; |
typedef |
struct SVGA3dCapsRecord { |
SVGA3dCapsRecordHeader header; |
uint32 data[1]; |
} |
SVGA3dCapsRecord; |
typedef uint32 SVGA3dCapPair[2]; |
#endif /* _SVGA3D_REG_H_ */ |
/drivers/video/drm/vmwgfx/svga3d_surfacedefs.h |
---|
38,8 → 38,11 |
#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) |
#define max_t(type, x, y) ((x) > (y) ? (x) : (y)) |
#define min_t(type, x, y) ((x) < (y) ? (x) : (y)) |
#define surf_size_struct SVGA3dSize |
#define u32 uint32 |
#define u64 uint64_t |
#define U32_MAX ((u32)~0U) |
#endif /* __KERNEL__ */ |
704,8 → 707,8 |
static inline u32 clamped_umul32(u32 a, u32 b) |
{ |
uint64_t tmp = (uint64_t) a*b; |
return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp; |
u64 tmp = (u64) a*b; |
return (tmp > (u64) U32_MAX) ? U32_MAX : tmp; |
} |
static inline const struct svga3d_surface_desc * |
834,7 → 837,7 |
bool cubemap) |
{ |
const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format); |
u32 total_size = 0; |
u64 total_size = 0; |
u32 mip; |
for (mip = 0; mip < num_mip_levels; mip++) { |
847,7 → 850,7 |
if (cubemap) |
total_size *= SVGA3D_MAX_SURFACE_FACES; |
return total_size; |
return (u32) min_t(u64, total_size, (u64) U32_MAX); |
} |
/drivers/video/drm/vmwgfx/svga_reg.h |
---|
169,10 → 169,17 |
SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */ |
SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */ |
SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */ |
SVGA_REG_COMMAND_LOW = 48, /* Lower 32 bits and submits commands */ |
SVGA_REG_COMMAND_HIGH = 49, /* Upper 32 bits of command buffer PA */ |
SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, /* Max primary memory */ |
SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Suggested limit on mob mem */ |
SVGA_REG_DEV_CAP = 52, /* Write dev cap index, read value */ |
SVGA_REG_TOP = 53, /* Must be 1 more than the last register */ |
SVGA_REG_CMD_PREPEND_LOW = 53, |
SVGA_REG_CMD_PREPEND_HIGH = 54, |
SVGA_REG_SCREENTARGET_MAX_WIDTH = 55, |
SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56, |
SVGA_REG_MOB_MAX_SIZE = 57, |
SVGA_REG_TOP = 58, /* Must be 1 more than the last register */ |
SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ |
/* Next 768 (== 256*3) registers exist for colormap */ |
/drivers/video/drm/vmwgfx/vmwgfx_context.c |
---|
33,11 → 33,12 |
struct ttm_base_object base; |
struct vmw_resource res; |
struct vmw_ctx_binding_state cbs; |
struct vmw_cmdbuf_res_manager *man; |
}; |
typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *); |
typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *, bool); |
static void vmw_user_context_free(struct vmw_resource *res); |
static struct vmw_resource * |
50,9 → 51,11 |
bool readback, |
struct ttm_validate_buffer *val_buf); |
static int vmw_gb_context_destroy(struct vmw_resource *res); |
static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi); |
static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi); |
static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi); |
static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind); |
static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi, |
bool rebind); |
static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, bool rebind); |
static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs); |
static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs); |
static uint64_t vmw_user_context_size; |
101,7 → 104,8 |
static void vmw_hw_context_destroy(struct vmw_resource *res) |
{ |
struct vmw_user_context *uctx = |
container_of(res, struct vmw_user_context, res); |
struct vmw_private *dev_priv = res->dev_priv; |
struct { |
SVGA3dCmdHeader header; |
111,7 → 115,11 |
if (res->func->destroy == vmw_gb_context_destroy) { |
mutex_lock(&dev_priv->cmdbuf_mutex); |
vmw_cmdbuf_res_man_destroy(uctx->man); |
mutex_lock(&dev_priv->binding_mutex); |
(void) vmw_context_binding_state_kill(&uctx->cbs); |
(void) vmw_gb_context_destroy(res); |
mutex_unlock(&dev_priv->binding_mutex); |
if (dev_priv->pinned_bo != NULL && |
!dev_priv->query_cid_valid) |
__vmw_execbuf_release_pinned_bo(dev_priv, NULL); |
146,14 → 154,17 |
ret = vmw_resource_init(dev_priv, res, true, |
res_free, &vmw_gb_context_func); |
res->backup_size = SVGA3D_CONTEXT_DATA_SIZE; |
if (unlikely(ret != 0)) |
goto out_err; |
if (unlikely(ret != 0)) { |
if (res_free) |
res_free(res); |
else |
kfree(res); |
return ret; |
if (dev_priv->has_mob) { |
uctx->man = vmw_cmdbuf_res_man_create(dev_priv); |
if (unlikely(IS_ERR(uctx->man))) { |
ret = PTR_ERR(uctx->man); |
uctx->man = NULL; |
goto out_err; |
} |
} |
memset(&uctx->cbs, 0, sizeof(uctx->cbs)); |
INIT_LIST_HEAD(&uctx->cbs.list); |
160,6 → 171,13 |
vmw_resource_activate(res, vmw_hw_context_destroy); |
return 0; |
out_err: |
if (res_free) |
res_free(res); |
else |
kfree(res); |
return ret; |
} |
static int vmw_context_init(struct vmw_private *dev_priv, |
328,7 → 346,7 |
BUG_ON(bo->mem.mem_type != VMW_PL_MOB); |
mutex_lock(&dev_priv->binding_mutex); |
vmw_context_binding_state_kill(&uctx->cbs); |
vmw_context_binding_state_scrub(&uctx->cbs); |
submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0); |
378,11 → 396,7 |
SVGA3dCmdHeader header; |
SVGA3dCmdDestroyGBContext body; |
} *cmd; |
struct vmw_user_context *uctx = |
container_of(res, struct vmw_user_context, res); |
BUG_ON(!list_empty(&uctx->cbs.list)); |
if (likely(res->id == -1)) |
return 0; |
461,7 → 475,6 |
struct vmw_resource *tmp; |
struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data; |
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
struct vmw_master *vmaster = vmw_master(file_priv->master); |
int ret; |
471,9 → 484,10 |
*/ |
if (unlikely(vmw_user_context_size == 0)) |
vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128; |
vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128 + |
((dev_priv->has_mob) ? vmw_cmdbuf_res_man_size() : 0); |
ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) |
return ret; |
520,7 → 534,7 |
out_err: |
vmw_resource_unreference(&res); |
out_unlock: |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
return ret; |
} |
530,8 → 544,9 |
* vmw_context_scrub_shader - scrub a shader binding from a context. |
* |
* @bi: single binding information. |
* @rebind: Whether to issue a bind instead of scrub command. |
*/ |
static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi) |
static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind) |
{ |
struct vmw_private *dev_priv = bi->ctx->dev_priv; |
struct { |
550,7 → 565,7 |
cmd->header.size = sizeof(cmd->body); |
cmd->body.cid = bi->ctx->id; |
cmd->body.type = bi->i1.shader_type; |
cmd->body.shid = SVGA3D_INVALID_ID; |
cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); |
vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
return 0; |
561,8 → 576,10 |
* from a context. |
* |
* @bi: single binding information. |
* @rebind: Whether to issue a bind instead of scrub command. |
*/ |
static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi) |
static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi, |
bool rebind) |
{ |
struct vmw_private *dev_priv = bi->ctx->dev_priv; |
struct { |
581,7 → 598,7 |
cmd->header.size = sizeof(cmd->body); |
cmd->body.cid = bi->ctx->id; |
cmd->body.type = bi->i1.rt_type; |
cmd->body.target.sid = SVGA3D_INVALID_ID; |
cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); |
cmd->body.target.face = 0; |
cmd->body.target.mipmap = 0; |
vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
593,11 → 610,13 |
* vmw_context_scrub_texture - scrub a texture binding from a context. |
* |
* @bi: single binding information. |
* @rebind: Whether to issue a bind instead of scrub command. |
* |
* TODO: Possibly complement this function with a function that takes |
* a list of texture bindings and combines them to a single command. |
*/ |
static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi) |
static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, |
bool rebind) |
{ |
struct vmw_private *dev_priv = bi->ctx->dev_priv; |
struct { |
621,7 → 640,7 |
cmd->body.c.cid = bi->ctx->id; |
cmd->body.s1.stage = bi->i1.texture_stage; |
cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE; |
cmd->body.s1.value = (uint32) SVGA3D_INVALID_ID; |
cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); |
vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
return 0; |
694,6 → 713,7 |
vmw_context_binding_drop(loc); |
loc->bi = *bi; |
loc->bi.scrubbed = false; |
list_add_tail(&loc->ctx_list, &cbs->list); |
INIT_LIST_HEAD(&loc->res_list); |
729,13 → 749,12 |
if (loc->bi.ctx != NULL) |
vmw_context_binding_drop(loc); |
if (bi->res != NULL) { |
loc->bi = *bi; |
list_add_tail(&loc->ctx_list, &cbs->list); |
if (bi->res != NULL) |
list_add_tail(&loc->res_list, &bi->res->binding_head); |
else |
INIT_LIST_HEAD(&loc->res_list); |
} |
} |
/** |
* vmw_context_binding_kill - Kill a binding on the device |
748,7 → 767,10 |
*/ |
static void vmw_context_binding_kill(struct vmw_ctx_binding *cb) |
{ |
(void) vmw_scrub_funcs[cb->bi.bt](&cb->bi); |
if (!cb->bi.scrubbed) { |
(void) vmw_scrub_funcs[cb->bi.bt](&cb->bi, false); |
cb->bi.scrubbed = true; |
} |
vmw_context_binding_drop(cb); |
} |
770,6 → 792,27 |
} |
/** |
* vmw_context_binding_state_scrub - Scrub all bindings associated with a |
* struct vmw_ctx_binding state structure. |
* |
* @cbs: Pointer to the context binding state tracker. |
* |
* Emits commands to scrub all bindings associated with the |
* context binding state tracker. |
*/ |
static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs) |
{ |
struct vmw_ctx_binding *entry; |
list_for_each_entry(entry, &cbs->list, ctx_list) { |
if (!entry->bi.scrubbed) { |
(void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false); |
entry->bi.scrubbed = true; |
} |
} |
} |
/** |
* vmw_context_binding_res_list_kill - Kill all bindings on a |
* resource binding list |
* |
787,6 → 830,27 |
} |
/** |
* vmw_context_binding_res_list_scrub - Scrub all bindings on a |
* resource binding list |
* |
* @head: list head of resource binding list |
* |
* Scrub all bindings associated with a specific resource. Typically |
* called before the resource is evicted. |
*/ |
void vmw_context_binding_res_list_scrub(struct list_head *head) |
{ |
struct vmw_ctx_binding *entry; |
list_for_each_entry(entry, head, res_list) { |
if (!entry->bi.scrubbed) { |
(void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false); |
entry->bi.scrubbed = true; |
} |
} |
} |
/** |
* vmw_context_binding_state_transfer - Commit staged binding info |
* |
* @ctx: Pointer to context to commit the staged binding info to. |
805,3 → 869,55 |
list_for_each_entry_safe(entry, next, &from->list, ctx_list) |
vmw_context_binding_transfer(&uctx->cbs, &entry->bi); |
} |
/** |
* vmw_context_rebind_all - Rebind all scrubbed bindings of a context |
* |
* @ctx: The context resource |
* |
* Walks through the context binding list and rebinds all scrubbed |
* resources. |
*/ |
int vmw_context_rebind_all(struct vmw_resource *ctx) |
{ |
struct vmw_ctx_binding *entry; |
struct vmw_user_context *uctx = |
container_of(ctx, struct vmw_user_context, res); |
struct vmw_ctx_binding_state *cbs = &uctx->cbs; |
int ret; |
list_for_each_entry(entry, &cbs->list, ctx_list) { |
if (likely(!entry->bi.scrubbed)) |
continue; |
if (WARN_ON(entry->bi.res == NULL || entry->bi.res->id == |
SVGA3D_INVALID_ID)) |
continue; |
ret = vmw_scrub_funcs[entry->bi.bt](&entry->bi, true); |
if (unlikely(ret != 0)) |
return ret; |
entry->bi.scrubbed = false; |
} |
return 0; |
} |
/** |
* vmw_context_binding_list - Return a list of context bindings |
* |
* @ctx: The context resource |
* |
* Returns the current list of bindings of the given context. Note that |
* this list becomes stale as soon as the dev_priv::binding_mutex is unlocked. |
*/ |
struct list_head *vmw_context_binding_list(struct vmw_resource *ctx) |
{ |
return &(container_of(ctx, struct vmw_user_context, res)->cbs.list); |
} |
struct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx) |
{ |
return container_of(ctx, struct vmw_user_context, res)->man; |
} |
/drivers/video/drm/vmwgfx/vmwgfx_dmabuf.c |
---|
52,7 → 52,6 |
struct ttm_placement *placement, |
bool interruptible) |
{ |
// struct vmw_master *vmaster = dev_priv->active_master; |
struct ttm_buffer_object *bo = &buf->base; |
int ret; |
62,7 → 61,7 |
vmw_execbuf_release_pinned_bo(dev_priv); |
ret = ttm_bo_reserve(bo, interruptible, false, false, 0); |
ret = ttm_bo_reserve(bo, interruptible, false, false, NULL); |
if (unlikely(ret != 0)) |
goto err; |
95,7 → 94,6 |
struct vmw_dma_buffer *buf, |
bool pin, bool interruptible) |
{ |
// struct vmw_master *vmaster = dev_priv->active_master; |
struct ttm_buffer_object *bo = &buf->base; |
struct ttm_placement *placement; |
int ret; |
107,7 → 105,7 |
if (pin) |
vmw_execbuf_release_pinned_bo(dev_priv); |
ret = ttm_bo_reserve(bo, interruptible, false, false, 0); |
ret = ttm_bo_reserve(bo, interruptible, false, false, NULL); |
if (unlikely(ret != 0)) |
goto err; |
198,7 → 196,6 |
struct vmw_dma_buffer *buf, |
bool pin, bool interruptible) |
{ |
// struct vmw_master *vmaster = dev_priv->active_master; |
struct ttm_buffer_object *bo = &buf->base; |
struct ttm_placement placement; |
int ret = 0; |
215,7 → 212,7 |
if (pin) |
vmw_execbuf_release_pinned_bo(dev_priv); |
ret = ttm_bo_reserve(bo, interruptible, false, false, 0); |
ret = ttm_bo_reserve(bo, interruptible, false, false, NULL); |
if (unlikely(ret != 0)) |
goto err_unlock; |
/drivers/video/drm/vmwgfx/vmwgfx_drv.c |
---|
142,11 → 142,11 |
static const struct drm_ioctl_desc vmw_ioctls[] = { |
VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, |
vmw_kms_cursor_bypass_ioctl, |
DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), |
159,29 → 159,28 |
DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), |
VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_FENCE_SIGNALED, |
vmw_fence_obj_signaled_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
VMW_IOCTL_DEF(VMW_FENCE_EVENT, |
vmw_fence_event_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_FENCE_EVENT, vmw_fence_event_ioctl, |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
/* these allow direct access to the framebuffers mark as master only */ |
VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl, |
194,19 → 193,19 |
DRM_MASTER | DRM_UNLOCKED), |
VMW_IOCTL_DEF(VMW_CREATE_SHADER, |
vmw_shader_define_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_UNREF_SHADER, |
vmw_shader_destroy_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE, |
vmw_gb_surface_define_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_GB_SURFACE_REF, |
vmw_gb_surface_reference_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), |
VMW_IOCTL_DEF(VMW_SYNCCPU, |
vmw_user_dmabuf_synccpu_ioctl, |
DRM_AUTH | DRM_UNLOCKED), |
DRM_UNLOCKED | DRM_RENDER_ALLOW), |
}; |
#endif |
315,7 → 314,7 |
if (unlikely(ret != 0)) |
return ret; |
ret = ttm_bo_reserve(bo, false, true, false, 0); |
ret = ttm_bo_reserve(bo, false, true, false, NULL); |
BUG_ON(ret != 0); |
ret = ttm_bo_kmap(bo, 0, 1, &map); |
341,7 → 340,6 |
static int vmw_request_device(struct vmw_private *dev_priv) |
{ |
int ret; |
ENTER(); |
ret = vmw_fifo_init(dev_priv, &dev_priv->fifo); |
if (unlikely(ret != 0)) { |
354,8 → 352,8 |
// goto out_no_query_bo; |
// vmw_dummy_query_bo_prepare(dev_priv); |
LEAVE(); |
return 0; |
out_no_query_bo: |
534,8 → 532,6 |
enum vmw_res_type i; |
bool refuse_dma = false; |
ENTER(); |
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); |
if (unlikely(dev_priv == NULL)) { |
DRM_ERROR("Failed allocating a device private struct.\n"); |
552,6 → 548,7 |
mutex_init(&dev_priv->release_mutex); |
mutex_init(&dev_priv->binding_mutex); |
rwlock_init(&dev_priv->resource_lock); |
ttm_lock_init(&dev_priv->reservation_sem); |
for (i = vmw_res_context; i < vmw_res_max; ++i) { |
idr_init(&dev_priv->res_idr[i]); |
570,9 → 567,6 |
dev_priv->vram_start = pci_resource_start(dev->pdev, 1); |
dev_priv->mmio_start = pci_resource_start(dev->pdev, 2); |
printk("io: %x vram: %x mmio: %x\n",dev_priv->io_start, |
dev_priv->vram_start,dev_priv->mmio_start); |
dev_priv->enable_fb = enable_fbdev; |
mutex_lock(&dev_priv->hw_mutex); |
616,6 → 610,7 |
dev_priv->memory_size = 512*1024*1024; |
} |
dev_priv->max_mob_pages = 0; |
dev_priv->max_mob_size = 0; |
if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { |
uint64_t mem_size = |
vmw_read(dev_priv, |
625,6 → 620,8 |
dev_priv->prim_bb_mem = |
vmw_read(dev_priv, |
SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM); |
dev_priv->max_mob_size = |
vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); |
} else |
dev_priv->prim_bb_mem = dev_priv->vram_size; |
667,7 → 664,9 |
ret = ttm_bo_device_init(&dev_priv->bdev, |
dev_priv->bo_global_ref.ref.object, |
&vmw_bo_driver, VMWGFX_FILE_PAGE_OFFSET, |
&vmw_bo_driver, |
NULL, |
VMWGFX_FILE_PAGE_OFFSET, |
false); |
if (unlikely(ret != 0)) { |
DRM_ERROR("Failed initializing TTM buffer object driver.\n"); |
717,14 → 716,14 |
goto out_err4; |
} |
// dev_priv->tdev = ttm_object_device_init |
// (dev_priv->mem_global_ref.object, 12, &vmw_prime_dmabuf_ops); |
dev_priv->tdev = ttm_object_device_init |
(dev_priv->mem_global_ref.object, 12, &vmw_prime_dmabuf_ops); |
// if (unlikely(dev_priv->tdev == NULL)) { |
// DRM_ERROR("Unable to initialize TTM object management.\n"); |
// ret = -ENOMEM; |
// goto out_err4; |
// } |
if (unlikely(dev_priv->tdev == NULL)) { |
DRM_ERROR("Unable to initialize TTM object management.\n"); |
ret = -ENOMEM; |
goto out_err4; |
} |
dev->dev_private = dev_priv; |
731,7 → 730,7 |
#if 0 |
if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { |
ret = drm_irq_install(dev); |
ret = drm_irq_install(dev, dev->pdev->irq); |
if (ret != 0) { |
DRM_ERROR("Failed installing irq: %d\n", ret); |
goto out_no_irq; |
761,7 → 760,6 |
main_device = dev; |
LEAVE(); |
return 0; |
out_no_fifo: |
890,7 → 888,6 |
// goto out_no_tfile; |
file_priv->driver_priv = vmw_fp; |
// dev_priv->bdev.dev_mapping = dev->dev_mapping; |
return 0; |
1094,12 → 1091,11 |
{ |
struct vmw_private *dev_priv = |
container_of(nb, struct vmw_private, pm_nb); |
struct vmw_master *vmaster = dev_priv->active_master; |
switch (val) { |
case PM_HIBERNATION_PREPARE: |
case PM_SUSPEND_PREPARE: |
ttm_suspend_lock(&vmaster->lock); |
ttm_suspend_lock(&dev_priv->reservation_sem); |
/** |
* This empties VRAM and unbinds all GMR bindings. |
1113,7 → 1109,7 |
case PM_POST_HIBERNATION: |
case PM_POST_SUSPEND: |
case PM_POST_RESTORE: |
ttm_suspend_unlock(&vmaster->lock); |
ttm_suspend_unlock(&dev_priv->reservation_sem); |
break; |
case PM_RESTORE_PREPARE: |
1201,7 → 1197,7 |
static struct drm_driver driver = { |
.driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | |
DRIVER_MODESET, |
DRIVER_MODESET | DRIVER_RENDER, |
.load = vmw_driver_load, |
// .unload = vmw_driver_unload, |
// .lastclose = vmw_lastclose, |
1248,7 → 1244,6 |
const struct pci_device_id *ent; |
int err; |
ENTER(); |
ent = find_pci_device(&device, vmw_pci_id_list); |
if( unlikely(ent == NULL) ) |
1263,7 → 1258,6 |
device.pci_dev.device); |
err = drm_get_pci_dev(&device.pci_dev, ent, &driver); |
LEAVE(); |
return err; |
} |
/drivers/video/drm/vmwgfx/vmwgfx_drv.h |
---|
36,15 → 36,15 |
//#include <linux/suspend.h> |
#include <drm/ttm/ttm_bo_driver.h> |
#include <drm/ttm/ttm_object.h> |
//#include <drm/ttm/ttm_lock.h> |
#include <drm/ttm/ttm_lock.h> |
#include <drm/ttm/ttm_execbuf_util.h> |
//#include <drm/ttm/ttm_module.h> |
#include "vmwgfx_fence.h" |
#define VMWGFX_DRIVER_DATE "20121114" |
#define VMWGFX_DRIVER_DATE "20140704" |
#define VMWGFX_DRIVER_MAJOR 2 |
#define VMWGFX_DRIVER_MINOR 5 |
#define VMWGFX_DRIVER_PATCHLEVEL 0 |
#define VMWGFX_DRIVER_MINOR 6 |
#define VMWGFX_DRIVER_PATCHLEVEL 1 |
#define VMWGFX_FILE_PAGE_OFFSET 0x00100000 |
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024) |
#define VMWGFX_MAX_RELOCATIONS 2048 |
89,13 → 89,12 |
return v; |
} |
struct ttm_lock{}; |
struct ww_acquire_ctx{}; |
struct vmw_fpriv { |
// struct drm_master *locked_master; |
struct ttm_object_file *tfile; |
struct list_head fence_events; |
bool gb_aware; |
}; |
struct vmw_dma_buffer { |
137,6 → 136,10 |
void (*hw_destroy) (struct vmw_resource *res); |
}; |
/* |
* Resources that are managed using ioctls. |
*/ |
enum vmw_res_type { |
vmw_res_context, |
vmw_res_surface, |
145,6 → 148,15 |
vmw_res_max |
}; |
/* |
* Resources that are managed using command streams. |
*/ |
enum vmw_cmdbuf_res_type { |
vmw_cmdbuf_res_compat_shader |
}; |
struct vmw_cmdbuf_res_manager; |
struct vmw_cursor_snooper { |
struct drm_crtc *crtc; |
size_t age; |
172,8 → 184,8 |
struct vmw_marker_queue { |
struct list_head head; |
struct timespec lag; |
struct timespec lag_time; |
u64 lag; |
u64 lag_time; |
spinlock_t lock; |
}; |
289,6 → 301,7 |
struct vmw_resource *ctx; |
struct vmw_resource *res; |
enum vmw_ctx_binding_type bt; |
bool scrubbed; |
union { |
SVGA3dShaderType shader_type; |
SVGA3dRenderTargetType rt_type; |
335,7 → 348,7 |
struct drm_open_hash res_ht; |
bool res_ht_initialized; |
bool kernel; /**< is the called made from the kernel */ |
struct ttm_object_file *tfile; |
struct vmw_fpriv *fp; |
struct list_head validate_nodes; |
struct vmw_relocation relocs[VMWGFX_MAX_RELOCATIONS]; |
uint32_t cur_reloc; |
353,6 → 366,7 |
bool needs_post_query_barrier; |
struct vmw_resource *error_resource; |
struct vmw_ctx_binding_state staged_bindings; |
struct list_head staged_cmd_res; |
}; |
struct vmw_legacy_display; |
397,6 → 411,7 |
uint32_t max_gmr_ids; |
uint32_t max_gmr_pages; |
uint32_t max_mob_pages; |
uint32_t max_mob_size; |
uint32_t memory_size; |
bool has_gmr; |
bool has_mob; |
497,6 → 512,11 |
uint32_t num_3d_resources; |
/* |
* Replace this with an rwsem as soon as we have down_xx_interruptible() |
*/ |
struct ttm_lock reservation_sem; |
/* |
* Query processing. These members |
* are protected by the cmdbuf mutex. |
*/ |
586,6 → 606,8 |
extern void vmw_resource_unreference(struct vmw_resource **p_res); |
extern struct vmw_resource *vmw_resource_reference(struct vmw_resource *res); |
extern struct vmw_resource * |
vmw_resource_reference_unless_doomed(struct vmw_resource *res); |
extern int vmw_resource_validate(struct vmw_resource *res); |
extern int vmw_resource_reserve(struct vmw_resource *res, bool no_backup); |
extern bool vmw_resource_needs_backup(const struct vmw_resource *res); |
960,6 → 982,9 |
vmw_context_binding_state_transfer(struct vmw_resource *res, |
struct vmw_ctx_binding_state *cbs); |
extern void vmw_context_binding_res_list_kill(struct list_head *head); |
extern void vmw_context_binding_res_list_scrub(struct list_head *head); |
extern int vmw_context_rebind_all(struct vmw_resource *ctx); |
extern struct list_head *vmw_context_binding_list(struct vmw_resource *ctx); |
/* |
* Surface management - vmwgfx_surface.c |
979,6 → 1004,27 |
*/ |
extern const struct vmw_user_resource_conv *user_shader_converter; |
extern struct vmw_cmdbuf_res_manager * |
vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv); |
extern void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man); |
extern size_t vmw_cmdbuf_res_man_size(void); |
extern struct vmw_resource * |
vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man, |
enum vmw_cmdbuf_res_type res_type, |
u32 user_key); |
extern void vmw_cmdbuf_res_revert(struct list_head *list); |
extern void vmw_cmdbuf_res_commit(struct list_head *list); |
extern int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man, |
enum vmw_cmdbuf_res_type res_type, |
u32 user_key, |
struct vmw_resource *res, |
struct list_head *list); |
extern int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man, |
enum vmw_cmdbuf_res_type res_type, |
u32 user_key, |
struct list_head *list); |
/** |
* Inline helper functions |
*/ |
/drivers/video/drm/vmwgfx/vmwgfx_execbuf.c |
---|
114,8 → 114,10 |
* persistent context binding tracker. |
*/ |
if (unlikely(val->staged_bindings)) { |
if (!backoff) { |
vmw_context_binding_state_transfer |
(val->res, val->staged_bindings); |
} |
kfree(val->staged_bindings); |
val->staged_bindings = NULL; |
} |
178,6 → 180,44 |
} |
/** |
* vmw_resource_context_res_add - Put resources previously bound to a context on |
* the validation list |
* |
* @dev_priv: Pointer to a device private structure |
* @sw_context: Pointer to a software context used for this command submission |
* @ctx: Pointer to the context resource |
* |
* This function puts all resources that were previously bound to @ctx on |
* the resource validation list. This is part of the context state reemission |
*/ |
static int vmw_resource_context_res_add(struct vmw_private *dev_priv, |
struct vmw_sw_context *sw_context, |
struct vmw_resource *ctx) |
{ |
struct list_head *binding_list; |
struct vmw_ctx_binding *entry; |
int ret = 0; |
struct vmw_resource *res; |
mutex_lock(&dev_priv->binding_mutex); |
binding_list = vmw_context_binding_list(ctx); |
list_for_each_entry(entry, binding_list, ctx_list) { |
res = vmw_resource_reference_unless_doomed(entry->bi.res); |
if (unlikely(res == NULL)) |
continue; |
ret = vmw_resource_val_add(sw_context, entry->bi.res, NULL); |
vmw_resource_unreference(&res); |
if (unlikely(ret != 0)) |
break; |
} |
mutex_unlock(&dev_priv->binding_mutex); |
return ret; |
} |
/** |
* vmw_resource_relocation_add - Add a relocation to the relocation list |
* |
* @list: Pointer to head of relocation list. |
233,9 → 273,13 |
{ |
struct vmw_resource_relocation *rel; |
list_for_each_entry(rel, list, head) |
list_for_each_entry(rel, list, head) { |
if (likely(rel->res != NULL)) |
cb[rel->offset] = rel->res->id; |
else |
cb[rel->offset] = SVGA_3D_CMD_NOP; |
} |
} |
static int vmw_cmd_invalid(struct vmw_private *dev_priv, |
struct vmw_sw_context *sw_context, |
378,7 → 422,72 |
return 0; |
} |
/** |
* vmw_cmd_res_reloc_add - Add a resource to a software context's |
* relocation- and validation lists. |
* |
* @dev_priv: Pointer to a struct vmw_private identifying the device. |
* @sw_context: Pointer to the software context. |
* @res_type: Resource type. |
* @id_loc: Pointer to where the id that needs translation is located. |
* @res: Valid pointer to a struct vmw_resource. |
* @p_val: If non null, a pointer to the struct vmw_resource_validate_node |
* used for this resource is returned here. |
*/ |
static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv, |
struct vmw_sw_context *sw_context, |
enum vmw_res_type res_type, |
uint32_t *id_loc, |
struct vmw_resource *res, |
struct vmw_resource_val_node **p_val) |
{ |
int ret; |
struct vmw_resource_val_node *node; |
*p_val = NULL; |
ret = vmw_resource_relocation_add(&sw_context->res_relocations, |
res, |
id_loc - sw_context->buf_start); |
if (unlikely(ret != 0)) |
goto out_err; |
ret = vmw_resource_val_add(sw_context, res, &node); |
if (unlikely(ret != 0)) |
goto out_err; |
if (res_type == vmw_res_context && dev_priv->has_mob && |
node->first_usage) { |
/* |
* Put contexts first on the list to be able to exit |
* list traversal for contexts early. |
*/ |
list_del(&node->head); |
list_add(&node->head, &sw_context->resource_list); |
ret = vmw_resource_context_res_add(dev_priv, sw_context, res); |
if (unlikely(ret != 0)) |
goto out_err; |
node->staged_bindings = |
kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL); |
if (node->staged_bindings == NULL) { |
DRM_ERROR("Failed to allocate context binding " |
"information.\n"); |
goto out_err; |
} |
INIT_LIST_HEAD(&node->staged_bindings->list); |
} |
if (p_val) |
*p_val = node; |
out_err: |
return ret; |
} |
/** |
* vmw_cmd_res_check - Check that a resource is present and if so, put it |
* on the resource validate list unless it's already there. |
* |
386,14 → 495,17 |
* @sw_context: Pointer to the software context. |
* @res_type: Resource type. |
* @converter: User-space visisble type specific information. |
* @id: Pointer to the location in the command buffer currently being |
* @id_loc: Pointer to the location in the command buffer currently being |
* parsed from where the user-space resource id handle is located. |
* @p_val: Pointer to pointer to resource validalidation node. Populated |
* on exit. |
*/ |
static int vmw_cmd_res_check(struct vmw_private *dev_priv, |
static int |
vmw_cmd_res_check(struct vmw_private *dev_priv, |
struct vmw_sw_context *sw_context, |
enum vmw_res_type res_type, |
const struct vmw_user_resource_conv *converter, |
uint32_t *id, |
uint32_t *id_loc, |
struct vmw_resource_val_node **p_val) |
{ |
struct vmw_res_cache_entry *rcache = |
402,7 → 514,7 |
struct vmw_resource_val_node *node; |
int ret; |
if (*id == SVGA3D_INVALID_ID) { |
if (*id_loc == SVGA3D_INVALID_ID) { |
if (p_val) |
*p_val = NULL; |
if (res_type == vmw_res_context) { |
417,7 → 529,7 |
* resource |
*/ |
if (likely(rcache->valid && *id == rcache->handle)) { |
if (likely(rcache->valid && *id_loc == rcache->handle)) { |
const struct vmw_resource *res = rcache->res; |
rcache->node->first_usage = false; |
426,50 → 538,33 |
return vmw_resource_relocation_add |
(&sw_context->res_relocations, res, |
id - sw_context->buf_start); |
id_loc - sw_context->buf_start); |
} |
ret = vmw_user_resource_lookup_handle(dev_priv, |
sw_context->tfile, |
*id, |
sw_context->fp->tfile, |
*id_loc, |
converter, |
&res); |
if (unlikely(ret != 0)) { |
DRM_ERROR("Could not find or use resource 0x%08x.\n", |
(unsigned) *id); |
// dump_stack(); |
(unsigned) *id_loc); |
.. dump_stack(); |
return ret; |
} |
rcache->valid = true; |
rcache->res = res; |
rcache->handle = *id; |
rcache->handle = *id_loc; |
ret = vmw_resource_relocation_add(&sw_context->res_relocations, |
res, |
id - sw_context->buf_start); |
ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, res_type, id_loc, |
res, &node); |
if (unlikely(ret != 0)) |
goto out_no_reloc; |
ret = vmw_resource_val_add(sw_context, res, &node); |
if (unlikely(ret != 0)) |
goto out_no_reloc; |
rcache->node = node; |
if (p_val) |
*p_val = node; |
if (node->first_usage && res_type == vmw_res_context) { |
node->staged_bindings = |
kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL); |
if (node->staged_bindings == NULL) { |
DRM_ERROR("Failed to allocate context binding " |
"information.\n"); |
goto out_no_reloc; |
} |
INIT_LIST_HEAD(&node->staged_bindings->list); |
} |
vmw_resource_unreference(&res); |
return 0; |
481,6 → 576,34 |
} |
/** |
* vmw_rebind_contexts - Rebind all resources previously bound to |
* referenced contexts. |
* |
* @sw_context: Pointer to the software context. |
* |
* Rebind context binding points that have been scrubbed because of eviction. |
*/ |
static int vmw_rebind_contexts(struct vmw_sw_context *sw_context) |
{ |
struct vmw_resource_val_node *val; |
int ret; |
list_for_each_entry(val, &sw_context->resource_list, head) { |
if (unlikely(!val->staged_bindings)) |
break; |
ret = vmw_context_rebind_all(val->res); |
if (unlikely(ret != 0)) { |
if (ret != -ERESTARTSYS) |
DRM_ERROR("Failed to rebind context.\n"); |
return ret; |
} |
} |
return 0; |
} |
/** |
* vmw_cmd_cid_check - Check a command header for valid context information. |
* |
* @dev_priv: Pointer to a device private structure. |
496,7 → 619,7 |
{ |
struct vmw_cid_cmd { |
SVGA3dCmdHeader header; |
__le32 cid; |
uint32_t cid; |
} *cmd; |
cmd = container_of(header, struct vmw_cid_cmd, header); |
767,7 → 890,7 |
struct vmw_relocation *reloc; |
int ret; |
ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo); |
ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo); |
if (unlikely(ret != 0)) { |
DRM_ERROR("Could not find or use MOB buffer.\n"); |
return -EINVAL; |
828,7 → 951,7 |
struct vmw_relocation *reloc; |
int ret; |
ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo); |
ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo); |
if (unlikely(ret != 0)) { |
DRM_ERROR("Could not find or use GMR region.\n"); |
return -EINVAL; |
1108,8 → 1231,19 |
SVGA3dCmdSurfaceDMA dma; |
} *cmd; |
int ret; |
SVGA3dCmdSurfaceDMASuffix *suffix; |
uint32_t bo_size; |
cmd = container_of(header, struct vmw_dma_cmd, header); |
suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->dma + |
header->size - sizeof(*suffix)); |
/* Make sure device and verifier stays in sync. */ |
if (unlikely(suffix->suffixSize != sizeof(*suffix))) { |
DRM_ERROR("Invalid DMA suffix size.\n"); |
return -EINVAL; |
} |
ret = vmw_translate_guest_ptr(dev_priv, sw_context, |
&cmd->dma.guest.ptr, |
&vmw_bo); |
1116,6 → 1250,17 |
if (unlikely(ret != 0)) |
return ret; |
/* Make sure DMA doesn't cross BO boundaries. */ |
bo_size = vmw_bo->base.num_pages * PAGE_SIZE; |
if (unlikely(cmd->dma.guest.ptr.offset > bo_size)) { |
DRM_ERROR("Invalid DMA offset.\n"); |
return -EINVAL; |
} |
bo_size -= cmd->dma.guest.ptr.offset; |
if (unlikely(suffix->maximumOffset > bo_size)) |
suffix->maximumOffset = bo_size; |
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, |
user_surface_converter, &cmd->dma.host.sid, |
NULL); |
1478,6 → 1623,7 |
&cmd->body.sid, NULL); |
} |
#if 0 |
/** |
* vmw_cmd_set_shader - Validate an SVGA_3D_CMD_SET_SHADER |
* command |
1494,7 → 1640,9 |
SVGA3dCmdHeader header; |
SVGA3dCmdSetShader body; |
} *cmd; |
struct vmw_resource_val_node *ctx_node; |
struct vmw_resource_val_node *ctx_node, *res_node = NULL; |
struct vmw_ctx_bindinfo bi; |
struct vmw_resource *res = NULL; |
int ret; |
cmd = container_of(header, struct vmw_set_shader_cmd, |
1506,15 → 1654,34 |
if (unlikely(ret != 0)) |
return ret; |
if (dev_priv->has_mob) { |
struct vmw_ctx_bindinfo bi; |
struct vmw_resource_val_node *res_node; |
if (!dev_priv->has_mob) |
return 0; |
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_shader, |
if (cmd->body.shid != SVGA3D_INVALID_ID) { |
res = vmw_compat_shader_lookup |
(vmw_context_res_man(ctx_node->res), |
cmd->body.shid, |
cmd->body.type); |
if (!IS_ERR(res)) { |
ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, |
vmw_res_shader, |
&cmd->body.shid, res, |
&res_node); |
vmw_resource_unreference(&res); |
if (unlikely(ret != 0)) |
return ret; |
} |
} |
if (!res_node) { |
ret = vmw_cmd_res_check(dev_priv, sw_context, |
vmw_res_shader, |
user_shader_converter, |
&cmd->body.shid, &res_node); |
if (unlikely(ret != 0)) |
return ret; |
} |
bi.ctx = ctx_node->res; |
bi.res = res_node ? res_node->res : NULL; |
1522,10 → 1689,42 |
bi.i1.shader_type = cmd->body.type; |
return vmw_context_binding_add(ctx_node->staged_bindings, &bi); |
} |
#endif |
/** |
* vmw_cmd_set_shader_const - Validate an SVGA_3D_CMD_SET_SHADER_CONST |
* command |
* |
* @dev_priv: Pointer to a device private struct. |
* @sw_context: The software context being used for this batch. |
* @header: Pointer to the command header in the command stream. |
*/ |
static int vmw_cmd_set_shader_const(struct vmw_private *dev_priv, |
struct vmw_sw_context *sw_context, |
SVGA3dCmdHeader *header) |
{ |
struct vmw_set_shader_const_cmd { |
SVGA3dCmdHeader header; |
SVGA3dCmdSetShaderConst body; |
} *cmd; |
int ret; |
cmd = container_of(header, struct vmw_set_shader_const_cmd, |
header); |
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context, |
user_context_converter, &cmd->body.cid, |
NULL); |
if (unlikely(ret != 0)) |
return ret; |
if (dev_priv->has_mob) |
header->id = SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE; |
return 0; |
} |
#if 0 |
/** |
* vmw_cmd_bind_gb_shader - Validate an SVGA_3D_CMD_BIND_GB_SHADER |
* command |
1551,6 → 1750,7 |
&cmd->body.shid, &cmd->body.mobid, |
cmd->body.offsetInBytes); |
} |
#endif |
static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, |
struct vmw_sw_context *sw_context, |
1595,7 → 1795,7 |
return 0; |
} |
static const struct vmw_cmd_entry const vmw_cmd_entries[SVGA_3D_CMD_MAX] = { |
static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { |
VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid, |
false, false, false), |
VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid, |
1634,14 → 1834,14 |
true, false, false), |
VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check, |
false, false, false), |
VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_cid_check, |
true, true, false), |
VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check, |
true, true, false), |
VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader, |
true, false, false), |
VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check, |
true, true, false), |
// VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_shader_define, |
// true, false, false), |
// VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_shader_destroy, |
// true, false, false), |
// VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader, |
// true, false, false), |
// VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_set_shader_const, |
// true, false, false), |
VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw, |
true, false, false), |
VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check, |
1726,8 → 1926,8 |
false, false, true), |
VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SHADER, &vmw_cmd_invalid, |
false, false, true), |
VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SHADER, &vmw_cmd_bind_gb_shader, |
true, false, true), |
// VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SHADER, &vmw_cmd_bind_gb_shader, |
// true, false, true), |
VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SHADER, &vmw_cmd_invalid, |
false, false, true), |
VMW_CMD_DEF(SVGA_3D_CMD_SET_OTABLE_BASE64, &vmw_cmd_invalid, |
1792,6 → 1992,9 |
goto out_invalid; |
entry = &vmw_cmd_entries[cmd_id]; |
if (unlikely(!entry->func)) |
goto out_invalid; |
if (unlikely(!entry->user_allow && !sw_context->kernel)) |
goto out_privileged; |
2129,6 → 2332,8 |
} |
} |
int vmw_execbuf_process(struct drm_file *file_priv, |
struct vmw_private *dev_priv, |
void __user *user_commands, |
2172,7 → 2377,7 |
} else */ |
sw_context->kernel = true; |
sw_context->tfile = vmw_fpriv(file_priv)->tfile; |
sw_context->fp = vmw_fpriv(file_priv); |
sw_context->cur_reloc = 0; |
sw_context->cur_val_buf = 0; |
sw_context->fence_flags = 0; |
2189,16 → 2394,17 |
goto out_unlock; |
sw_context->res_ht_initialized = true; |
} |
INIT_LIST_HEAD(&sw_context->staged_cmd_res); |
INIT_LIST_HEAD(&resource_list); |
ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands, |
command_size); |
if (unlikely(ret != 0)) |
goto out_err; |
goto out_err_nores; |
ret = vmw_resources_reserve(sw_context); |
if (unlikely(ret != 0)) |
goto out_err; |
goto out_err_nores; |
ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes); |
if (unlikely(ret != 0)) |
2226,6 → 2432,12 |
goto out_err; |
} |
if (dev_priv->has_mob) { |
ret = vmw_rebind_contexts(sw_context); |
if (unlikely(ret != 0)) |
goto out_unlock_binding; |
} |
cmd = vmw_fifo_reserve(dev_priv, command_size); |
if (unlikely(cmd == NULL)) { |
DRM_ERROR("Failed reserving fifo space for commands.\n"); |
2277,6 → 2489,7 |
} |
list_splice_init(&sw_context->resource_list, &resource_list); |
vmw_cmdbuf_res_commit(&sw_context->staged_cmd_res); |
mutex_unlock(&dev_priv->cmdbuf_mutex); |
/* |
2290,10 → 2503,11 |
out_unlock_binding: |
mutex_unlock(&dev_priv->binding_mutex); |
out_err: |
ttm_eu_backoff_reservation(&ticket, &sw_context->validate_nodes); |
out_err_nores: |
vmw_resource_list_unreserve(&sw_context->resource_list, true); |
vmw_resource_relocations_free(&sw_context->res_relocations); |
vmw_free_relocations(sw_context); |
ttm_eu_backoff_reservation(&ticket, &sw_context->validate_nodes); |
vmw_resource_list_unreserve(&sw_context->resource_list, true); |
vmw_clear_validations(sw_context); |
if (unlikely(dev_priv->pinned_bo != NULL && |
!dev_priv->query_cid_valid)) |
2302,6 → 2516,7 |
list_splice_init(&sw_context->resource_list, &resource_list); |
error_resource = sw_context->error_resource; |
sw_context->error_resource = NULL; |
vmw_cmdbuf_res_revert(&sw_context->staged_cmd_res); |
mutex_unlock(&dev_priv->cmdbuf_mutex); |
/* |
2458,7 → 2673,6 |
{ |
struct vmw_private *dev_priv = vmw_priv(dev); |
struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data; |
// struct vmw_master *vmaster = vmw_master(file_priv->master); |
int ret; |
/* |
2475,7 → 2689,7 |
return -EINVAL; |
} |
// ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) |
return ret; |
2491,6 → 2705,6 |
// vmw_kms_cursor_post_execbuf(dev_priv); |
out_unlock: |
// ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
return ret; |
} |
/drivers/video/drm/vmwgfx/vmwgfx_fence.c |
---|
701,7 → 701,7 |
if (!arg->cookie_valid) { |
arg->cookie_valid = 1; |
arg->kernel_cookie = GetTimerTicks() + wait_timeout; |
arg->kernel_cookie = jiffies + wait_timeout; |
} |
base = ttm_base_object_lookup(tfile, arg->handle); |
714,7 → 714,7 |
fence = &(container_of(base, struct vmw_user_fence, base)->fence); |
timeout = GetTimerTicks(); |
timeout = jiffies; |
if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie)) { |
ret = ((vmw_fence_obj_signaled(fence, arg->flags)) ? |
0 : -EBUSY); |
/drivers/video/drm/vmwgfx/vmwgfx_fifo.c |
---|
106,8 → 106,6 |
uint32_t min; |
uint32_t dummy; |
ENTER(); |
fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE; |
fifo->static_buffer = KernelAlloc(fifo->static_buffer_size); |
if (unlikely(fifo->static_buffer == NULL)) |
167,7 → 165,6 |
vmw_marker_queue_init(&fifo->marker_queue); |
int ret = 0; //vmw_fifo_send_fence(dev_priv, &dummy); |
LEAVE(); |
return ret; |
} |
233,7 → 230,7 |
unsigned long timeout) |
{ |
int ret = 0; |
unsigned long end_jiffies = GetTimerTicks() + timeout; |
unsigned long end_jiffies = jiffies + timeout; |
// DEFINE_WAIT(__wait); |
DRM_INFO("Fifo wait noirq.\n"); |
244,7 → 241,7 |
// TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); |
if (!vmw_fifo_is_full(dev_priv, bytes)) |
break; |
if (time_after_eq(GetTimerTicks(), end_jiffies)) { |
if (time_after_eq(jiffies, end_jiffies)) { |
ret = -EBUSY; |
DRM_ERROR("SVGA device lockup.\n"); |
break; |
411,8 → 408,6 |
uint32_t *buffer = (fifo_state->dynamic_buffer != NULL) ? |
fifo_state->dynamic_buffer : fifo_state->static_buffer; |
ENTER(); |
if (bytes < chunk_size) |
chunk_size = bytes; |
423,8 → 418,6 |
if (rest) |
memcpy(fifo_mem + (min >> 2), buffer + (chunk_size >> 2), |
rest); |
LEAVE(); |
} |
static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state, |
434,7 → 427,6 |
{ |
uint32_t *buffer = (fifo_state->dynamic_buffer != NULL) ? |
fifo_state->dynamic_buffer : fifo_state->static_buffer; |
ENTER(); |
while (bytes > 0) { |
iowrite32(*buffer++, fifo_mem + (next_cmd >> 2)); |
446,7 → 438,6 |
mb(); |
bytes -= sizeof(uint32_t); |
} |
LEAVE(); |
} |
void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) |
458,8 → 449,6 |
uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN); |
bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE; |
// ENTER(); |
BUG_ON((bytes & 3) != 0); |
BUG_ON(bytes > fifo_state->reserved_size); |
495,8 → 484,6 |
// up_write(&fifo_state->rwsem); |
vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); |
mutex_unlock(&fifo_state->fifo_mutex); |
// LEAVE(); |
} |
int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) |
/drivers/video/drm/vmwgfx/vmwgfx_gmrid_manager.c |
---|
47,6 → 47,7 |
static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man, |
struct ttm_buffer_object *bo, |
struct ttm_placement *placement, |
uint32_t flags, |
struct ttm_mem_reg *mem) |
{ |
struct vmwgfx_gmrid_man *gman = |
/drivers/video/drm/vmwgfx/vmwgfx_irq.c |
---|
128,7 → 128,7 |
uint32_t count = 0; |
uint32_t signal_seq; |
int ret; |
unsigned long end_jiffies = GetTimerTicks() + timeout; |
unsigned long end_jiffies = jiffies + timeout; |
bool (*wait_condition)(struct vmw_private *, uint32_t); |
DEFINE_WAIT(__wait); |
150,7 → 150,7 |
// TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); |
if (wait_condition(dev_priv, seqno)) |
break; |
if (time_after_eq(GetTimerTicks(), end_jiffies)) { |
if (time_after_eq(jiffies, end_jiffies)) { |
DRM_ERROR("SVGA device lockup.\n"); |
break; |
} |
/drivers/video/drm/vmwgfx/vmwgfx_kms.c |
---|
118,7 → 118,7 |
*dst++ = 0; |
} |
for(i = 0; i < 64*(64-32); i++) |
*image++ = 0; |
*dst++ = 0; |
cmd->cmd = cpu_to_le32(SVGA_CMD_DEFINE_ALPHA_CURSOR); |
cmd->cursor.id = cpu_to_le32(0); |
148,7 → 148,7 |
kmap_offset = 0; |
kmap_num = (width*height*4 + PAGE_SIZE - 1) >> PAGE_SHIFT; |
ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0); |
ret = ttm_bo_reserve(&dmabuf->base, true, false, false, NULL); |
if (unlikely(ret != 0)) { |
DRM_ERROR("reserve failed\n"); |
return -EINVAL; |
200,7 → 200,7 |
* can do this since the caller in the drm core doesn't check anything |
* which is protected by any looks. |
*/ |
mutex_unlock(&crtc->mutex); |
drm_modeset_unlock(&crtc->mutex); |
drm_modeset_lock_all(dev_priv->dev); |
/* A lot of the code assumes this */ |
265,7 → 265,7 |
ret = 0; |
out: |
drm_modeset_unlock_all(dev_priv->dev); |
mutex_lock(&crtc->mutex); |
drm_modeset_lock(&crtc->mutex, NULL); |
return ret; |
} |
286,7 → 286,7 |
* can do this since the caller in the drm core doesn't check anything |
* which is protected by any looks. |
*/ |
mutex_unlock(&crtc->mutex); |
drm_modeset_unlock(&crtc->mutex); |
drm_modeset_lock_all(dev_priv->dev); |
vmw_cursor_update_position(dev_priv, shown, |
294,7 → 294,7 |
du->cursor_y + du->hotspot_y); |
drm_modeset_unlock_all(dev_priv->dev); |
mutex_lock(&crtc->mutex); |
drm_modeset_lock(&crtc->mutex, NULL); |
return 0; |
} |
356,7 → 356,7 |
kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT; |
kmap_num = (64*64*4) >> PAGE_SHIFT; |
ret = ttm_bo_reserve(bo, true, false, false, 0); |
ret = ttm_bo_reserve(bo, true, false, false, NULL); |
if (unlikely(ret != 0)) { |
DRM_ERROR("reserve failed\n"); |
return; |
478,7 → 478,7 |
num_units = 0; |
list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, |
head) { |
if (crtc->fb != &framebuffer->base) |
if (crtc->primary->fb != &framebuffer->base) |
continue; |
units[num_units++] = vmw_crtc_to_du(crtc); |
} |
606,7 → 606,6 |
unsigned num_clips) |
{ |
struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); |
struct vmw_master *vmaster = vmw_master(file_priv->master); |
struct vmw_framebuffer_surface *vfbs = |
vmw_framebuffer_to_vfbs(framebuffer); |
struct drm_clip_rect norect; |
621,7 → 620,7 |
drm_modeset_lock_all(dev_priv->dev); |
ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) { |
drm_modeset_unlock_all(dev_priv->dev); |
return ret; |
642,7 → 641,7 |
flags, color, |
clips, num_clips, inc, NULL); |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
drm_modeset_unlock_all(dev_priv->dev); |
893,7 → 892,7 |
num_units = 0; |
list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { |
if (crtc->fb != &framebuffer->base) |
if (crtc->primary->fb != &framebuffer->base) |
continue; |
units[num_units++] = vmw_crtc_to_du(crtc); |
} |
964,7 → 963,6 |
unsigned num_clips) |
{ |
struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); |
struct vmw_master *vmaster = vmw_master(file_priv->master); |
struct vmw_framebuffer_dmabuf *vfbd = |
vmw_framebuffer_to_vfbd(framebuffer); |
struct drm_clip_rect norect; |
972,7 → 970,7 |
drm_modeset_lock_all(dev_priv->dev); |
ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) { |
drm_modeset_unlock_all(dev_priv->dev); |
return ret; |
999,7 → 997,7 |
clips, num_clips, increment, NULL); |
} |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
drm_modeset_unlock_all(dev_priv->dev); |
1257,7 → 1255,7 |
num_units = 0; |
list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { |
if (crtc->fb != &vfb->base) |
if (crtc->primary->fb != &vfb->base) |
continue; |
units[num_units++] = vmw_crtc_to_du(crtc); |
} |
1394,7 → 1392,7 |
num_units = 0; |
list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { |
if (crtc->fb != &vfb->base) |
if (crtc->primary->fb != &vfb->base) |
continue; |
units[num_units++] = vmw_crtc_to_du(crtc); |
} |
1480,8 → 1478,6 |
struct drm_device *dev = dev_priv->dev; |
int ret; |
ENTER(); |
drm_mode_config_init(dev); |
dev->mode_config.funcs = &vmw_kms_funcs; |
dev->mode_config.min_width = 1; |
1491,11 → 1487,7 |
dev->mode_config.max_height = 8192; |
ret = vmw_kms_init_screen_object_display(dev_priv); |
// if (ret) /* Fallback */ |
// (void)vmw_kms_init_legacy_display_system(dev_priv); |
LEAVE(); |
return 0; |
} |
1520,7 → 1512,6 |
{ |
struct drm_vmw_cursor_bypass_arg *arg = data; |
struct vmw_display_unit *du; |
struct drm_mode_object *obj; |
struct drm_crtc *crtc; |
int ret = 0; |
1538,13 → 1529,12 |
return 0; |
} |
obj = drm_mode_object_find(dev, arg->crtc_id, DRM_MODE_OBJECT_CRTC); |
if (!obj) { |
crtc = drm_crtc_find(dev, arg->crtc_id); |
if (!crtc) { |
ret = -ENOENT; |
goto out; |
} |
crtc = obj_to_crtc(obj); |
du = vmw_crtc_to_du(crtc); |
du->hotspot_x = arg->xhot; |
1744,7 → 1734,7 |
uint32_t page_flip_flags) |
{ |
struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
struct drm_framebuffer *old_fb = crtc->fb; |
struct drm_framebuffer *old_fb = crtc->primary->fb; |
struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); |
struct drm_file *file_priv ; |
struct vmw_fence_obj *fence = NULL; |
1762,7 → 1752,7 |
if (!vmw_kms_screen_object_flippable(dev_priv, crtc)) |
return -EINVAL; |
crtc->fb = fb; |
crtc->primary->fb = fb; |
/* do a full screen dirty update */ |
clips.x1 = clips.y1 = 0; |
1802,7 → 1792,7 |
return ret; |
out_no_fence: |
crtc->fb = old_fb; |
crtc->primary->fb = old_fb; |
return ret; |
} |
#endif |
2026,7 → 2016,7 |
if (du->pref_mode) |
list_move(&du->pref_mode->head, &connector->probed_modes); |
drm_mode_connector_list_update(connector); |
drm_mode_connector_list_update(connector, true); |
return 1; |
} |
2045,7 → 2035,6 |
struct vmw_private *dev_priv = vmw_priv(dev); |
struct drm_vmw_update_layout_arg *arg = |
(struct drm_vmw_update_layout_arg *)data; |
struct vmw_master *vmaster = vmw_master(file_priv->master); |
void __user *user_rects; |
struct drm_vmw_rect *rects; |
unsigned rects_size; |
2053,7 → 2042,7 |
int i; |
struct drm_mode_config *mode_config = &dev->mode_config; |
ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) |
return ret; |
2095,7 → 2084,7 |
out_free: |
kfree(rects); |
out_unlock: |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
return ret; |
} |
#endif |
/drivers/video/drm/vmwgfx/vmwgfx_marker.c |
---|
27,19 → 27,18 |
#include "vmwgfx_drv.h" |
#include <linux/time.h> |
struct vmw_marker { |
struct list_head head; |
uint32_t seqno; |
struct timespec submitted; |
u64 submitted; |
}; |
void vmw_marker_queue_init(struct vmw_marker_queue *queue) |
{ |
INIT_LIST_HEAD(&queue->head); |
queue->lag = ns_to_timespec(0); |
// getrawmonotonic(&queue->lag_time); |
queue->lag = 0; |
queue->lag_time = ktime_get_raw_ns(); |
spin_lock_init(&queue->lock); |
} |
63,7 → 62,7 |
return -ENOMEM; |
marker->seqno = seqno; |
// getrawmonotonic(&marker->submitted); |
marker->submitted = ktime_get_raw_ns(); |
spin_lock(&queue->lock); |
list_add_tail(&marker->head, &queue->head); |
spin_unlock(&queue->lock); |
75,14 → 74,14 |
uint32_t signaled_seqno) |
{ |
struct vmw_marker *marker, *next; |
struct timespec now; |
bool updated = false; |
u64 now; |
spin_lock(&queue->lock); |
// getrawmonotonic(&now); |
now = ktime_get_raw_ns(); |
if (list_empty(&queue->head)) { |
// queue->lag = ns_to_timespec(0); |
queue->lag = 0; |
queue->lag_time = now; |
updated = true; |
goto out_unlock; |
92,7 → 91,7 |
if (signaled_seqno - marker->seqno > (1 << 30)) |
continue; |
// queue->lag = timespec_sub(now, marker->submitted); |
queue->lag = now - marker->submitted; |
queue->lag_time = now; |
updated = true; |
list_del(&marker->head); |
105,27 → 104,13 |
return (updated) ? 0 : -EBUSY; |
} |
static struct timespec vmw_timespec_add(struct timespec t1, |
struct timespec t2) |
static u64 vmw_fifo_lag(struct vmw_marker_queue *queue) |
{ |
t1.tv_sec += t2.tv_sec; |
t1.tv_nsec += t2.tv_nsec; |
if (t1.tv_nsec >= 1000000000L) { |
t1.tv_sec += 1; |
t1.tv_nsec -= 1000000000L; |
} |
u64 now; |
return t1; |
} |
static struct timespec vmw_fifo_lag(struct vmw_marker_queue *queue) |
{ |
struct timespec now; |
spin_lock(&queue->lock); |
// getrawmonotonic(&now); |
// queue->lag = vmw_timespec_add(queue->lag, |
// timespec_sub(now, queue->lag_time)); |
now = ktime_get_raw_ns(); |
queue->lag += now - queue->lag_time; |
queue->lag_time = now; |
spin_unlock(&queue->lock); |
return queue->lag; |
135,11 → 120,9 |
static bool vmw_lag_lt(struct vmw_marker_queue *queue, |
uint32_t us) |
{ |
struct timespec lag, cond; |
u64 cond = (u64) us * NSEC_PER_USEC; |
cond = ns_to_timespec((s64) us * 1000); |
lag = vmw_fifo_lag(queue); |
return (timespec_compare(&lag, &cond) < 1); |
return vmw_fifo_lag(queue) <= cond; |
} |
int vmw_wait_lag(struct vmw_private *dev_priv, |
/drivers/video/drm/vmwgfx/vmwgfx_mob.c |
---|
134,6 → 134,7 |
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
if (unlikely(cmd == NULL)) { |
DRM_ERROR("Failed reserving FIFO space for OTable setup.\n"); |
ret = -ENOMEM; |
goto out_no_fifo; |
} |
187,9 → 188,10 |
bo = otable->page_table->pt_bo; |
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
if (unlikely(cmd == NULL)) |
DRM_ERROR("Failed reserving FIFO space for OTable setup.\n"); |
if (unlikely(cmd == NULL)) { |
DRM_ERROR("Failed reserving FIFO space for OTable " |
"takedown.\n"); |
} else { |
memset(cmd, 0, sizeof(*cmd)); |
cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE; |
cmd->header.size = sizeof(cmd->body); |
199,6 → 201,7 |
cmd->body.validSizeInBytes = 0; |
cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID; |
vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
} |
if (bo) { |
int ret; |
562,11 → 565,12 |
if (unlikely(cmd == NULL)) { |
DRM_ERROR("Failed reserving FIFO space for Memory " |
"Object unbinding.\n"); |
} |
} else { |
cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB; |
cmd->header.size = sizeof(cmd->body); |
cmd->body.mobid = mob->id; |
vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
} |
if (bo) { |
vmw_fence_single_bo(bo, NULL); |
ttm_bo_unreserve(bo); |
/drivers/video/drm/vmwgfx/vmwgfx_resource.c |
---|
122,7 → 122,7 |
if (res->backup) { |
struct ttm_buffer_object *bo = &res->backup->base; |
ttm_bo_reserve(bo, false, false, false, 0); |
ttm_bo_reserve(bo, false, false, false, NULL); |
if (!list_empty(&res->mob_head) && |
res->func->unbind != NULL) { |
struct ttm_validate_buffer val_buf; |
136,8 → 136,12 |
vmw_dmabuf_unreference(&res->backup); |
} |
if (likely(res->hw_destroy != NULL)) |
if (likely(res->hw_destroy != NULL)) { |
res->hw_destroy(res); |
mutex_lock(&dev_priv->binding_mutex); |
vmw_context_binding_res_list_kill(&res->binding_head); |
mutex_unlock(&dev_priv->binding_mutex); |
} |
id = res->id; |
if (res->res_free != NULL) |
418,8 → 422,7 |
INIT_LIST_HEAD(&vmw_bo->res_list); |
ret = ttm_bo_init(bdev, &vmw_bo->base, size, |
(user) ? ttm_bo_type_device : |
ttm_bo_type_kernel, placement, |
ttm_bo_type_device, placement, |
0, interruptible, |
NULL, acc_size, NULL, bo_free); |
return ret; |
532,8 → 535,13 |
return -EPERM; |
vmw_user_bo = vmw_user_dma_buffer(bo); |
return (vmw_user_bo->prime.base.tfile == tfile || |
vmw_user_bo->prime.base.shareable) ? 0 : -EPERM; |
/* Check that the caller has opened the object. */ |
if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base))) |
return 0; |
DRM_ERROR("Could not grant buffer access.\n"); |
return -EPERM; |
} |
/** |
553,7 → 561,7 |
{ |
struct ttm_buffer_object *bo = &user_bo->dma.base; |
bool existed; |
int ret=0; |
int ret; |
if (flags & drm_vmw_synccpu_allow_cs) { |
struct ttm_bo_device *bdev = bo->bdev; |
671,10 → 679,9 |
struct drm_vmw_dmabuf_rep *rep = &arg->rep; |
struct vmw_dma_buffer *dma_buf; |
uint32_t handle; |
struct vmw_master *vmaster = vmw_master(file_priv->master); |
int ret; |
ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) |
return ret; |
691,7 → 698,7 |
vmw_dmabuf_unreference(&dma_buf); |
out_no_dmabuf: |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
return ret; |
} |
806,7 → 813,7 |
container_of(res, struct vmw_user_stream, stream.res); |
struct vmw_private *dev_priv = res->dev_priv; |
// ttm_base_object_kfree(stream, base); |
ttm_base_object_kfree(stream, base); |
ttm_mem_global_free(vmw_mem_glob(dev_priv), |
vmw_user_stream_size); |
} |
870,7 → 877,6 |
struct vmw_resource *tmp; |
struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data; |
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
struct vmw_master *vmaster = vmw_master(file_priv->master); |
int ret; |
/* |
881,7 → 887,7 |
if (unlikely(vmw_user_stream_size == 0)) |
vmw_user_stream_size = ttm_round_pot(sizeof(*stream)) + 128; |
ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) |
return ret; |
929,7 → 935,7 |
out_err: |
vmw_resource_unreference(&res); |
out_unlock: |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
return ret; |
} |
#endif |
979,7 → 985,7 |
args->pitch = args->width * ((args->bpp + 7) / 8); |
args->size = args->pitch * args->height; |
ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) |
return ret; |
991,7 → 997,7 |
vmw_dmabuf_unreference(&dma_buf); |
out_no_dmabuf: |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
return ret; |
} |
#endif |
/drivers/video/drm/vmwgfx/vmwgfx_scrn.c |
---|
100,7 → 100,7 |
/** |
* Send the fifo command to create a screen. |
*/ |
int vmw_sou_fifo_create(struct vmw_private *dev_priv, |
static int vmw_sou_fifo_create(struct vmw_private *dev_priv, |
struct vmw_screen_object_unit *sou, |
uint32_t x, uint32_t y, |
struct drm_display_mode *mode) |
114,10 → 114,8 |
SVGAScreenObject obj; |
} *cmd; |
// BUG_ON(!sou->buffer); |
BUG_ON(!sou->buffer); |
ENTER(); |
fifo_size = sizeof(*cmd); |
cmd = vmw_fifo_reserve(dev_priv, fifo_size); |
/* The hardware has hung, nothing we can do about it here. */ |
143,10 → 141,7 |
} |
/* Ok to assume that buffer is pinned in vram */ |
// vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); |
cmd->obj.backingStore.ptr.gmrId = SVGA_GMR_FRAMEBUFFER; |
cmd->obj.backingStore.ptr.offset = 0; |
vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); |
cmd->obj.backingStore.pitch = mode->hdisplay * 4; |
vmw_fifo_commit(dev_priv, fifo_size); |
153,8 → 148,6 |
sou->defined = true; |
LEAVE(); |
return 0; |
} |
314,7 → 307,7 |
connector->encoder = NULL; |
encoder->crtc = NULL; |
crtc->fb = NULL; |
crtc->primary->fb = NULL; |
crtc->x = 0; |
crtc->y = 0; |
crtc->enabled = false; |
375,7 → 368,7 |
connector->encoder = NULL; |
encoder->crtc = NULL; |
crtc->fb = NULL; |
crtc->primary->fb = NULL; |
crtc->x = 0; |
crtc->y = 0; |
crtc->enabled = false; |
388,7 → 381,7 |
connector->encoder = encoder; |
encoder->crtc = crtc; |
crtc->mode = *mode; |
crtc->fb = fb; |
crtc->primary->fb = fb; |
crtc->x = set->x; |
crtc->y = set->y; |
crtc->enabled = true; |
447,8 → 440,6 |
struct drm_encoder *encoder; |
struct drm_crtc *crtc; |
ENTER(); |
sou = kzalloc(sizeof(*sou), GFP_KERNEL); |
if (!sou) |
return -ENOMEM; |
476,6 → 467,8 |
encoder->possible_crtcs = (1 << unit); |
encoder->possible_clones = 0; |
(void) drm_connector_register(connector); |
drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs); |
drm_mode_crtc_set_gamma_size(crtc, 256); |
483,7 → 476,7 |
drm_object_attach_property(&connector->base, |
dev->mode_config.dirty_info_property, |
1); |
LEAVE(); |
return 0; |
} |
492,8 → 485,6 |
struct drm_device *dev = dev_priv->dev; |
int i, ret; |
ENTER(); |
if (dev_priv->sou_priv) { |
DRM_INFO("sou system already on\n"); |
return -EINVAL; |
523,7 → 514,6 |
DRM_INFO("Screen objects system initialized\n"); |
LEAVE(); |
return 0; |
err_vblank_cleanup: |
579,7 → 569,7 |
BUG_ON(!sou->base.is_implicit); |
dev_priv->sou_priv->implicit_fb = |
vmw_framebuffer_to_vfb(sou->base.crtc.fb); |
vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb); |
} |
#include "bitmap.h" |
639,8 → 629,6 |
bool ret = false; |
ENTER(); |
// dbgprintf("width %d height %d vrefresh %d\n", |
// reqmode->width, reqmode->height, reqmode->freq); |
718,6 → 706,7 |
vmw_write(dev_priv,SVGA_REG_WIDTH, mode->hdisplay); |
vmw_write(dev_priv,SVGA_REG_HEIGHT, mode->vdisplay); |
vmw_write(dev_priv,SVGA_REG_BITS_PER_PIXEL, 32); |
os_display->select_cursor(os_display->cursor); |
ret = 0; |
#endif |
if (ret == 0) |
737,6 → 726,5 |
os_display->width, os_display->height, crtc); |
} |
LEAVE(); |
return ret; |
}; |
/drivers/video/drm/vmwgfx/vmwgfx_shader.c |
---|
29,6 → 29,9 |
#include "vmwgfx_resource_priv.h" |
#include "ttm/ttm_placement.h" |
#define VMW_COMPAT_SHADER_HT_ORDER 12 |
#if 0 |
struct vmw_shader { |
struct vmw_resource res; |
SVGA3dShaderType type; |
40,6 → 43,50 |
struct vmw_shader shader; |
}; |
/** |
* enum vmw_compat_shader_state - Staging state for compat shaders |
*/ |
enum vmw_compat_shader_state { |
VMW_COMPAT_COMMITED, |
VMW_COMPAT_ADD, |
VMW_COMPAT_DEL |
}; |
/** |
* struct vmw_compat_shader - Metadata for compat shaders. |
* |
* @handle: The TTM handle of the guest backed shader. |
* @tfile: The struct ttm_object_file the guest backed shader is registered |
* with. |
* @hash: Hash item for lookup. |
* @head: List head for staging lists or the compat shader manager list. |
* @state: Staging state. |
* |
* The structure is protected by the cmdbuf lock. |
*/ |
struct vmw_compat_shader { |
u32 handle; |
struct ttm_object_file *tfile; |
struct drm_hash_item hash; |
struct list_head head; |
enum vmw_compat_shader_state state; |
}; |
/** |
* struct vmw_compat_shader_manager - Compat shader manager. |
* |
* @shaders: Hash table containing staged and commited compat shaders |
* @list: List of commited shaders. |
* @dev_priv: Pointer to a device private structure. |
* |
* @shaders and @list are protected by the cmdbuf mutex for now. |
*/ |
struct vmw_compat_shader_manager { |
struct drm_open_hash shaders; |
struct list_head list; |
struct vmw_private *dev_priv; |
}; |
static void vmw_user_shader_free(struct vmw_resource *res); |
static struct vmw_resource * |
vmw_user_shader_base_to_res(struct ttm_base_object *base); |
52,8 → 99,6 |
struct ttm_validate_buffer *val_buf); |
static int vmw_gb_shader_destroy(struct vmw_resource *res); |
static uint64_t vmw_user_shader_size; |
static const struct vmw_user_resource_conv user_shader_conv = { |
.object_type = VMW_RES_SHADER, |
.base_obj_to_res = vmw_user_shader_base_to_res, |
258,7 → 303,7 |
return 0; |
mutex_lock(&dev_priv->binding_mutex); |
vmw_context_binding_res_list_kill(&res->binding_head); |
vmw_context_binding_res_list_scrub(&res->binding_head); |
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
if (unlikely(cmd == NULL)) { |
296,9 → 341,9 |
container_of(res, struct vmw_user_shader, shader.res); |
struct vmw_private *dev_priv = res->dev_priv; |
// ttm_base_object_kfree(ushader, base); |
// ttm_mem_global_free(vmw_mem_glob(dev_priv), |
// vmw_user_shader_size); |
ttm_base_object_kfree(ushader, base); |
ttm_mem_global_free(vmw_mem_glob(dev_priv), |
vmw_user_shader_size); |
} |
/** |
325,18 → 370,84 |
TTM_REF_USAGE); |
} |
#if 0 |
static int vmw_user_shader_alloc(struct vmw_private *dev_priv, |
struct vmw_dma_buffer *buffer, |
size_t shader_size, |
size_t offset, |
SVGA3dShaderType shader_type, |
struct ttm_object_file *tfile, |
u32 *handle) |
{ |
struct vmw_user_shader *ushader; |
struct vmw_resource *res, *tmp; |
int ret; |
/* |
* Approximate idr memory usage with 128 bytes. It will be limited |
* by maximum number_of shaders anyway. |
*/ |
if (unlikely(vmw_user_shader_size == 0)) |
vmw_user_shader_size = |
ttm_round_pot(sizeof(struct vmw_user_shader)) + 128; |
ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), |
vmw_user_shader_size, |
false, true); |
if (unlikely(ret != 0)) { |
if (ret != -ERESTARTSYS) |
DRM_ERROR("Out of graphics memory for shader " |
"creation.\n"); |
goto out; |
} |
ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); |
if (unlikely(ushader == NULL)) { |
ttm_mem_global_free(vmw_mem_glob(dev_priv), |
vmw_user_shader_size); |
ret = -ENOMEM; |
goto out; |
} |
res = &ushader->shader.res; |
ushader->base.shareable = false; |
ushader->base.tfile = NULL; |
/* |
* From here on, the destructor takes over resource freeing. |
*/ |
ret = vmw_gb_shader_init(dev_priv, res, shader_size, |
offset, shader_type, buffer, |
vmw_user_shader_free); |
if (unlikely(ret != 0)) |
goto out; |
tmp = vmw_resource_reference(res); |
ret = ttm_base_object_init(tfile, &ushader->base, false, |
VMW_RES_SHADER, |
&vmw_user_shader_base_release, NULL); |
if (unlikely(ret != 0)) { |
vmw_resource_unreference(&tmp); |
goto out_err; |
} |
if (handle) |
*handle = ushader->base.hash.key; |
out_err: |
vmw_resource_unreference(&res); |
out: |
return ret; |
} |
int vmw_shader_define_ioctl(struct drm_device *dev, void *data, |
struct drm_file *file_priv) |
{ |
struct vmw_private *dev_priv = vmw_priv(dev); |
struct vmw_user_shader *ushader; |
struct vmw_resource *res; |
struct vmw_resource *tmp; |
struct drm_vmw_shader_create_arg *arg = |
(struct drm_vmw_shader_create_arg *)data; |
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
struct vmw_master *vmaster = vmw_master(file_priv->master); |
struct vmw_dma_buffer *buffer = NULL; |
SVGA3dShaderType shader_type; |
int ret; |
374,70 → 485,164 |
goto out_bad_arg; |
} |
/* |
* Approximate idr memory usage with 128 bytes. It will be limited |
* by maximum number_of shaders anyway. |
*/ |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) |
goto out_bad_arg; |
if (unlikely(vmw_user_shader_size == 0)) |
vmw_user_shader_size = ttm_round_pot(sizeof(*ushader)) |
+ 128; |
ret = vmw_user_shader_alloc(dev_priv, buffer, arg->size, arg->offset, |
shader_type, tfile, &arg->shader_handle); |
ret = ttm_read_lock(&vmaster->lock, true); |
if (unlikely(ret != 0)) |
ttm_read_unlock(&dev_priv->reservation_sem); |
out_bad_arg: |
vmw_dmabuf_unreference(&buffer); |
return ret; |
} |
ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), |
vmw_user_shader_size, |
false, true); |
if (unlikely(ret != 0)) { |
if (ret != -ERESTARTSYS) |
DRM_ERROR("Out of graphics memory for shader" |
" creation.\n"); |
goto out_unlock; |
/** |
* vmw_compat_shader_id_ok - Check whether a compat shader user key and |
* shader type are within valid bounds. |
* |
* @user_key: User space id of the shader. |
* @shader_type: Shader type. |
* |
* Returns true if valid false if not. |
*/ |
static bool vmw_compat_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type) |
{ |
return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16; |
} |
ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); |
if (unlikely(ushader == NULL)) { |
ttm_mem_global_free(vmw_mem_glob(dev_priv), |
vmw_user_shader_size); |
ret = -ENOMEM; |
goto out_unlock; |
/** |
* vmw_compat_shader_key - Compute a hash key suitable for a compat shader. |
* |
* @user_key: User space id of the shader. |
* @shader_type: Shader type. |
* |
* Returns a hash key suitable for a command buffer managed resource |
* manager hash table. |
*/ |
static u32 vmw_compat_shader_key(u32 user_key, SVGA3dShaderType shader_type) |
{ |
return user_key | (shader_type << 20); |
} |
res = &ushader->shader.res; |
ushader->base.shareable = false; |
ushader->base.tfile = NULL; |
/** |
* vmw_compat_shader_remove - Stage a compat shader for removal. |
* |
* @man: Pointer to the compat shader manager identifying the shader namespace. |
* @user_key: The key that is used to identify the shader. The key is |
* unique to the shader type. |
* @shader_type: Shader type. |
* @list: Caller's list of staged command buffer resource actions. |
*/ |
int vmw_compat_shader_remove(struct vmw_cmdbuf_res_manager *man, |
u32 user_key, SVGA3dShaderType shader_type, |
struct list_head *list) |
{ |
if (!vmw_compat_shader_id_ok(user_key, shader_type)) |
return -EINVAL; |
/* |
* From here on, the destructor takes over resource freeing. |
return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_compat_shader, |
vmw_compat_shader_key(user_key, |
shader_type), |
list); |
} |
/** |
* vmw_compat_shader_add - Create a compat shader and stage it for addition |
* as a command buffer managed resource. |
* |
* @man: Pointer to the compat shader manager identifying the shader namespace. |
* @user_key: The key that is used to identify the shader. The key is |
* unique to the shader type. |
* @bytecode: Pointer to the bytecode of the shader. |
* @shader_type: Shader type. |
* @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is |
* to be created with. |
* @list: Caller's list of staged command buffer resource actions. |
* |
*/ |
int vmw_compat_shader_add(struct vmw_private *dev_priv, |
struct vmw_cmdbuf_res_manager *man, |
u32 user_key, const void *bytecode, |
SVGA3dShaderType shader_type, |
size_t size, |
struct list_head *list) |
{ |
struct vmw_dma_buffer *buf; |
struct ttm_bo_kmap_obj map; |
bool is_iomem; |
int ret; |
struct vmw_resource *res; |
ret = vmw_gb_shader_init(dev_priv, res, arg->size, |
arg->offset, shader_type, buffer, |
vmw_user_shader_free); |
if (!vmw_compat_shader_id_ok(user_key, shader_type)) |
return -EINVAL; |
/* Allocate and pin a DMA buffer */ |
buf = kzalloc(sizeof(*buf), GFP_KERNEL); |
if (unlikely(buf == NULL)) |
return -ENOMEM; |
ret = vmw_dmabuf_init(dev_priv, buf, size, &vmw_sys_ne_placement, |
true, vmw_dmabuf_bo_free); |
if (unlikely(ret != 0)) |
goto out_unlock; |
goto out; |
tmp = vmw_resource_reference(res); |
ret = ttm_base_object_init(tfile, &ushader->base, false, |
VMW_RES_SHADER, |
&vmw_user_shader_base_release, NULL); |
ret = ttm_bo_reserve(&buf->base, false, true, false, NULL); |
if (unlikely(ret != 0)) |
goto no_reserve; |
/* Map and copy shader bytecode. */ |
ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT, |
&map); |
if (unlikely(ret != 0)) { |
vmw_resource_unreference(&tmp); |
goto out_err; |
ttm_bo_unreserve(&buf->base); |
goto no_reserve; |
} |
arg->shader_handle = ushader->base.hash.key; |
out_err: |
memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size); |
WARN_ON(is_iomem); |
ttm_bo_kunmap(&map); |
ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, false, true); |
WARN_ON(ret != 0); |
ttm_bo_unreserve(&buf->base); |
res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type); |
if (unlikely(ret != 0)) |
goto no_reserve; |
ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_compat_shader, |
vmw_compat_shader_key(user_key, shader_type), |
res, list); |
vmw_resource_unreference(&res); |
out_unlock: |
ttm_read_unlock(&vmaster->lock); |
out_bad_arg: |
vmw_dmabuf_unreference(&buffer); |
no_reserve: |
vmw_dmabuf_unreference(&buf); |
out: |
return ret; |
} |
/** |
* vmw_compat_shader_lookup - Look up a compat shader |
* |
* @man: Pointer to the command buffer managed resource manager identifying |
* the shader namespace. |
* @user_key: The user space id of the shader. |
* @shader_type: The shader type. |
* |
* Returns a refcounted pointer to a struct vmw_resource if the shader was |
* found. An error pointer otherwise. |
*/ |
struct vmw_resource * |
vmw_compat_shader_lookup(struct vmw_cmdbuf_res_manager *man, |
u32 user_key, |
SVGA3dShaderType shader_type) |
{ |
if (!vmw_compat_shader_id_ok(user_key, shader_type)) |
return ERR_PTR(-EINVAL); |
return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_compat_shader, |
vmw_compat_shader_key(user_key, |
shader_type)); |
} |
#endif |
/drivers/video/drm/vmwgfx/vmwgfx_surface.c |
---|
36,6 → 36,7 |
* @base: The TTM base object handling user-space visibility. |
* @srf: The surface metadata. |
* @size: TTM accounting size for the surface. |
* @master: master of the creating client. Used for security check. |
*/ |
struct vmw_user_surface { |
struct ttm_prime_object prime; |
681,7 → 682,6 |
struct vmw_surface_offset *cur_offset; |
uint32_t num_sizes; |
uint32_t size; |
struct vmw_master *vmaster = vmw_master(file_priv->master); |
const struct svga3d_surface_desc *desc; |
if (unlikely(vmw_user_surface_size == 0)) |
707,7 → 707,7 |
return -EINVAL; |
} |
ret = ttm_read_lock(&vmaster->lock, true); |
ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
if (unlikely(ret != 0)) |
return ret; |
828,7 → 828,7 |
rep->sid = user_srf->prime.base.hash.key; |
vmw_resource_unreference(&res); |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
return 0; |
out_no_copy: |
kfree(srf->offsets); |
839,7 → 839,8 |
out_no_user_srf: |
ttm_mem_global_free(vmw_mem_glob(dev_priv), size); |
out_unlock: |
ttm_read_unlock(&vmaster->lock); |
ttm_read_unlock(&dev_priv->reservation_sem); |
return ret; |
} |
864,27 → 865,16 |
struct vmw_user_surface *user_srf; |
struct drm_vmw_size __user *user_sizes; |
struct ttm_base_object *base; |
int ret = -EINVAL; |
int ret; |
base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); |
if (unlikely(base == NULL)) { |
DRM_ERROR("Could not find surface to reference.\n"); |
return -EINVAL; |
} |
ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, |
req->handle_type, &base); |
if (unlikely(ret != 0)) |
return ret; |
if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) |
goto out_bad_resource; |
user_srf = container_of(base, struct vmw_user_surface, prime.base); |
srf = &user_srf->srf; |
ret = ttm_ref_object_add(tfile, &user_srf->prime.base, |
TTM_REF_USAGE, NULL); |
if (unlikely(ret != 0)) { |
DRM_ERROR("Could not add a reference to a surface.\n"); |
goto out_no_reference; |
} |
rep->flags = srf->flags; |
rep->format = srf->format; |
memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels)); |
892,11 → 882,12 |
rep->size_addr; |
if (user_sizes) |
ret = copy_to_user(user_sizes, srf->sizes, |
srf->num_sizes * sizeof(*srf->sizes)); |
ret = copy_to_user(user_sizes, &srf->base_size, |
sizeof(srf->base_size)); |
if (unlikely(ret != 0)) { |
DRM_ERROR("copy_to_user failed %p %u\n", |
user_sizes, srf->num_sizes); |
ttm_ref_object_base_unref(tfile, base->hash.key, TTM_REF_USAGE); |
ret = -EFAULT; |
} |
out_bad_resource: |
/drivers/video/drm/vmwgfx/vmwgfx_ttm_glue.c |
---|
53,7 → 53,6 |
static void vmw_ttm_mem_global_release(struct drm_global_reference *ref) |
{ |
// ttm_mem_global_release(ref->object); |
} |
int vmw_ttm_global_init(struct vmw_private *dev_priv) |