Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 5077 → Rev 5078

/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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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 = &reg_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, &gtt_addr);
if (r) {
DRM_ERROR("Failed to pin GTT object %d\n", i);
goto out_lclean_unres;
}
 
r = radeon_bo_kmap(gtt_obj[i], &gtt_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], &gtt_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(&gtt_obj[i]);
out_lclean:
for (--i; i >= 0; --i) {
radeon_bo_unpin(gtt_obj[i]);
radeon_bo_unreserve(gtt_obj[i]);
radeon_bo_unref(&gtt_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(&gtt->ttm);
// ttm_dma_tt_fini(&gtt->ttm);
kfree(gtt);
}
 
327,24 → 580,98
return &gtt->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(&gtt->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(&gtt->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, &dividers);
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, &current_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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers) == 0) {
vco_freq = rv6xx_calculate_vco_frequency(ref_clk, &dividers,
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, &dividers))
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,
&dividers,
&vco_freq);
 
rv6xx_find_memory_clock_with_highest_vco(rdev,
pi->hw.mclks[pi->hw.medium_mclk_index],
ref_clk,
&dividers,
&vco_freq);
 
rv6xx_find_memory_clock_with_highest_vco(rdev,
pi->hw.mclks[pi->hw.low_mclk_index],
ref_clk,
&dividers,
&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, &current_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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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,
&dividers, &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,
&dividers, &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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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, &dividers);
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)